Tariff API and embeddable duty calculator

Send an HTS code, a country of origin and a customs value; get back an estimate of U.S. import duty, the Merchandise Processing Fee (MPF), the Harbor Maintenance Fee (HMF) and landed cost. It is the same engine that runs the Airlift USA tariff simulator, open over plain HTTP. Free, with no key and no signup.

Not writing code? Paste two lines of HTML and the calculator below appears on your own site.

Try the widget

This is the real widget, loaded from /widget/tariff-widget.js and calling the live API: the same file and the same endpoint your embed will use.

Embed the widget on your site

Paste this where you want the calculator to appear. It has no dependencies, renders inside a Shadow DOM so your styles and its styles can't clash, and weighs about 6 KB gzipped.

HTML
<div id="airlift-tariff-widget" data-origin="IN" data-hts="6802.23.00.00"></div>
<script src="https://airliftusa.com/widget/tariff-widget.js" async></script>

Widget options

AttributeEffect
data-htsPre-fills the HTS code field, e.g. 6802.23.00.00.
data-originPre-selects the country of origin by ISO 2-letter code, e.g. IN.
data-valuePre-fills the customs value in USD.
data-entry-datePre-fills the entry date as YYYY-MM-DD. Defaults to today.
data-transport-modeocean (default), air, truck, rail or mail. Only vessel arrivals pay the Harbor Maintenance Fee.
  • No API calls on page load. Nothing is calculated until a visitor presses the button.
  • Several calculators on one page. Add the class airlift-tariff-widget to each element that should hold one.
  • No blank boxes when something fails. If the API is unreachable or you hit the rate limit, the widget keeps the form filled in, explains what happened and links to the full simulator.

API endpoints

Base URL: https://api.myairliftusa.com/api/tariff. Requests and responses are JSON, and CORS is open, so browser code can call the API without a proxy.

Optional: send X-Airlift-Client: your-app/1.0 to identify your integration. It is logged, never required, and does not change your rate limit.

POST/api/tariff/calculate

Estimates duty, customs fees (MPF and HMF) and landed cost for one HTS code, country of origin and customs value.

Request

{
  "hts_code": "6802.23.00.00",
  "origin_country": "IN",
  "value": 25000,
  "quantity": 1,
  "entry_date": "2026-09-01",
  "transport_mode": "ocean"
}

Response

{
  "hts_code": "6802.23.00.00",
  "origin_country": "IN",
  "value": 25000,
  "quantity": 1,
  "unit": "",
  "general_rate": "3.7%",
  "special_rate": "Free (A+,AU,BH,...)",
  "other_rate": "40%",
  "applicable_rate": "3.7%",
  "duty_amount": 925,
  "breakdown": {
    "ad_valorem_duty": 925,
    "additional_duties": 0,
    "total_duty": 925,
    "tariff_components": [
      {
        "hts_code": "6802.23.00.00",
        "description": "General (MFN) duty",
        "rate": "3.7%",
        "duty_amount": 925
      }
    ]
  },
  "hmf": 31.25,
  "mpf": 86.6,
  "landed_cost": 26042.85,
  "entry_date": "2026-09-01",
  "transport_mode": "ocean",
  "assumptions": [
    "Antidumping/countervailing duties, excise taxes and quota provisions are not included"
  ],
  "measures_version": "2026-09-03"
}

GET/api/tariff/hts/{hts_code}

Returns the schedule entry for one exact code, with children[] and footnotes[] when present. Returns 404 if the code is not in the schedule.

Response

{
  "id": 41233,
  "htsno": "6802.23.00.00",
  "description": "Granite: Other",
  "units": ["kg"],
  "general": "3.7%",
  "special": "Free (A+,AU,BH,...)",
  "other": "40%",
  "footnotes": [
    { "id": 912, "htsEntryId": 41233, "columns": ["general"], "value": "See 9903.88.15.", "type": "endnote" }
  ]
}

GET/api/tariff/countries

Lists the origins the engine recognizes. Use code as the origin_country value on /calculate.

Response

[
  { "id": 6, "code": "IN", "name": "India", "isoCode": "IN" },
  { "id": 2, "code": "CN", "name": "China", "isoCode": "CN" }
]

GET/api/tariff/version

Reports which rule set and schedule edition answered your request. If measures_version differs from the value inside a cached calculation, recompute.

Response

{
  "measures_version": "2026-10-05",
  "schedule_revision": "2026 rev 20",
  "build": "a1b2c3d"
}

Request fields for /calculate

