How to Calculate Taxes and Duties
Estimate the import tax and duty (T&D) your buyer will pay on an international order, so you can show the full landed cost at checkout or charge it upfront (DDP).
public.tax_and_duty:read (advanced)Tax vs duty in 30 seconds
VAT, GST or sales tax charged by the destination country, usually on the goods, shipping and duty combined.
A tariff on the goods, set by the item's HS (Harmonized System) code and country of origin.
DDU (Delivered Duty Unpaid): the buyer pays on delivery. DDP (Delivered Duty Paid): you charge the buyer at checkout and pay it on their behalf.
Two ways to get T&D
Standalone POST /taxes_and_duties | Inside Rates POST /rates | |
|---|---|---|
| Use when | You already know the shipping cost, or don't need courier prices | You're also comparing couriers |
| You send | Countries, shipping charge, insurance fee, items with HS codes | Addresses and parcels (as for any rate request) |
| You get | tax, duty, optional per-item breakdown | estimated_import_tax and estimated_import_duty on every rate |
Standalone calculation
- Collect the inputs
Field Required Notes origin_country_alpha2✔ Where the parcel ships from (or origin_country_id)destination_country_alpha2✔ Where it's going (or destination_country_id)shipment_charge✔ Shipping cost. You can get it from Rates insurance_fee✔ 0if not insureditems[].hs_code✔ 8-digit HS code items[].duty_origin_country_alpha2✔ Where the item was made items[].customs_value✔ Total value of the items with this HS code currencyOptional Defaults to the origin country's currency - Send the requestcURLcurl -X POST https://public-api.easyship.com/2024-09/taxes_and_duties \ -H "Authorization: Bearer $EASYSHIP_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "origin_country_alpha2": "US", "destination_country_alpha2": "CA", "currency": "USD", "insurance_fee": 0, "shipment_charge": 120.10, "items": [ { "duty_origin_country_alpha2": "US", "hs_code": "17029010", "customs_value": 100 }, { "duty_origin_country_alpha2": "CN", "hs_code": "42029100", "customs_value": 20.10 } ] }'
- Read the resultResponse{ "tax_and_duty": { "currency": "USD", "tax": 20.21, "duty": 100.21, "import_duty_details": null }, "meta": { "request_id": "01563646-58c1-4607-8fe0-cae3e92c4477" } }
Landed cost for the buyer = goods + shipping +
tax+duty. Whenimport_duty_detailsis present, it explains each line: the HS code actually applied, the rate type, the calculation method (e.g. CIF) and any extra duties.
customs_value.T&D inside a rate request
Send incoterms with your rate request. Each rate then includes the tax and duty estimate.
Only need courier prices? Send "calculate_tax_and_duties": false. The T&D fields come back as null and the call isn't billed as T&D.
incoterms: "DDP" with calculate_tax_and_duties: false returns a 400 error.Usage and billing
| Request | Billed as T&D? |
|---|---|
POST /taxes_and_duties, international | ✔ Yes |
POST /taxes_and_duties, domestic (same country) | ✘ No |
POST /rates, international, T&D on (default) | ✔ Yes, in addition to Rates |
POST /rates with calculate_tax_and_duties: false | ✘ No (Rates only) |
POST /rates, domestic | ✘ No |
| Any sandbox request | ✘ No |
Only successful (2xx) responses count. You can see your usage under Account → Subscription in the dashboard.
429 error; check the X-RateLimit-* headers.Errors and limitations
| Status | Why | Fix |
|---|---|---|
| 402 | insufficient_subscription: your plan doesn't include T&D | Upgrade your plan |
| 403 | Your token is missing the advanced scope | Enable public.tax_and_duty:read on your API connection |
| 422 | invalid_content, e.g. items[2]: hs_code is not an eight-digit number | Fix the field named in details |
| 422 | No tax or duty data for that route or HS code | Check the HS code and the countries |
| 429 | Rate limit reached | Retry after X-RateLimit-Reset |
Updated about 18 hours ago
