> For the complete documentation index, see [llms.txt](https://developer.esw.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.esw.com/customs-catalog-api/resources/tutorials/managing-duty-rules.md).

# Managing Duty Rules

Duty rules let you control how duty rates are calculated for a destination country, HS code, country of origin, and brand.

{% hint style="info" icon="rocket-launch" %}

### Prerequisites

* A valid Bearer JWT token — see Authentication
* Your `brandCode` or `tenantCode`
* Classifications set up
  {% endhint %}

<p align="center">There are two kinds of rules the API manages</p>

{% columns %}
{% column %}
{% hint style="info" icon="calculator-simple" %}
**Rate type rules**

Defines which duty rate type applies for a given brand, country, and country of origin.
{% endhint %}
{% endcolumn %}

{% column %}
{% hint style="info" icon="calculator" %}
**Additional duty rules**

Defines extra duties applied on top of the base rate for a given destination country and HS code.
{% endhint %}
{% endcolumn %}
{% endcolumns %}

***

{% stepper %}
{% step %}

### Understand the Duty Rule Data Model

Every duty rule (`DutyRuleDto`) is a single document with three top-level fields:

| Field            | Type   | Description                                                            |
| ---------------- | ------ | ---------------------------------------------------------------------- |
| `id`             | string | Internal rule ID — present on existing rules, omit when creating       |
| `ruleType`       | string | A label identifying the kind of rule — see Rule Types below            |
| `rateType`       | object | Defines the duty rate type for a brand/country combination — see below |
| `additionalDuty` | object | Defines an extra duty applied by HS code and origin — see below        |

A rule contains either a `rateType`, an `additionalDuty`, or both, depending on what it governs.

***

#### Rule Types

`ruleType` is a free-form string that labels what the rule does. Common values you are likely to encounter or set include:

| Value          | Meaning                                            |
| -------------- | -------------------------------------------------- |
| `MFN`          | Most Favoured Nation — the standard WTO duty rate  |
| `General`      | General duty rate for non-preferential trade       |
| `Preferential` | Reduced rate under a trade agreement               |
| `Additional`   | An additional duty layered on top of the base rate |
| `FTA`          | Free Trade Agreement rate — zero or reduced duty   |

These are not enforced by the API as an enum — you can use any string that is meaningful to your team — but consistency in naming will make filtering and auditing much easier.

***

#### The `rateType` Object

`rateType` determines which rate applies for products shipped from a specific origin to a specific country, for a specific brand.

| Field             | Type             | Description                                                      |
| ----------------- | ---------------- | ---------------------------------------------------------------- |
| `country`         | string           | Destination country ISO-2 code, e.g. `"US"`, `"GB"`              |
| `tenantCode`      | string           | Brand/tenant code this rate applies to                           |
| `rate`            | string           | The rate type label, e.g. `"MFN"`, `"General"`, `"Preferential"` |
| `countryOfOrigin` | array of strings | ISO-2 codes of the manufacturing countries this rate applies to  |

> **Note:** In the write (POST) body, the field is `tenantCode`. In the read (GET) response, the equivalent field is `brandCode`. Both refer to the same brand identifier.

***

#### The `additionalDuty` Object

`additionalDuty` defines an extra layer of duty applied on top of a base rate, scoped by destination country and HS code.

| Field             | Type             | Description                                                   |
| ----------------- | ---------------- | ------------------------------------------------------------- |
| `country`         | string           | Destination country ISO-2 code the additional duty applies to |
| `hsCode`          | string           | The HS code this additional duty targets                      |
| `countryOfOrigin` | array of strings | ISO-2 codes of origins subject to this additional duty        |

***

{% endstep %}

{% step %}

### List and Filter Existing Rules

Retrieve duty rules with optional filters. All parameters are optional — omitting them returns all rules.

```http
GET /api/v2/DutyRule
Authorization: Bearer <token>
```

**Query parameters:**

| Parameter    | Type   | Description                                             |
| ------------ | ------ | ------------------------------------------------------- |
| `RuleType`   | string | Filter by rule type label, e.g. `"MFN"`, `"Additional"` |
| `Country`    | string | Filter by destination country ISO-2 code                |
| `TenantCode` | string | Filter to rules for a specific brand/tenant             |
| `HsCode`     | string | Filter to rules for a specific HS code                  |

**Example — all rules for a brand:**

```http
GET /api/v2/DutyRule?TenantCode=my-tenant-001
Authorization: Bearer <token>
```

**Example — additional duty rules for a specific destination country:**

```http
GET /api/v2/DutyRule?RuleType=Additional&Country=US
Authorization: Bearer <token>
```

**Example — all rules for a specific HS code:**

```http
GET /api/v2/DutyRule?HsCode=4202.32
Authorization: Bearer <token>
```

**Example response:**

{% code expandable="true" %}

```json
[
  {
    "id": "rule-001",
    "ruleType": "MFN",
    "rateType": {
      "brandCode": "MBR",
      "country": "US",
      "rate": "MFN",
      "countryOfOrigin": ["CN", "VN", "BD"]
    },
    "additionalDuty": null
  },
  {
    "id": "rule-002",
    "ruleType": "Additional",
    "rateType": null,
    "additionalDuty": {
      "country": "US",
      "hsCode": "4202.32",
      "countryOfOrigin": ["CN"]
    }
  },
  {
    "id": "rule-003",
    "ruleType": "Preferential",
    "rateType": {
      "brandCode": "MBR",
      "country": "GB",
      "rate": "Preferential",
      "countryOfOrigin": ["IT", "FR", "DE"]
    },
    "additionalDuty": null
  }
]
```

{% endcode %}

**Response:** `200 OK` — array of `DutyRuleSearchResponse` objects · `404 Not Found` — no rules match the filters · `500 Internal Server Error`

***

{% endstep %}

{% step %}

### Create and Upsert Rules

Use `POST /api/v2/DutyRule` to create new rules or update existing ones. The endpoint accepts an array, so you can create or update multiple rules in a single call.

* To **create** a new rule — omit the `id` field
* To **update** an existing rule — include the `id` from the GET response

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[ ...array of DutyRuleDto objects... ]
```

**Responses:** `200 OK` · `400 Bad Request` · `500 Internal Server Error`

***

#### Example A — Create a Rate Type Rule

Apply the MFN rate for a brand's products shipped from China, Vietnam, and Bangladesh into the United States:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "MFN",
    "rateType": {
      "country": "US",
      "tenantCode": "my-tenant-001",
      "rate": "MFN",
      "countryOfOrigin": ["CN", "VN", "BD"]
    }
  }
]
```

{% endcode %}

***

#### Example B — Create an Additional Duty Rule

Apply a US Section 301 additional duty on wallets (HS code `4202.32`) manufactured in China:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "Additional",
    "additionalDuty": {
      "country": "US",
      "hsCode": "4202.32",
      "countryOfOrigin": ["CN"]
    }
  }
]
```

{% endcode %}

***

#### Example C — Create a Preferential (FTA) Rate Rule

Apply a preferential rate for EU-origin goods shipped to the UK under a trade agreement:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "Preferential",
    "rateType": {
      "country": "GB",
      "tenantCode": "my-tenant-001",
      "rate": "Preferential",
      "countryOfOrigin": ["IT", "FR", "DE", "ES", "PT"]
    }
  }
]
```

