Changelog
V.V.1.0.7Headings that state their rate in words now return a pointer
Some headings never state a number. They tell you to look somewhere else:
* `8206.00.00.00` (tool sets) — "the rate of duty applicable to that article in the set
subject to the highest rate of duty"
* `6103.22.00` (ensembles) — "the rate applicable to each garment in the ensemble if
separately entered"
* `9110.11.00.00` (watch movements) — "the rate applicable to the complete, assembled
movement"
* `9005.90.40.00` (optical parts) — "the rate applicable to the article of which it is a
part or accessory"
These used to come back as `rate_type: "unparsed"`, with the sentence in `raw_rate` and
nothing a program could act on. They are now `rate_type: "reference"` and carry
`base_tariff.refers_to`, alongside a `BASE_RATE_REFERENCE` warning,
`summary.base_rate_known: false` and a confidence of 0.5.
Eight pointer kinds are now recognised:
* `set_highest` — the highest-rated article in the set
* `ensemble_component` — each garment, rated as if entered separately
* `parent_article` — the article of which this is a part or accessory
* `assembled_movement` — the complete, assembled movement
* `absence_of_heading` and `absence_of_subheading` — the rate that would apply without it
* `heading` — a named heading, for example `{"targets": ["2009"]}`
* `note` — a named U.S. note, for example `{"note": "U.S. note 3", "basis": "repair_value"}`
* `self_subheading` — this subheading's own rate, optionally with `delta_percentage`,
`plus_percentage`, or `originating_in` for a trade-agreement rate
We record the pointer. We do not follow it. Resolving "heading 2009" on your behalf would
mean choosing one of its children for you, which is a classification decision, not a rate
lookup.
88 duty rows moved from unparsed to reference. Four rows remain unparsed across the whole
schedule: the drawback clauses of `9801.00.70` and `9801.00.80`, which genuinely state no
rate.
Compound duties no longer drop a term, and 201 rates now parse
Two correctness fixes and a large coverage improvement.
A duty carrying both a percentage and a per-unit component was classified from a
denormalised `compound_rate` flag rather than from the components themselves. When a
backfill set the components without the flag, the rate was demoted to `specific` and its
ad valorem side was silently dropped. Thirteen headings were affected, including
`9606.21.40.00` (buttons), whose rate is 4.6% plus 0.3 cents per line per gross.
Separately, ten watch and clock headings had been storing only the first two terms of a
three-term rate, which under-reported their duty.
The rate parser gained coverage for rate shapes it had always refused:
* Chapter 99 special-column rates qualified by a trade program, such as "$1.41/kg (PA)".
* Missing unit aliases: per metre, per linear metre, per pack, per article, per jewel,
per line per gross, per thousand pins.
* Rates with three or more terms, and rates charged on a metal content, a component of the
article, the fair retail value or the cost of repairs.
* The polarimeter-degree sugar formulas of Chapter 17, including their floors.
* Cross-references to another heading, subheading or U.S. note.
* Damage introduced by the source extraction, such as a soft-hyphen break inside a word.
Duties whose rate text contains a number and which we could not parse fell from 203 to 2.
A further 90 headings state their rate in words alone, with no number at all; those are
covered in V.1.0.7.
Unreadable base duties are no longer reported as 0%
When a base duty could not be parsed, the API returned
`rate_type: "ad_valorem", percentage_component: null`, and `summary.notes` said
"Base duty is 0%" alongside `confidence.score: 1.0` and an empty `warnings` array. Any
client that reads a null percentage as zero computed a duty-free base. Our own AI tools
rendered those headings as "Free".
This affected 91 general-column headings, including beet sugar, and the lead, molybdenum,
tungsten and magnesium ores.
A base duty that is not a plain number now says so, on every endpoint including
`resolve_batch`:
* `summary.base_rate_known: false` — `applicable_ad_valorem_rate` excludes the base duty
and is a lower bound.
* `warnings[]` carries one of `BASE_RATE_UNPARSED` (we could not read it),
`BASE_RATE_NOT_CALCULABLE` (we read it but it needs inputs only you hold) or
`BASE_RATE_REFERENCE` (it defers to another heading or note), each with the source text
and, where relevant, `inputs_required` or `refers_to`.
* `confidence` gains a fourth factor, `base_rate`, which drops the score to 0.5.
A specific duty is no longer described as "Base duty is 0%" either. A rate of 68 cents per
head has no ad valorem component, but it is not a zero duty, and the note now says so.
`applicable_ad_valorem_rate` is unchanged in shape and remains a number.
New rate_type values: unparsed, reference and formula
`base_tariff.rate_type` previously returned only `ad_valorem`, `specific` or `compound`.
Three values have been added, and each one replaces a case that used to be reported
misleadingly as `ad_valorem` with a null rate:
* `formula` — we read the rate but cannot total it without inputs only you hold. Carries
`components[]`, `constraints[]`, `inputs_required` and `raw_rate`.
* `reference` — the heading defers to another heading, subheading or U.S. note. Carries
`refers_to` and `raw_rate`.
* `unparsed` — we could not read the rate at all. Carries the verbatim USITC text in
`raw_rate`.
If your integration switches on `rate_type`, add these three cases. A response with
`rate_type` of `formula`, `reference` or `unparsed` has a **null** `percentage_component`,
and a null percentage is not a zero percentage. A `formula` rate deliberately exposes no
scalar at all: for `1.7 cents/kg on lead content`, a `per_unit_component` of 0.017 would
invite you to multiply by total kilograms when the correct multiplicand is the lead
kilograms.
The API path is unchanged and remains `/api/v1`.
Structured rate components on base_tariff
Some US HTS headings carry a base duty that a single number cannot express. A watch
movement is dutiable at "36 cents each + 5.6% + 2 cents per jewel". Lead ore is dutiable
per kilogram **of lead content**, not per kilogram of ore. Beet sugar is dutiable per
kilogram, reduced for every polarimeter degree under 100, with a floor. Until now the API
had only two fields for a rate, `percentage_component` and `per_unit_component`, so these
headings had no honest representation.
`base_tariff` now carries five new fields:
* `components[]` — every term of the rate, as `{kind, value, unit, basis}`. `kind` is
`specific` or `ad_valorem`. `basis` appears only when the term applies to something
other than the entered value or the entered quantity, for example `lead_content`,
`battery`, `fair_retail_value` or `degree_under_100`.
* `constraints[]` — floors and caps, for example `{"kind":"floor","value":0.03143854,"unit":"kg"}`
or `{"kind":"cap","basis":"complete_movement"}`.
* `duty_calculable` — `false` when the duty cannot be totalled from entered value and
entered quantity alone.
* `inputs_required` — what you must supply when `duty_calculable` is `false`, for example
`[{"name":"polarimeter_degrees","unit":"degree"}]`.
* `refers_to` — for headings that name another heading or a U.S. note instead of stating a
rate, for example `{"kind":"heading","targets":["2009"]}`.
These fields are additive. `percentage_component` and `per_unit_component` keep their exact
meaning for ordinary ad valorem, specific and compound rates.
We describe these rates. We do not total them, and we do not follow a reference to another
heading. The jewel count of a movement, the copper content of an ore and the polarimeter
reading of a sugar shipment are facts only the importer holds. Guessing at them would
produce a confident wrong number.
AI Chat Assistant
We have added a new way to discover HTS codes, our AI agent trained on our entire database will be able to help you discover and understand HTS codes.
Organizations: Collaborate on HTS codes with your team
Invite and collaborate on hts codes by inviting your team to your TariffsAPI organization. Share your subscription API and AI credits
Tariff Data Fixes: 8471 Exemption Restored & Cleaner API
Section 122 exemption restored for heading 8471, exempted measures now visible with suppression reasons, and duplicate duties removed.
New API Dashboard
We have refreshed the API dashboard to include more details around API credits, API keys usage and billing.
HTS source on API response
We have added the official source on every API response. You can now always verify the official sources by yourself for every API call.
Better Data Accuracy
We have increased our audit process to increase the data accuracy, including unique cases like the reversal of teh IEEPA tariffs under the current administration.
MCP server connection
Speak directly to TariffsAPI database through our MCP endpoint 🔥
Batch resolve endpoint
You can now query several rates at a time, up to 150 rates in one API call. This is perfect if you have high needs and product interations.
Country-Aware Tariff Resolution (Section 301, Trade Agreements & HTS Inheritance)
“Given an HTS code and a country of origin, what tariffs apply today?” - Try out the /resolve endpoint and our updated tariffs calculator.
Automatic inheritance when exact matches aren't found
querying 8541.10.00.80 will return tariffs from 8541.10.00 when the child has no tariffs.