The Tariff API provides programmatic access to TariffBase tariff rate data, enabling you to integrate customs duty lookups directly into your internal systems -- such as ERP platforms, customs management software, supply chain tools, or e-commerce pricing engines.
Plan requirement: API access requires a Professional or Enterprise plan. Enterprise-exclusive endpoints (Batch Lookup and Nomenclature Download) require the Enterprise plan.
Security: Treat your API key like a password. Do not expose it in client-side code, public repositories, or shared documents.
The TariffBase API uses token-based authentication. Include your API key in the Authorization header for all requests:
Authorization: Token YOUR_API_KEY
Requests without a valid token will receive a 401 Unauthorized response.
Retrieve tariff rates for a specific product code and trading partner.
Plan: Professional, Enterprise
Endpoint:
GET https://www.tariffbase.io/api/v1/tariff-rate/
| Parameter | Type | Required | Description |
|---|---|---|---|
code |
string | Yes | HS product code (e.g., 0101290010) |
partner |
string | Yes | Partner country name (e.g., Afghanistan) |
country |
string | No | Querying country (default: United States) |
The country parameter accepts the following values:
| Country | Description |
|---|---|
United States |
U.S. tariff schedule (default) |
European Union |
EU common external tariff |
China |
China tariff schedule |
The partner parameter accepts full country names (e.g., Afghanistan, Canada, Japan, Germany). The availability of rate data depends on the trade relationships and regimes in the querying country's schedule.
cURL:
curl -X GET "https://www.tariffbase.io/api/v1/tariff-rate/" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Accept: application/json" \
-G \
-d "code=0101290010" \
-d "partner=Afghanistan" \
-d "country=United States"
Python:
import requests
BASE_URL = "https://www.tariffbase.io/api/v1/tariff-rate/"
API_KEY = "YOUR_API_KEY"
params = {
"code": "0101290010",
"partner": "Afghanistan",
"country": "United States",
}
headers = {
"Authorization": f"Token {API_KEY}",
"Accept": "application/json",
}
response = requests.get(BASE_URL, headers=headers, params=params)
if response.status_code == 200:
for row in response.json():
print(f"{row['code']} {row['regime']}: {row['rate']}")
elif response.status_code == 429:
body = response.json()
if body.get("quota_exceeded"):
# Daily quota hit -- counter resets at 00:00 UTC.
print(f"Daily quota reached: {body['current_usage']}/{body['daily_limit']}")
else:
# Per-minute/per-day throttle -- back off and retry.
retry_after = int(response.headers.get("Retry-After", 60))
print(f"Throttled. Retry in {retry_after}s.")
elif response.status_code == 404:
print("No tariff rates found for that code/partner.")
else:
print(f"Error {response.status_code}: {response.text}")
JavaScript (Node.js):
const axios = require('axios');
const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://www.tariffbase.io/api/v1/tariff-rate/';
async function getTariffRates() {
try {
const { data } = await axios.get(BASE_URL, {
headers: {
'Authorization': `Token ${API_KEY}`,
'Accept': 'application/json'
},
params: {
code: '0101290010',
partner: 'Afghanistan',
country: 'United States'
}
});
data.forEach(row => {
console.log(`${row.code} ${row.regime}: ${row.rate}`);
});
} catch (error) {
const res = error.response;
if (res?.status === 429 && res.data?.quota_exceeded) {
// Daily quota hit -- resets at 00:00 UTC.
console.error(`Daily quota reached: ${res.data.current_usage}/${res.data.daily_limit}`);
} else if (res?.status === 429) {
// Per-minute/per-day throttle -- back off and retry.
const retryAfter = res.headers['retry-after'] || 60;
console.error(`Throttled. Retry in ${retryAfter}s.`);
} else if (res?.status === 404) {
console.error('No tariff rates found for that code/partner.');
} else {
console.error('Error:', res?.data || error.message);
}
}
}
getTariffRates();
A successful request returns an array of applicable tariff regimes for the given code and partner:
[
{
"country": "United States",
"partner": "Afghanistan",
"code": "0101290010",
"description": "Horses, live, except purebred breeding, n.e.s.o.i.",
"regime": "MFN",
"regime_name": "Most Favored Nation",
"rate": "2.5%"
},
{
"country": "United States",
"partner": "Afghanistan",
"code": "0101290010",
"description": "Horses, live, except purebred breeding, n.e.s.o.i.",
"regime": "GSP",
"regime_name": "Generalized System of Preferences",
"rate": "0.0%"
}
]
| Field | Type | Description |
|---|---|---|
country |
string | The querying (importing) country |
partner |
string | The trading partner (exporting) country |
code |
string | The queried HS product code |
description |
string | Product description from the tariff schedule |
regime |
string | Regime code (e.g., MFN, GSP, Section 301) |
regime_name |
string | Full name of the tariff regime |
rate |
string | The tariff rate |
The Enterprise Batch API extends the standard Tariff API with high-volume endpoints designed for large-scale data operations. These endpoints are available exclusively on the Enterprise plan.
Plan requirement: All endpoints in this section require an Enterprise subscription. Requests from non-Enterprise accounts will receive a
403 Forbiddenresponse.
Look up tariff rates for multiple HS codes in a single request. Supports up to 50 codes per request with JSON or CSV output.
Endpoint:
POST https://www.tariffbase.io/api/v1/tariff-rate/bulk/
| Parameter | Type | Required | Description |
|---|---|---|---|
codes |
string[] | Yes | List of HS product codes (max 50) |
partner |
string | Yes | Partner country name (e.g., China) |
country |
string | No | Querying country (default: United States) |
output_format |
string | No | json (default) or csv |
cURL:
# JSON response
curl -X POST "https://www.tariffbase.io/api/v1/tariff-rate/bulk/" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"codes": ["0101290010", "0201100010", "0302110000"],
"partner": "China",
"country": "United States",
"output_format": "json"
}'
# CSV download
curl -X POST "https://www.tariffbase.io/api/v1/tariff-rate/bulk/" \
-H "Authorization: Token YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"codes": ["0101290010", "0201100010", "0302110000"],
"partner": "China",
"country": "United States",
"output_format": "csv"
}' -o tariff_rates.csv
Python:
import requests
BULK_URL = "https://www.tariffbase.io/api/v1/tariff-rate/bulk/"
API_KEY = "YOUR_API_KEY"
# Up to 50 codes per request. Duplicates are deduped server-side,
# and each unique code costs one query against your daily quota.
payload = {
"codes": ["0101290010", "0201100010", "0302110000"],
"partner": "China",
"country": "United States",
"output_format": "json",
}
headers = {
"Authorization": f"Token {API_KEY}",
"Content-Type": "application/json",
}
response = requests.post(BULK_URL, json=payload, headers=headers)
if response.status_code == 200:
data = response.json()
print(f"Retrieved {len(data)} rate rows")
for rate in data:
print(f" {rate['code']} {rate['regime']}: {rate['rate']}")
elif response.status_code == 429 and response.json().get("quota_exceeded"):
body = response.json()
print(f"Daily quota reached: {body['current_usage']}/{body['daily_limit']}")
elif response.status_code == 403:
# Returned when the plan is not Enterprise. The `detail` field explains why.
print(f"Access denied: {response.json().get('detail')}")
else:
print(f"Error {response.status_code}: {response.text}")
# CSV download -- writes the returned attachment to disk.
payload["output_format"] = "csv"
csv_response = requests.post(BULK_URL, json=payload, headers=headers)
if csv_response.status_code == 200:
with open("tariff_rates.csv", "w", encoding="utf-8") as f:
f.write(csv_response.text)
print("Saved to tariff_rates.csv")
JavaScript (Node.js):
const axios = require('axios');
const fs = require('fs');
const API_KEY = 'YOUR_API_KEY';
const BULK_URL = 'https://www.tariffbase.io/api/v1/tariff-rate/bulk/';
// Up to 50 codes per request. Duplicates are deduped server-side,
// and each unique code costs one query against your daily quota.
const basePayload = {
codes: ['0101290010', '0201100010', '0302110000'],
partner: 'China',
country: 'United States',
};
const headers = {
'Authorization': `Token ${API_KEY}`,
'Content-Type': 'application/json',
};
async function bulkTariffLookup() {
try {
const { data } = await axios.post(
BULK_URL,
{ ...basePayload, output_format: 'json' },
{ headers },
);
console.log(`Retrieved ${data.length} rate rows`);
data.forEach(rate => {
console.log(` ${rate.code} ${rate.regime}: ${rate.rate}`);
});
// CSV download -- responseType 'text' so we get the raw CSV body.
const csv = await axios.post(
BULK_URL,
{ ...basePayload, output_format: 'csv' },
{ headers, responseType: 'text' },
);
fs.writeFileSync('tariff_rates.csv', csv.data);
console.log('Saved to tariff_rates.csv');
} catch (error) {
const res = error.response;
if (res?.status === 429 && res.data?.quota_exceeded) {
console.error(`Daily quota reached: ${res.data.current_usage}/${res.data.daily_limit}`);
} else if (res?.status === 403) {
// Non-Enterprise plans cannot access the bulk endpoint.
console.error('Access denied:', res.data?.detail);
} else {
console.error('Error:', res?.data || error.message);
}
}
}
bulkTariffLookup();
[
{
"country": "United States",
"partner": "China",
"code": "0101290010",
"description": "Horses, live, except purebred breeding, n.e.s.o.i.",
"regime": "MFN",
"regime_name": "Most Favored Nation",
"rate": "2.5%"
},
{
"country": "United States",
"partner": "China",
"code": "0201100010",
"description": "Meat of bovine animals, fresh or chilled, carcasses and half-carcasses",
"regime": "MFN",
"regime_name": "Most Favored Nation",
"rate": "26.4%"
}
]
When output_format is set to csv, the response is returned as a downloadable CSV file with columns: country, partner, code, description, regime, regime_name, rate.
Download the full list of HS codes for a given country. Use this endpoint to discover valid codes for use with the Tariff Rate Lookup and Batch Lookup endpoints.
Endpoint:
GET https://www.tariffbase.io/api/v1/nomenclature/
| Parameter | Type | Required | Description |
|---|---|---|---|
country |
string | No | Country name (default: United States). Valid: United States, European Union, China |
output_format |
string | No | json (default) or csv |
tariff_lines_only |
string | No | true (default) returns only tariff-line codes usable in lookups. false returns the full HS hierarchy. |
cURL:
# JSON -- tariff-line codes only
curl -X GET "https://www.tariffbase.io/api/v1/nomenclature/" \
-H "Authorization: Token YOUR_API_KEY" \
-G \
-d "country=United States" \
-d "output_format=json" \
-d "tariff_lines_only=true"
# CSV download
curl -X GET "https://www.tariffbase.io/api/v1/nomenclature/" \
-H "Authorization: Token YOUR_API_KEY" \
-G \
-d "country=United States" \
-d "output_format=csv" \
-d "tariff_lines_only=true" \
-o nomenclature_us.csv
# Download all three countries
for country in "United States" "European Union" "China"; do
curl -X GET "https://www.tariffbase.io/api/v1/nomenclature/" \
-H "Authorization: Token YOUR_API_KEY" \
-G \
-d "country=$country" \
-d "output_format=csv" \
-o "nomenclature_$(echo $country | tr ' ' '_' | tr '[:upper:]' '[:lower:]').csv"
done
Python:
import requests
NOMEN_URL = "https://www.tariffbase.io/api/v1/nomenclature/"
API_KEY = "YOUR_API_KEY"
headers = {
"Authorization": f"Token {API_KEY}",
}
params = {
"country": "United States",
"output_format": "json",
"tariff_lines_only": "true"
}
response = requests.get(NOMEN_URL, headers=headers, params=params)
if response.status_code == 200:
codes = response.json()
print(f"Found {len(codes)} tariff line codes")
for item in codes[:5]:
print(f" {item['code']} - {item['description']}")
else:
print(f"Error {response.status_code}: {response.text}")
# Download as CSV
params["output_format"] = "csv"
response = requests.get(NOMEN_URL, headers=headers, params=params)
if response.status_code == 200:
with open("nomenclature_us.csv", "w") as f:
f.write(response.text)
print("Saved to nomenclature_us.csv")
JavaScript (Node.js):
const axios = require('axios');
const fs = require('fs');
const API_KEY = 'YOUR_API_KEY';
const NOMEN_URL = 'https://www.tariffbase.io/api/v1/nomenclature/';
async function downloadNomenclature() {
try {
const response = await axios.get(NOMEN_URL, {
headers: { 'Authorization': `Token ${API_KEY}` },
params: {
country: 'United States',
output_format: 'json',
tariff_lines_only: 'true'
}
});
console.log(`Found ${response.data.length} tariff line codes`);
response.data.slice(0, 5).forEach(item => {
console.log(` ${item.code} - ${item.description}`);
});
// CSV download
const csvResponse = await axios.get(NOMEN_URL, {
headers: { 'Authorization': `Token ${API_KEY}` },
params: {
country: 'United States',
output_format: 'csv',
tariff_lines_only: 'true'
}
});
fs.writeFileSync('nomenclature_us.csv', csvResponse.data);
console.log('Saved to nomenclature_us.csv');
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
downloadNomenclature();
[
{
"country": "United States",
"key": "0101210010",
"nomen_code": "0101.21.00.10",
"indent": 4,
"description": "Purebred breeding horses",
"tl_flag": true,
"code": "0101210010"
},
{
"country": "United States",
"key": "0101290010",
"nomen_code": "0101.29.00.10",
"indent": 4,
"description": "Horses, live, except purebred breeding, n.e.s.o.i.",
"tl_flag": true,
"code": "0101290010"
}
]
| Field | Type | Description |
|---|---|---|
country |
string | The querying country |
key |
string | Unique key for the nomenclature entry |
nomen_code |
string | Formatted HS code with dot separators (e.g., 0101.29.00.10) |
indent |
integer | Indentation level in the HS hierarchy |
description |
string | Product description |
tl_flag |
boolean | true if the code is a tariff line usable in rate lookups |
code |
string | HS product code usable with the Tariff Rate Lookup endpoint |
When output_format is set to csv, the response is returned as a downloadable CSV file with the same fields as the JSON response.
Two independent limits apply to every authenticated request: a request throttle (per-minute and per-day) that depends on your subscription family, and a daily query quota set by your specific plan. Either limit can return a 429 Too Many Requests response.
| Plan | Throttle |
|---|---|
| Professional | 10 requests per minute, 1,000 requests per day |
| Enterprise | 100 requests per minute, 50,000 requests per day |
When the throttle is exceeded, the API returns 429 with a Retry-After header indicating how many seconds to wait before retrying.
In addition to the throttle above, each plan has a daily_query_limit that caps the total number of queries per 24-hour window. Key points:
429 with a JSON body containing quota_exceeded: true -- see the Error Handling section below.For applications that need to make frequent queries:
429 response, honor the Retry-After header and wait progressively longer between retries.quota_exceeded on 429 responses -- if the daily quota is exhausted, retrying before 00:00 UTC will not help. Defer work or upgrade the plan.| Status Code | Description |
|---|---|
200 |
OK -- Request successful |
400 |
Bad Request -- Missing or invalid request parameters |
401 |
Unauthorized -- Invalid or missing API key |
403 |
Forbidden -- Your subscription does not include access to this endpoint |
404 |
Not Found -- No tariff rates found for the given parameters |
429 |
Too Many Requests -- Rate limit or daily query quota exceeded |
500 |
Internal Server Error -- Contact support if this persists |
Missing Parameters (400):
{
"error": "Missing 'code' or 'partner' parameter."
}
Authentication Error (401):
{
"detail": "Authentication credentials were not provided."
}
No API Access on Current Plan (403):
{
"detail": "Your current plan does not include API access. Please upgrade to a plan that includes the API."
}
Enterprise Required (403):
Returned by the Batch Lookup and Nomenclature Download endpoints when the caller does not have an Enterprise subscription:
{
"detail": "This endpoint is available on Enterprise plans only. Please upgrade your subscription to access batch API and CSV exports."
}
No Data Found (404):
{
"error": "No tariff rates found"
}
Rate Limit Exceeded (429):
Returned when the per-minute or per-day throttle is exceeded. Includes a Retry-After header.
{
"detail": "Request was throttled. Expected available in 60 seconds."
}
Daily Quota Exceeded (429):
Returned when your plan's daily query limit is reached. The counter is shared across all TariffBase apps (web search, HS classifier, API) and resets at 00:00 UTC. The Batch Lookup endpoint charges one query per unique HS code in the request.
{
"error": "Daily query limit reached (1000/day). Try again tomorrow or upgrade your plan.",
"quota_exceeded": true,
"current_usage": 1000,
"daily_limit": 1000
}