{% endcode %}

***

#### Example D — Update an Existing Rule

Add Bangladesh to an existing MFN rule by including the `id` and providing the updated `countryOfOrigin` array:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "id": "rule-001",
    "ruleType": "MFN",
    "rateType": {
      "country": "US",
      "tenantCode": "my-tenant-001",
      "rate": "MFN",
      "countryOfOrigin": ["CN", "VN", "BD", "PK"]
    }
  }
]
```

{% endcode %}

***

#### Example E — Create Multiple Rules in One Call

Submit several rules together to minimise round trips:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "MFN",
    "rateType": {
      "country": "AU",
      "tenantCode": "my-tenant-001",
      "rate": "MFN",
      "countryOfOrigin": ["CN", "VN"]
    }
  },
  {
    "ruleType": "Additional",
    "additionalDuty": {
      "country": "AU",
      "hsCode": "6403.99",
      "countryOfOrigin": ["CN"]
    }
  },
  {
    "ruleType": "FTA",
    "rateType": {
      "country": "AU",
      "tenantCode": "my-tenant-001",
      "rate": "FTA",
      "countryOfOrigin": ["NZ"]
    }
  }
]
```

{% endcode %}

***

{% endstep %}

{% step %}

### Update an Additional Duty Rule Status

The `PUT /api/v2/DutyRule/AdditionalDutyRuleStatus` endpoint toggles the active/inactive status of an additional duty rule, scoped by destination country and HS code. Use this to quickly enable or disable an additional duty without deleting and recreating the rule.