FieldTypeRequiredNotes
hts_codestringYes8- or 10-digit HTS code, with or without dots.
origin_countrystringYesISO 2-letter code from /countries.
valuenumberYesCustoms value in USD.
quantitynumberYesQuantity in unit. Only matters for specific (per-unit) rates.
unitstringNoUnit of quantity, e.g. kg or No.
entry_datestringNoYYYY-MM-DD, defaults to today. Rates are dated, so this changes the answer.
transport_modestringNoocean (default), air, truck, rail, mail.
usmca_qualifyingbooleanNoGoods of Canada or Mexico meeting USMCA rules of origin.
us_content_sharenumberNo0–1 share of U.S. content in a USMCA-qualifying vehicle.
fta_qualifyingbooleanNoWhether a preferential claim will be made when the origin is eligible. Defaults to true.
civil_aircraftbooleanNoEntered under the civil-aircraft certification (General Note 6).

Reading the /calculate response

  • breakdown.tariff_components[] is the duty stack, one row per measure applied: first the base rate (Column 1 General, Special or Column 2), then any Chapter 99 additional-duty lines. Each row has its own hts_code, description, rate and duty_amount.
  • The top-level duty_amount is the sum of those rows.
  • mpf and hmf are the two statutory customs fees.
  • landed_cost is value plus duty plus those two fees.
  • assumptions[] lists everything the engine had to assume. Show it to your users next to the number.

Error codes

StatusWhenBody
400 Bad RequestMalformed JSON, or a request that fails validation: bad HTS format, unknown country, non-positive value, unparseable entry_date.Plain text
404 Not FoundThe HTS code is not in the current schedule.Plain text: HTS code not found
429 Too Many RequestsYou are over the rate limit. Wait at least the number of seconds in Retry-After before retrying.JSON: {"error":"rate limit exceeded"}
500 Internal Server ErrorA server or upstream failure. Retry with backoff.Plain text

Branch on the status code, not the body: only the 429 body is JSON, and the rest are plain text.

Rate limits

Limits apply per client IP address, enforced with a token bucket. Your address is the first hop of X-Forwarded-For when present, otherwise the socket address.

EndpointSustainedBurst
/calculate, /search, /hts/{code}, /countries, /version60 requests / minute20
/health300 requests / minute100

Every response carries X-RateLimit-Limit and X-RateLimit-Remaining. When the bucket empties you get 429 with a Retry-After header in whole seconds and {"error":"rate limit exceeded"}. Wait at least that long before retrying. CORS preflight requests don't count against the limit.

Cache aggressively. /countries and /version change a handful of times a year. A calculation for the same hts_code, origin_country and entry_date stays the same until the schedule changes, and measures_version tells you when that happens. Need more headroom? Talk to us rather than working around the limit.

Attribution (required)

The API is free; attribution is the price. Any public-facing use of the API or the widget must show a visible credit that links back to the simulator:

Powered by <a href="https://airliftusa.com/tariff-simulator">Airlift USA Tariff Simulator</a>

The widget adds that line itself on every embed, and it can't be turned off. If you call the API directly, put the same credit next to the numbers you display.

How results are calculated and versioned

Additional-duty logic follows the Chapter 99 text of the tariff schedule. It is checked against broker-filed entry summaries and against Census records of the duty CBP actually collects. The Chapter 99 lines in breakdown.tariff_components[] are the ones brokers file.

entry_date selects the rules in force on that date, so changing it can legitimately change the result. Every calculation carries the measures_version that produced it, and GET /api/tariff/version reports the rule set, the USITC schedule edition currently loaded and the build of the running engine. When the version in a cached result no longer matches the live one, recompute.

Terms of use

  • Figures are estimates for planning purposes only, provided as is and without warranty of any kind, express or implied.
  • U.S. Customs and Border Protection determines the final duty owed on any entry. Classification remains the importer's responsibility.
  • Duty rates, exclusions and additional-duty programs change frequently. A result is a snapshot of the rule set named in measures_version, not a quotation.
  • Not included: anti-dumping and countervailing duties, excise taxes, quota and admissibility holds, and freight, insurance and brokerage charges.
  • Nothing returned by this API is customs, legal or tax advice.
  • Airlift USA arranges customs clearance through our licensed broker network. Before you rely on a number for a real entry, have us check it.

Related tools

We value your privacy

We use cookies to keep our portal working, measure site usage, and analyse the businesses that visit us. Under U.S. state privacy laws, the data we share with our analytics, advertising and sales partners is considered a “sale” or “sharing” of personal data.