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).

What it does
Returns import tax and duty for a shipment
You need
Countries, shipping cost, and each item's HS code and value
Scope
public.tax_and_duty:read (advanced)
Plan
Paid plans only

Tax vs duty in 30 seconds

🧾
Import tax

VAT, GST or sales tax charged by the destination country, usually on the goods, shipping and duty combined.

🏛️
Import duty

A tariff on the goods, set by the item's HS (Harmonized System) code and country of origin.

📦
DDU vs DDP

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_dutiesInside Rates POST /rates
Use whenYou already know the shipping cost, or don't need courier pricesYou're also comparing couriers
You sendCountries, shipping charge, insurance fee, items with HS codesAddresses and parcels (as for any rate request)
You gettax, duty, optional per-item breakdownestimated_import_tax and estimated_import_duty on every rate

Standalone calculation

  1. Collect the inputs
    FieldRequiredNotes
    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✔0 if not insured
    items[].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
    currencyOptionalDefaults to the origin country's currency
  2. Send the request
    cURLPOST /2024-09/taxes_and_duties
    curl -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 } ] }'
  3. Read the result
    Response200 OK
    { "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. When import_duty_details is present, it explains each line: the HS code actually applied, the rate type, the calculation method (e.g. CIF) and any extra duties.

One entry per HS code. If you sell three T-shirts with the same HS code and origin, send one item with their combined customs_value.

T&D inside a rate request

Send incoterms with your rate request. Each rate then includes the tax and duty estimate.

RatesPOST /2024-09/rates (excerpts)
// Request (excerpt) { "incoterms": "DDP", "calculate_tax_and_duties": true, ... } // Each rate in the response (excerpt) { "estimated_import_tax": 10.00, "estimated_import_duty": 2.50, "ddp_handling_fee": 1.20 }

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.

DDP needs T&D. incoterms: "DDP" with calculate_tax_and_duties: false returns a 400 error.

Usage and billing

RequestBilled 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.

T&D has its own rate limits, separate from the general API limit. CONFIRM limits per plan Exceeding them returns a 429 error; check the X-RateLimit-* headers.

Errors and limitations

StatusWhyFix
402insufficient_subscription: your plan doesn't include T&DUpgrade your plan
403Your token is missing the advanced scopeEnable public.tax_and_duty:read on your API connection
422invalid_content, e.g. items[2]: hs_code is not an eight-digit numberFix the field named in details
422No tax or duty data for that route or HS codeCheck the HS code and the countries
429Rate limit reachedRetry after X-RateLimit-Reset
Known limitations. Fixed-amount tariffs (e.g. Switzerland) aren't supported. Countries that change their import rules often (e.g. Saudi Arabia) may take time to be reflected in the results.

Did this page help you?