```http
PUT /api/v2/DutyRule/AdditionalDutyRuleStatus?DeliveryCountry={country}&HsCode={hsCode}
Authorization: Bearer <token>
```

**Query parameters:**

| Parameter         | Type   | Required | Description                                       |
| ----------------- | ------ | -------- | ------------------------------------------------- |
| `DeliveryCountry` | string | ❌        | Destination country ISO-2 code                    |
| `HsCode`          | string | ❌        | The HS code of the additional duty rule to toggle |

**Example — disable the additional duty on CN-origin wallets into the US:**

```http
PUT /api/v2/DutyRule/AdditionalDutyRuleStatus?DeliveryCountry=US&HsCode=4202.32
Authorization: Bearer <token>
```

**Responses:** `200 OK` · `400 Bad Request` · `500 Internal Server Error`

> **Tip:** This is the recommended approach when a tariff changes temporarily or a trade measure is suspended — it preserves the rule configuration so you can re-enable it later without rebuilding it from scratch.

***

{% endstep %}

{% step %}

### Delete Rules

#### Delete a Single Rule by ID

```http
DELETE /api/v2/DutyRule/{id}
Authorization: Bearer <token>
```

**Example:**

```http
DELETE /api/v2/DutyRule/rule-002
Authorization: Bearer <token>
```

**Responses:** `200 OK` · `400 Bad Request` · `500 Internal Server Error`

The `id` is obtained from the `id` field in a `GET /api/v2/DutyRule` response.

***

#### Delete All Rules for a Brand

> **This is irreversible.** All duty rules for the tenant will be permanently removed. You will need to recreate them if deleted in error.

```http
DELETE /api/v2/DutyRule/deleteAll/{tenantCode}
Authorization: Bearer <token>
```

**Example:**

```http
DELETE /api/v2/DutyRule/deleteAll/my-tenant-001
Authorization: Bearer <token>
```

**Responses:** `200 OK` · `400 Bad Request` · `500 Internal Server Error`

Use this during a full reconfiguration — for example, when a brand's trade lanes change completely and the entire rule set needs to be rebuilt. The recommended sequence is:

```angular-ts
1. GET /api/v2/DutyRule?TenantCode=my-tenant-001  ← save a backup of current rules
2. DELETE /api/v2/DutyRule/deleteAll/my-tenant-001
3. POST /api/v2/DutyRule  ← submit the new rule set
4. GET /api/v2/DutyRule?TenantCode=my-tenant-001  ← verify the new rules are in place
```

***

{% endstep %}

{% step %}

### Practical Configuration Scenarios

#### Scenario 1 — Standard Setup for a New Brand

When onboarding a new brand, create a baseline set of rate type rules covering the brand's primary shipping lanes:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "MFN",
    "rateType": {
      "country": "US",
      "tenantCode": "new-brand-001",
      "rate": "MFN",
      "countryOfOrigin": ["IT", "FR", "DE"]
    }
  },
  {
    "ruleType": "MFN",
    "rateType": {
      "country": "AU",
      "tenantCode": "new-brand-001",
      "rate": "MFN",
      "countryOfOrigin": ["IT", "FR", "DE"]
    }
  },
  {
    "ruleType": "MFN",
    "rateType": {
      "country": "CA",
      "tenantCode": "new-brand-001",
      "rate": "MFN",
      "countryOfOrigin": ["IT", "FR", "DE"]
    }
  }
]
```

{% endcode %}

***

#### Scenario 2 — Applying Section 301 Tariffs (US Additional Duties on CN-Origin Goods)

Create additional duty rules for the HS codes affected by Section 301

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "Additional",
    "additionalDuty": {
      "country": "US",
      "hsCode": "4202.32",
      "countryOfOrigin": ["CN"]
    }
  },
  {
    "ruleType": "Additional",
    "additionalDuty": {
      "country": "US",
      "hsCode": "6403.99",
      "countryOfOrigin": ["CN"]
    }
  },
  {
    "ruleType": "Additional",
    "additionalDuty": {
      "country": "US",
      "hsCode": "6104.43",
      "countryOfOrigin": ["CN"]
    }
  }
]
```

