Documentation v1.0.1

Tariff API

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.


Getting Started

1. Obtain Your API Key

  1. Navigate to API in the left sidebar of your dashboard.
  2. Your unique API Key is displayed on the page.
  3. Copy the key and store it securely.

Security: Treat your API key like a password. Do not expose it in client-side code, public repositories, or shared documents.

2. Authentication

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.

Security Best Practices

  • Never expose your API key in client-side code
  • Store your API key securely in environment variables
  • Use HTTPS for all API requests
  • Rotate your API key regularly

API Reference

Tariff Rate Lookup

Retrieve tariff rates for a specific product code and trading partner.

Plan: Professional, Enterprise

Endpoint:

GET https://www.tariffbase.io/api/v1/tariff-rate/

Query Parameters

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)

Supported Querying Countries

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.

Example Requests

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();

Example Response

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%"
    }
]

Response Fields

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

Enterprise Batch API

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 Forbidden response.

Batch Tariff Rate Lookup

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/

Request Body (JSON)

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

Example Requests

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();

Example Response (JSON)

[
    {
        "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%"
    }
]

CSV Response

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.


Nomenclature Download (HS Code List)

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/

Query Parameters

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.

Example Requests

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();

Example Response (JSON)

[
    {
        "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"
    }
]

Nomenclature Response Fields

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

CSV Response

When output_format is set to csv, the response is returned as a downloadable CSV file with the same fields as the JSON response.


Rate Limits

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.

Request Throttles

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.

Daily Query Quota

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:

  • The counter is shared across all TariffBase products -- web search, HS classifier, and the API all draw from the same daily pool.
  • The counter resets at 00:00 UTC.
  • The Batch Lookup endpoint charges one query per unique HS code in the request; duplicates are only charged once.
  • Exceeding this quota returns 429 with a JSON body containing quota_exceeded: true -- see the Error Handling section below.

Handling Rate Limits

For applications that need to make frequent queries:

  • Cache responses for tariff codes you look up repeatedly. Tariff rates change infrequently (typically weekly or monthly).
  • Implement exponential backoff -- if you receive a throttled 429 response, honor the Retry-After header and wait progressively longer between retries.
  • Check 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.
  • Use the Batch endpoint (Enterprise) to look up multiple codes in a single request instead of making individual calls.

Error Handling

HTTP Status Codes

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

Common Error Responses

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
}

Integration Best Practices

  • Cache aggressively. Tariff rates for a given code-country-partner combination are typically stable for weeks or months. Cache responses and refresh periodically rather than querying on every transaction.
  • Use specific HS codes. Querying a 4-digit heading may return multiple entries. Use the most specific code available (6-digit or national level) for precise results.
  • Use the Nomenclature endpoint first. Enterprise subscribers should download the HS code list to discover valid codes before making bulk lookups.
  • Prefer batch over single lookups. Enterprise subscribers can reduce API calls and simplify integration by sending up to 50 codes per batch request.
  • Handle errors gracefully. Always check the HTTP status code before processing the response body. Implement retry logic for transient errors (429, 500).
  • Log API usage. Keep records of queries for audit and troubleshooting purposes.
  • Secure your token. Store the API key in environment variables or a secrets manager -- never hardcode it in your application source code.