Classification + Tariff Calculation API Enterprise HTS and duty API

Stop classifying every line by hand.

One API call turns a product description and its origin into a 10-digit HTS code and every duty layer, as JSON.

POST /openapi/v1/tariff/batch
RequestResponse
200 OK
{ "items": [ { "item_id": "SKU-DE-001", "status": "ok", "hts_code": "6109.10.0012", "tariffs": { "general_rate": "16.5%", "special_rate": "Free", "Section 301": [], "Section 232 - Metals": [] } }, { "item_id": "SKU-FR-002", "status": "ok", … } ], "summary": { "total": 2, "succeeded": 2, "failed": 0 }}

Illustration using the sample batch from the API manual: a request log for POST /openapi/v1/tariff/batch shows a 200 OK JSON response for two cotton T-shirts with hts_code 6109.10.0012 highlighted, beside a Your items panel showing Total 2, Succeeded 2 and Failed 0.

What is the Classification + Tariff Calculation API?

The short answer first.

CH06Classification + Tariff Calculation API

The Classification + Tariff Calculation API is GingerControl's REST API for HTS classification and U.S. duty calculation, for enterprise customers. Your system posts a plain product description and its country of origin, one product or a batch, 120 by default, and gets back JSON: a 10-digit HTS code, the general and special rates, and every Section 301 and Section 232 line with its Chapter 99 heading. Split-code goods such as Chapter 91 watches come back as components. The results feed entry prep that a licensed customs broker reviews.

Made for
Logistics providers, postal operators, 3PLs and platforms that classify at volume
You send
A description and country of origin, one product or 120 per call by default
You get back
A 10-digit HTS code and every duty layer, as JSON

How does one call work?

Three steps, from your system to a code and back.

  1. Send descriptions and origins.

    POST one product, or a batch with your own item_id on each line. Your API key rides in a request header.

    Illustration using the sample batch from the API manual: the Request tab of a request sent from your system shows a JSON body with two cotton T-shirts, from DE and FR, each with its own item_id. Beside it, the request headers with the API key masked sit above a Your items panel that has no codes yet.

  2. Each item gets its own status.

    Results come back in the order you sent them, and one product that fails does not sink the batch. If you hit a 429, Retry-After says how long to wait.

    Illustration using the sample batch from the API manual: a Sending status appears and the Your items panel lists both item_ids in the order they were sent, with their status still pending.

  3. Get the code and every duty layer.

    A 10-digit HTS code, the general and special rates, each Section 301 and 232 line, and a summary of what succeeded.

    Illustration using the sample batch from the API manual: the Response tab shows 200 OK and the JSON response with hts_code 6109.10.0012 highlighted, and the Your items panel shows Total 2, Succeeded 2 and Failed 0 with each item's HTS code marked OK.

POST /openapi/v1/tariff/batch
RequestResponse
From your system
Body
{ "items": [ { "item_id": "SKU-DE-001", "description": "Cotton knit short sleeve T-shirt", "country_of_origin": "DE", "extra": { "steel_pour_country": "IT" } }, { "item_id": "SKU-FR-002", "description": "Cotton crew neck T-shirt", "country_of_origin": "FR", "extra": {} } ]}
  1. Send descriptions and origins.

    POST one product, or a batch with your own item_id on each line. Your API key rides in a request header.

    POST /openapi/v1/tariff/batch
    RequestResponse
    From your system
    Body
    { "items": [ { "item_id": "SKU-DE-001", "description": "Cotton knit short sleeve T-shirt", "country_of_origin": "DE", "extra": { "steel_pour_country": "IT" } }, { "item_id": "SKU-FR-002", "description": "Cotton crew neck T-shirt", "country_of_origin": "FR", "extra": {} } ]}

    Illustration using the sample batch from the API manual: the Request tab of a request sent from your system shows a JSON body with two cotton T-shirts, from DE and FR, each with its own item_id. Beside it, the request headers with the API key masked sit above a Your items panel that has no codes yet.

  2. Each item gets its own status.

    Results come back in the order you sent them, and one product that fails does not sink the batch. If you hit a 429, Retry-After says how long to wait.

    POST /openapi/v1/tariff/batch
    RequestResponse
    Sending
    Body
    { "items": [ { "item_id": "SKU-DE-001", "description": "Cotton knit short sleeve T-shirt", "country_of_origin": "DE", "extra": { "steel_pour_country": "IT" } }, { "item_id": "SKU-FR-002", "description": "Cotton crew neck T-shirt", "country_of_origin": "FR", "extra": {} } ]}

    Illustration using the sample batch from the API manual: a Sending status appears and the Your items panel lists both item_ids in the order they were sent, with their status still pending.

  3. Get the code and every duty layer.

    A 10-digit HTS code, the general and special rates, each Section 301 and 232 line, and a summary of what succeeded.

    POST /openapi/v1/tariff/batch
    RequestResponse
    200 OK
    { "items": [ { "item_id": "SKU-DE-001", "status": "ok", "hts_code": "6109.10.0012", "tariffs": { "general_rate": "16.5%", "special_rate": "Free", "Section 301": [], "Section 232 - Metals": [] } }, { "item_id": "SKU-FR-002", "status": "ok", … } ], "summary": { "total": 2, "succeeded": 2, "failed": 0 }}

    Illustration using the sample batch from the API manual: the Response tab shows 200 OK and the JSON response with hts_code 6109.10.0012 highlighted, and the Your items panel shows Total 2, Succeeded 2 and Failed 0 with each item's HTS code marked OK.