{% endcode %}

If the tariff is subsequently suspended or modified, toggle the status without deleting:

```http
PUT /api/v2/DutyRule/AdditionalDutyRuleStatus?DeliveryCountry=US&HsCode=4202.32
Authorization: Bearer <token>
```

***

#### Scenario 3 — Free Trade Agreement Rate

Apply a zero-rate FTA duty for goods originating in EU countries shipped into the UK:

{% code expandable="true" %}

```http
POST /api/v2/DutyRule
Authorization: Bearer <token>
Content-Type: application/json

[
  {
    "ruleType": "FTA",
    "rateType": {
      "country": "GB",
      "tenantCode": "my-tenant-001",
      "rate": "FTA",
      "countryOfOrigin": ["DE", "FR", "IT", "ES", "NL", "BE", "AT", "PT"]
    }
  }
]
```

{% endcode %}

***

#### Scenario 4 — Auditing Rules Before a Tariff Change

Before a known tariff update takes effect, pull a full snapshot of the current state:

```http
GET /api/v2/DutyRule?TenantCode=my-tenant-001
Authorization: Bearer <token>
```

Save the response as a JSON backup. After the change is applied, compare the new GET response against it to confirm only the intended rules changed.
{% endstep %}
{% endstepper %}

***

### End-to-End Flow Summary

{% code expandable="true" %}

```ruby
New brand or tariff change?
        │
        ▼
GET /api/v2/DutyRule?TenantCode=...
  → Review existing rules
  → Save a backup if making bulk changes
        │
        ├── No rules yet / new brand
        │     └──→ POST /api/v2/DutyRule  (create baseline rate type rules)
        │
        ├── Need to add or update specific rules
        │     └──→ POST /api/v2/DutyRule  (upsert — include id to update, omit to create)
        │
        ├── Additional duty temporarily suspended
        │     └──→ PUT /api/v2/DutyRule/AdditionalDutyRuleStatus?DeliveryCountry=...&HsCode=...
        │
        ├── Single rule no longer needed
        │     └──→ DELETE /api/v2/DutyRule/{id}
        │
        └── Full rule rebuild for brand
              └──→ DELETE /api/v2/DutyRule/deleteAll/{tenantCode}
                    └──→ POST /api/v2/DutyRule  (submit new rule set)
                          └──→ GET /api/v2/DutyRule?TenantCode=...  (verify)
```

{% endcode %}

***

### Common Issues

| Symptom                                              | Likely Cause                                                | Action                                                                                                                 |
| ---------------------------------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `GET /DutyRule` returns `404`                        | No rules exist for the given filter combination             | Check `TenantCode`, `Country`, and `HsCode` values; omit filters to see all rules                                      |
| `POST /DutyRule` returns `400`                       | Malformed request body                                      | Ensure the body is a JSON array, even for a single rule; check that `country` uses ISO-2 codes                         |
| Upsert creates a duplicate instead of updating       | `id` not included in the request body                       | Fetch the existing rule's `id` from `GET /DutyRule` and include it in the POST body                                    |
| `DELETE /deleteAll` returns `400`                    | Invalid or missing `tenantCode`                             | Confirm the tenant code exactly matches what was used at onboarding                                                    |
| `PUT AdditionalDutyRuleStatus` has no visible effect | No rule exists matching both `DeliveryCountry` and `HsCode` | Query `GET /DutyRule?Country=...&HsCode=...` to confirm the rule exists before toggling                                |
| Rate type rule not being applied                     | `countryOfOrigin` missing the relevant origin code          | Fetch the rule with `GET /DutyRule` and confirm the origin country is in the `countryOfOrigin` array; upsert to update |


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.esw.com/customs-catalog-api/resources/tutorials/managing-duty-rules.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
