Customs duties and landed cost
POST /v1/duties/quote returns an estimate of the import duty, import VAT/GST and customs fees on a cross-border cart, without recording a calculation. The same estimate comes back on POST /v1/tax/calculate and POST /v1/tax/calculate/partner when you pass duties.include: true (or turn on the dutiesEnabled setting). Every measure is named, so a broker can reproduce the figure.
totalTax or totalAmountWithTax, and your tax figures are identical with duties off, on, or degraded. The one amount a checkout may add is summary.importChargesAtCheckout; summary.totalAmountDue, present only alongside it, is totalAmountWithTax plus that amount. Figures are estimates and are not guaranteed: reconcile any difference with the carrier or broker invoice.See also the Tax Calculations reference for the full calculate request and response.
What to send
The body is the POST /v1/tax/calculate body. duties.include is implied on a quote; commit, credit notes and transactionDirection: "purchase" are rejected with 422. A quote is stateless: nothing is stored and no idempotency key is read. A partner_calc key adds the same required sellerRegistrationContext and partnerMerchantId as POST /v1/tax/calculate/partner.
| Field | Type | Description |
|---|---|---|
| lineItems[].commodityCode | string | The tariff code the duty is priced at. The most important input: it decides the precision of the estimate. |
| lineItems[].commodityCodeScheme | "HS6" | "CN8" | "TARIC10" | "UK10" | "HTS10" | Scheme of that code. Omitted: inferred from the digit count and the destination (schemeInferred: true on the result). A national code is exact only in its own territory; anywhere else its first six digits are used and the result is HS6_EXACT or HS6_AMBIGUOUS, not an error. |
| lineItems[].countryOfOrigin | string | ISO 3166-1 alpha-2. Never inferred from shipFrom. Falls back to the product catalogue, then duties.defaultCountryOfOrigin, then the account default. |
| lineItems[].weight | object | { value, unit } with unit kg, g, lb or oz; per unit. Needed for per-kilogram duties. |
| shipFrom / lineItems[].shipFrom | object | Where goods are dispatched from; a different customs territory from the destination makes a customs crossing. customsStatus: "bonded" marks stock held under customs control. |
| incoterms / importerOfRecord | string | Who imports. importerOfRecord wins over incoterms (DDP is the seller, any other rule the buyer), which wins over the account defaultImporterOfRecord. |
| insurance | object | { amount, currency? }, part of the customs value where the destination values goods CIF. |
| duties.collectDeposit | boolean | Ask for the estimate to be collected at checkout when the buyer is the importer. |
| duties.defaultCountryOfOrigin, duties.ratePolicyForHs6 | string | Per-request overrides of the account settings. ratePolicyForHs6 is modal or highest; a collected deposit always uses the highest rate. |
Mapping a Shopify product
| Shopify | Clearvo line item |
|---|---|
harmonizedSystemCode | commodityCode (scheme inferred, or set commodityCodeScheme) |
countryHarmonizedSystemCodes[] | The entry for the destination country is its commodityCode with that country's national commodityCodeScheme. |
countryCodeOfOrigin | countryOfOrigin |
weight and weightUnit | weight.value and weight.unit |
| Product taxonomy category | classificationCodes: [{ "system": "shopify", "code": "aa-1-13" }]. Used when no code is sent, so the line is priced from its category as a proxy and never collected. |
What to show at checkout
Decide by consignments[].responsibleParty and collectedAtCheckout. Every quoted consignment also carries collection.reason, which says why nothing is collected when you asked for a deposit.
responsibleParty | collectedAtCheckout | Typical case | Tax fields (unchanged) | Show the buyer |
|---|---|---|---|---|
seller | false | DDP registered seller; IOSS up to €150 (the €3 is the IOSS holder's cost) | Normal destination VAT/GST or IOSS at checkout, or US sales tax on the price | Nothing new. Use landedCost for pricing and margin. |
customer | false | DAP or buyer importer, no deposit | OUT_OF_SCOPE, tax code O, rate 0 | Optional notice: "Import duties and taxes of approximately X may be payable to the carrier on delivery." Not added to the total. |
customer | true | Deposit model (duties.collectDeposit, buyer is importer) | Same as above | Add summary.importChargesAtCheckout as its own line, "Estimated import charges"; charge totalAmountDue. Never label it tax. Refund any excess. |
| any | any | duties.status: "not_applicable": domestic, intra-EU, GB to GB | Normal | Nothing. |
Reading an estimate
duties.statusisquoted,not_applicable,degradedordisabled. A duty failure is a 200 withdegradedand areason, never a 5xx, and it never changes the tax figures or the calculation's owndegradedflag.estimate: falsemeans no modelled source of variance (a flat or zero regime, or tariff-line precision with no origin-scoped measure and no static FX). It is never a guarantee: the declarant's classification, valuation, origin and declaration choices prevail.estimateReasonsis the closed list behindestimate: true.precisionrunsTARIFF_LINE,HS6_EXACT,HS6_AMBIGUOUS,PLATFORM_CODE,CATEGORY_PROXY,CHAPTER_PROXY,UNRESOLVED. The last three are never collected from a buyer.- Each measure carries its
rateExpression, a closed union:ad_valorem_pct,top_up_to_pct,flat,specific,compound,alternativeandmin_max. - Measures that exist but could not be evaluated (not yet in force, or origin unknown) are in
notEvaluatedand block collection. - The IOSS response may also carry
customsDuty. It is the same €3 per item as the consignment'sduty(sourcefee_rule):customsDutyis that one fee,consignments[]is the whole landed-cost estimate, so never add the two together. - Amounts using a static FX rate say so in
fx.sourceandfxSource; they are not live rates.
Turn duties on for the account with PATCH /v1/tax/settings: dutiesEnabled, dutyRatePolicyForHs6, defaultCountryOfOrigin. The quote_duties tool in the Clearvo MCP server and clearvo duties quote in the CLI call this endpoint; the TypeScript SDK exposes quoteDuties() and the DutiesResult type.
Example 1: $40 China-origin T-shirt, UK warehouse to Texas
{
"currency": "USD",
"date": "2026-10-03",
"supplier": {
"name": "Acme Apparel Ltd",
"billingAddress": {
"country": "GB",
"postalCode": "SW1A 1AA"
}
},
"customer": {
"name": "Jordan Lee",
"billingAddress": {
"country": "US",
"region": "TX",
"postalCode": "78701"
},
"shippingAddress": {
"country": "US",
"region": "TX",
"postalCode": "78701"
}
},
"shipFrom": {
"country": "GB",
"postalCode": "SW1A 1AA"
},
"lineItems": [
{
"id": "l1",
"amount": 40,
"quantity": 1,
"productName": "Cotton T-shirt",
"commodityCode": "6109100012",
"commodityCodeScheme": "HTS10",
"countryOfOrigin": "CN"
}
],
"duties": {
"include": true
}
}
{
"currency": "USD",
"duties": {
"status": "quoted",
"contentVersion": 1
},
"consignments": [
{
"id": "c1",
"lineIds": [
"l1"
],
"status": "quoted",
"dispatchTerritory": "GB",
"destinationTerritory": "US",
"customsStatus": "free_circulation",
"valuation": {
"basis": "FOB",
"goods": 40,
"freight": 0,
"insurance": 0,
"customsValue": 40,
"currency": "USD"
},
"regime": null,
"duty": {
"total": 9.6,
"source": "tariff",
"estimate": true
},
"importTax": {
"label": null,
"collection": "none",
"base": 40,
"rate": 0,
"amount": 0,
"baseIncludes": [
"customs_value"
],
"sellerRegistrationRequired": false,
"notes": []
},
"fees": [
{
"code": "US_MPF_INFORMAL",
"label": "Merchandise Processing Fee (informal entry)",
"amount": 2.77,
"currency": "USD",
"basis": "flat",
"entryType": "informal",
"entryTypeAssumed": true,
"incidence": "SELLER_COST"
}
],
"responsibleParty": "unresolved",
"responsiblePartySource": "unresolved",
"collectedAtCheckout": false,
"collection": {
"requested": false,
"collected": false,
"reason": "not_requested"
},
"landedCost": 52.37,
"importChargesAtCheckout": 0,
"sellerBorne": {
"duty": 0,
"importTax": 0,
"fees": 0,
"total": 0
},
"precision": "TARIFF_LINE",
"estimate": true,
"estimateReasons": [
"origin_measures_apply",
"measure_not_in_force",
"preference_not_considered",
"entry_type_assumed"
],
"notEvaluated": [
{
"familyCode": "US_301_BY_ORIGIN_CN",
"measureType": "SECTION_301_BY_ORIGIN",
"reason": "not_in_force",
"legalStatus": "announced"
}
],
"fxSource": null,
"sellerRegistrationGap": false
}
],
"lineItems": [
{
"id": "l1",
"duty": {
"consignmentId": "c1",
"commodityCode": "6109100012",
"scheme": "HTS10",
"codeSource": "request",
"precision": "TARIFF_LINE",
"origin": "CN",
"originSource": "request",
"customsValue": 40,
"amount": 9.6,
"measures": [
{
"type": "MFN",
"rate": 0.165,
"rateExpression": {
"type": "ad_valorem_pct",
"value": 16.5
},
"amount": 6.6,
"legalBasis": null,
"effectiveFrom": "2026-01-01"
},
{
"type": "SECTION_301_LIST_4A",
"rate": 0.075,
"rateExpression": {
"type": "ad_valorem_pct",
"value": 7.5
},
"amount": 3,
"legalBasis": "HTSUS 9903.88.15",
"effectiveFrom": "2026-01-01"
}
],
"notEvaluated": [
{
"familyCode": "US_301_BY_ORIGIN_CN",
"measureType": "SECTION_301_BY_ORIGIN",
"reason": "not_in_force",
"legalStatus": "announced"
}
],
"missingInputs": [],
"estimateReasons": [
"origin_measures_apply",
"measure_not_in_force",
"preference_not_considered"
]
}
}
],
"summary": {
"totalDuty": 9.6,
"totalImportTax": 0,
"totalImportFees": 2.77,
"totalLandedCost": 52.37,
"sellerBorneImportCosts": 0
}
}
How to read it
- Duty $9.60: 16.5% MFN ($6.60) plus 7.5% Section 301 List 4A ($3.00). The by-origin China measure is announced, not in force: it is listed in
notEvaluatedand never applied. - The informal-entry Merchandise Processing Fee of $2.77 applies (a $40 parcel is an informal entry,
entryTypeAssumed: true), not the $34.58 formal-entry minimum. A fee is a seller cost and is never added to what the buyer pays. - No importer of record is set, so
responsiblePartyisunresolvedand nothing is collected (collection.reason: not_requested). Texas sales tax on the $40 is unchanged.estimate: truebecause origin-scoped measures apply and one is not in force.
Example 2: €120 item, UK to France, IOSS-registered seller
{
"currency": "EUR",
"date": "2026-10-03",
"supplier": {
"name": "Acme Apparel Ltd",
"billingAddress": {
"country": "GB",
"postalCode": "SW1A 1AA"
}
},
"customer": {
"name": "Camille Martin",
"billingAddress": {
"country": "FR",
"postalCode": "75001"
},
"shippingAddress": {
"country": "FR",
"postalCode": "75001"
}
},
"shipFrom": {
"country": "GB",
"postalCode": "SW1A 1AA"
},
"importerOfRecord": "BUYER",
"lineItems": [
{
"id": "l1",
"amount": 120,
"quantity": 1,
"productName": "Cotton T-shirt",
"commodityCode": "61091000",
"commodityCodeScheme": "CN8",
"countryOfOrigin": "GB"
}
],
"duties": {
"include": true,
"collectDeposit": true
}
}
{
"currency": "EUR",
"duties": {
"status": "quoted",
"contentVersion": 1
},
"consignments": [
{
"id": "c1",
"lineIds": [
"l1"
],
"status": "quoted",
"dispatchTerritory": "GB",
"destinationTerritory": "EU",
"customsStatus": "free_circulation",
"valuation": {
"basis": "CIF",
"goods": 120,
"freight": 0,
"insurance": 0,
"customsValue": 120,
"currency": "EUR"
},
"regime": {
"code": "EU_IOSS_150",
"name": "EU_IOSS_150",
"basis": "intrinsic_value",
"thresholdAmount": 150,
"thresholdCurrency": "EUR",
"comparedValue": 120,
"nearThreshold": false,
"consequence": {
"vat": "checkout",
"duty": "flat_per_item"
},
"feeCode": "EU_LOW_VALUE_CONSIGNMENT_CUSTOMS_DUTY",
"taxTreatmentMismatch": false,
"notes": []
},
"duty": {
"total": 3,
"source": "fee_rule",
"feeCode": "EU_LOW_VALUE_CONSIGNMENT_CUSTOMS_DUTY",
"estimate": false
},
"importTax": {
"label": "VAT",
"collection": "checkout",
"base": 123,
"rate": 0,
"amount": 0,
"baseIncludes": [
"customs_value",
"duty",
"freight"
],
"sellerRegistrationRequired": false,
"notes": []
},
"fees": [],
"responsibleParty": "seller",
"responsiblePartySource": "regime",
"collectedAtCheckout": false,
"collection": {
"requested": true,
"collected": false,
"reason": "regime_vat_at_checkout"
},
"landedCost": 123,
"importChargesAtCheckout": 0,
"sellerBorne": {
"duty": 3,
"importTax": 0,
"fees": 0,
"total": 3
},
"precision": null,
"estimate": false,
"estimateReasons": [],
"notEvaluated": [],
"fxSource": null,
"sellerRegistrationGap": false
}
],
"lineItems": [
{
"id": "l1",
"duty": {
"consignmentId": "c1",
"commodityCode": "61091000",
"scheme": "CN8",
"codeSource": "request",
"precision": null,
"origin": "GB",
"originSource": "request",
"customsValue": 120,
"amount": 3,
"measures": [
{
"type": "REGIME_FLAT",
"rate": null,
"rateExpression": {
"type": "flat",
"amount": 0,
"currency": "EUR"
},
"amount": 3,
"legalBasis": null,
"effectiveFrom": "2026-07-01"
}
],
"notEvaluated": [],
"missingInputs": [],
"estimateReasons": []
}
}
],
"summary": {
"totalDuty": 3,
"totalImportTax": 0,
"totalImportFees": 0,
"totalLandedCost": 123,
"sellerBorneImportCosts": 3
}
}
How to read it
- French VAT is collected at checkout under IOSS and sits in
totalTax, so import VAT is0withcollection: "checkout"and nothing is added to the buyer's total. - The EU €3 per-item customs duty is the IOSS holder's cost:
responsibleParty: "seller",collection.reason: "regime_vat_at_checkout",importChargesAtCheckout: 0,sellerBorne.duty: 3. - Asking for a deposit and naming the buyer as importer changes nothing: under IOSS the declarant is the seller.
estimate: falsemeans no modelled source of variance, not a guarantee.
Example 3: the same item at €200, China origin, DAP
{
"currency": "EUR",
"date": "2026-10-03",
"supplier": {
"name": "Acme Apparel Ltd",
"billingAddress": {
"country": "GB",
"postalCode": "SW1A 1AA"
}
},
"customer": {
"name": "Camille Martin",
"billingAddress": {
"country": "FR",
"postalCode": "75001"
},
"shippingAddress": {
"country": "FR",
"postalCode": "75001"
}
},
"shipFrom": {
"country": "GB",
"postalCode": "SW1A 1AA"
},
"incoterms": "DAP",
"lineItems": [
{
"id": "l1",
"amount": 200,
"quantity": 1,
"productName": "Cotton T-shirt",
"commodityCode": "61091000",
"commodityCodeScheme": "CN8",
"countryOfOrigin": "CN"
},
{
"id": "ship",
"amount": 12,
"productName": "Shipping",
"taxCategory": "shipping_handling"
}
],
"duties": {
"include": true,
"collectDeposit": true
}
}
{
"currency": "EUR",
"duties": {
"status": "quoted",
"contentVersion": 1
},
"consignments": [
{
"id": "c1",
"lineIds": [
"l1"
],
"status": "quoted",
"dispatchTerritory": "GB",
"destinationTerritory": "EU",
"customsStatus": "free_circulation",
"valuation": {
"basis": "CIF",
"goods": 200,
"freight": 12,
"insurance": 0,
"customsValue": 212,
"currency": "EUR"
},
"regime": null,
"duty": {
"total": 25.44,
"source": "tariff",
"estimate": false
},
"importTax": {
"label": "VAT",
"collection": "border",
"base": 237.44,
"rate": 0.2,
"amount": 47.49,
"baseIncludes": [
"customs_value",
"duty",
"freight"
],
"sellerRegistrationRequired": false,
"notes": []
},
"fees": [],
"responsibleParty": "customer",
"responsiblePartySource": "incoterms",
"collectedAtCheckout": true,
"collection": {
"requested": true,
"collected": true,
"reason": "collected"
},
"landedCost": 284.93,
"importChargesAtCheckout": 72.93,
"sellerBorne": {
"duty": 0,
"importTax": 0,
"fees": 0,
"total": 0
},
"precision": "TARIFF_LINE",
"estimate": false,
"estimateReasons": [],
"notEvaluated": [],
"fxSource": null,
"sellerRegistrationGap": false
}
],
"lineItems": [
{
"id": "l1",
"duty": {
"consignmentId": "c1",
"commodityCode": "61091000",
"scheme": "CN8",
"codeSource": "request",
"precision": "TARIFF_LINE",
"origin": "CN",
"originSource": "request",
"customsValue": 212,
"amount": 25.44,
"measures": [
{
"type": "MFN",
"rate": 0.12,
"rateExpression": {
"type": "ad_valorem_pct",
"value": 12
},
"amount": 25.44,
"legalBasis": null,
"effectiveFrom": "2026-01-01"
}
],
"notEvaluated": [],
"missingInputs": [],
"estimateReasons": []
}
}
],
"summary": {
"totalDuty": 25.44,
"totalImportTax": 47.49,
"totalImportFees": 0,
"totalLandedCost": 284.93,
"sellerBorneImportCosts": 0,
"importChargesAtCheckout": 72.93,
"totalAmountDue": 284.93
}
}
How to read it
- Above €150 no low-value regime applies. Duty €25.44 is 12% of a CIF customs value of €212 (200 goods + 12 freight). Import VAT €47.49 is 20% of customs value plus duty (€237.44).
incoterms: "DAP"makes the buyer the importer and a deposit was requested, socollectedAtCheckoutistrueandsummary.importChargesAtCheckoutis €72.93. Show it as its own line, "Estimated import charges"; chargetotalAmountDue.- With
incoterms: "DDP"the same cart is seller-borne and nothing is collected.
Data sources and attribution
- United Kingdom: Contains public sector information licensed under the Open Government Licence v3.0.
- European Union: Combined Nomenclature and TARIC data, source acknowledged in accordance with Commission Decision 2011/833/EU on the reuse of Commission documents.
- United States: Harmonized Tariff Schedule of the United States (HTSUS), a public-domain work of the US International Trade Commission.
Estimates only, with no guarantee of accuracy. Clearvo is not a customs broker and does not file entries.