What comes back in one call?

The code, the base rates and each duty layer with its Chapter 99 lines, in one response.

POST /openapi/v1/tariff200 OK

Request body

{
"description": "Cotton knit short sleeve T-shirt","country_of_origin": "CN",
"extra": { "steel_pour_country": "IT", "aluminum_pour_country": "FR"}

Pour countriesWhere the steel was melted and poured and the aluminum smelted and cast. Section 232 metals duty depends on both.

}

Response

{
"hts_code": "6109.10.0012",

10-digit HTS codeThe U.S. code for this product, for your broker to review before it goes on an entry.

"tariffs": {
"general_rate": "16.5%","special_rate": "Free",

Base ratesThe general (MFN) and special rates, as the HTS prints them.

"Section 301": [ { "code": "9903.88.15", "rate": "7.5%" }, { "code": "9903.05.31", "rate": "12.5%" }],

Section 301Each line is a Chapter 99 heading and its rate, the line your broker reports on the entry.

"Section 232 - Metals": []

Section 232 metalsEmpty for a cotton T-shirt. Steel or aluminum content would put its Chapter 99 lines here.

}
}

Split-code response

{
"hts_code": "9101.11.40","tariffs": null,
"components": [ { "hts_code": "9101.11.4010", "tariffs": {…} }, { "hts_code": "9101.11.4020", "tariffs": {…} }, { "hts_code": "9101.11.4030", "tariffs": {…} }, { "hts_code": "9101.11.4040", "tariffs": {…} }]

Split-code componentsChapter 91 watches are dutiable part by part: the 8-digit parent comes back with the movement, case, strap and battery, each with its own 10-digit code and duties.

}

Illustration with sample data: an annotated request and response for POST /openapi/v1/tariff, where a cotton T-shirt from CN returns an HTS code, the general and special rates, two Section 301 lines and an empty Section 232 list, then a watch splits into four component codes.

Questions about the Classification + Tariff Calculation API

What does one API call return?

A 10-digit HTS code for goods entering the United States, the general (MFN) and special rates, and one list per duty layer, such as Section 301 and Section 232 metals, where each entry is a Chapter 99 heading with its rate. An empty list means that layer does not apply. Split-code products return a components array instead.

How do we plug tariff and classification data into our own systems?

Call the Classification + Tariff Calculation API from your ERP, quoting tool or entry-prep workflow. Send a product description and its origin, and get back a 10-digit HTS code, the base rates and each Chapter 99 duty layer as JSON, one product at a time or 120 per batch call by default. A licensed customs broker still reviews a code before it goes on an entry.

Is it a landed cost API?

It covers the duty part of landed cost. The API returns the duty rates and Chapter 99 lines; your system applies them to the customs value and adds freight, insurance and fees. It is built for pre-import decisions and entry prep. If you need guaranteed duties and taxes shown to shoppers at checkout, checkout tools such as Zonos and Avalara are built for that job.

How does it handle split-code products like watches?

Some goods, such as Chapter 91 watches, are dutiable part by part rather than as one unit. For those the API returns the 8-digit parent code and a components array: each part gets its own 10-digit HTS code and its own tariff data, worked out on our side in the same call.

What are the batch limits?

120 products per batch call by default, and we can size it to your throughput, each with a description of up to 10,000 characters. Each item carries your own item_id and comes back with its own status, ok or failed, in the order you sent it, so one product that cannot be classified does not fail the batch. The single and batch endpoints draw from the same item quota under your key.

How much traffic can it handle?

As much as your key is set up for. Every key has its own rate limit and item quota, and we size a production key after learning your calling pattern, IP allowlist and peak QPS. If you go over, the API answers 429 Too Many Requests with a Retry-After header that tells your client how many seconds to wait.

How do I get an API key?

The API is for enterprise customers, so it starts with a call: use the Ask for an API key button at the top of this page. We learn your calling pattern, IP allowlist and peak QPS, set your key's rate limit and item quota to match, and send the key through an offline channel such as email.

Do I need to be a licensed customs broker to use the API?

No. The API returns research output: an HTS code and the duty layers for your systems to use in quoting and entry prep. Per CBP ruling HQ H290535, classifying specific goods beyond six digits for importation is customs business under 19 U.S.C. § 1641, so a licensed customs broker reviews a code before it goes on an entry. GingerControl is not a broker.

Can the API classify export controls (ECCN)?

No. The API covers U.S. import classification and duties. Export control classification runs in the Export Control Classifier web app, which has no API today.

Where is the full technical documentation?

In the API reference at gingercontrol.com/products/openapi. It documents both endpoints, every request and response field, the error codes, headers and rate-limit rules, with curl examples you can paste.

Want an AI system that fits your process?

See GingerOS.

GingerOS is the trade compliance system we build on your own process: every code keeps its reason, and every change in your company triggers its own compliance recheck (tariffs, classification, export controls and more).

Click Me!

See how GingerOS works