HTS Classification API for Logistics Software Integration (2026)

htsapi.dev gives logistics software a single REST endpoint that returns HTS codes (to 10 digits when the facts support it), Census Bureau figures for duty actually collected on past imports, and CBP ruling citations. No SDK, no enterprise contract, no six-month integration project.

Last updated: April 2026

Why Logistics Platforms Need Embedded HTS Classification

Every logistics platform that touches US imports needs HTS codes. Transportation management systems need them for landed-cost calculations. Warehouse management systems need them for inventory compliance. Customs filing software needs them on every entry. Freight forwarders need them to quote duties before goods ship.

Manual HTS lookup does not scale. A 3PL handling 50 clients with 500 SKUs each is looking at 25,000 products that need classification. Each product requires searching the USITC tariff schedule, cross-referencing CBP rulings, and calculating effective duty rates that include Section 301/232 surcharges. That is weeks of work per catalog refresh.

The alternative is embedding classification directly into your software. When a new product enters your system, classify it programmatically. When tariff rates change, reclassify affected SKUs. When a customer asks what duties to expect, answer from data instead of saying "we'll get back to you."

How htsapi.dev Integrates with Your Software

The integration is a single HTTP POST. Your application sends a product description and country of origin. The API returns the HTS code, duty figures, rationale, and supporting evidence. No SDK to install, no WSDL to parse, no client library to maintain.

Your TMS / WMS / Filing Software
↓ POST /v1/classify
htsapi.dev
↓ JSON response
HTS code + duty rate + ruling citation

The request takes four fields:

# One call - that's the entire integration
curl -X POST https://htsapi.dev/v1/classify \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{
    "description": "lithium-ion battery pack 48V for electric forklift",
    "country_of_origin": "China",
    "material": "lithium-ion cells, steel casing",
    "category": "industrial battery"
  }'

Any language that can make an HTTP request works: Python, Node.js, Java, Go, C#, PHP, Ruby. The response is JSON. Parse it, store the HTS code and duty figures, and route anything below high confidence to a reviewer.

API Response: What You Get

Every classification response includes:

{
  "confident_to": "8507.60",
  "candidates": [
    {
      "hts_code": "8507.60.00.20",
      "description": "Lithium-ion storage batteries",
      "general_duty": "3.4%",
      "confidence": "high",
      "rationale": "Classified under heading 8507 covering electric accumulators. Subheading 8507.60 specifically covers lithium-ion batteries. GRI 1 applies: the terms of the heading are definitive for this product.",
      "rulings": [
        {
          "ruling_number": "N331847",
          "subject": "The tariff classification of lithium-ion battery packs from China",
          "source_url": "https://rulings.cbp.gov/ruling/N331847"
        }
      ],
      "census_duties": {
        "country": "CHINA",
        "period": "2025-06..2026-05",
        "total_effective_rate_pct": 28.4,
        "total_import_value_usd": 89200000,
        "total_duty_collected_usd": 25332800,
        "breakdown": [
          { "rp_code": "61", "rp_label": "Dutiable at the General (MFN) rate", "effective_rate_pct": 3.4 },
          { "rp_code": "69", "rp_label": "Dutiable under HTS chapter 99 (e.g. Section 301, 232), duty reported", "effective_rate_pct": 25.0 }
        ],
        "aggregate_import_value_usd": 312500000
      },
      "legal_notes": "--- SECTION XVI ---\n  Notes\n1 This section does not cover..."
    }
  ],
  "clarification": null
}

Key fields for logistics integration:

Batch Classification for Product Catalogs

Most logistics software needs to classify entire product catalogs, not one item at a time. Loop through your catalog, call the API for each product (there is no batch endpoint), and store the results. The rate limit is 10 requests per minute per API key.

import requests
import time
import json

API_KEY = "YOUR_API_KEY"
ENDPOINT = "https://htsapi.dev/v1/classify"

# Your product catalog - from database, CSV, ERP export, etc.
products = [
    {"sku": "FLT-4800", "desc": "lithium-ion battery 48V forklift", "origin": "China"},
    {"sku": "PPE-VEST-HV", "desc": "high-visibility safety vest polyester", "origin": "Vietnam"},
    {"sku": "CONV-BELT-10", "desc": "rubber conveyor belt 10m industrial", "origin": "Germany"},
    # ... thousands more
]

results = []
for i, product in enumerate(products):
    try:
        resp = requests.post(ENDPOINT,
            headers={"X-API-Key": API_KEY},
            json={
                "description": product["desc"],
                "country_of_origin": product["origin"]
            },
            timeout=90
        )

        if resp.status_code == 429:
            # Rate limited - wait and retry
            time.sleep(10)
            resp = requests.post(ENDPOINT,
                headers={"X-API-Key": API_KEY},
                json={"description": product["desc"], "country_of_origin": product["origin"]},
                timeout=90
            )

        data = resp.json()
        top = data["candidates"][0]
        results.append({
            "sku": product["sku"],
            "hts_code": top["hts_code"],
            "confidence": top["confidence"],
            "duty_rate": (top.get("census_duties") or {}).get("total_effective_rate_pct"),
            "rationale": top["rationale"]
        })

        # Progress
        print(f"[{i+1}/{len(products)}] {product['sku']}: {top['hts_code']} ({top['confidence']})")

        # Respect rate limit: 10/min = 1 every 6 seconds
        time.sleep(6)

    except Exception as e:
        print(f"ERROR {product['sku']}: {e}")
        results.append({"sku": product["sku"], "error": str(e)})

# Save results
with open("classified_catalog.json", "w") as f:
    json.dump(results, f, indent=2)

print(f"\nDone. {len([r for r in results if 'hts_code' in r])}/{len(products)} classified.")
Tip: Each call takes 15-35 seconds, plus the 6-second pause, so this loop runs a 5,000-SKU catalog in about 30-60 hours sequentially. Run it as a background job and save results as you go.

Duty Figures from Census Data

Getting the HTS code is only half the problem. Logistics software also needs to answer: what duty should the importer expect?

The statutory duty rate in the HTS schedule is just the starting point. Real-world duty depends on the country of origin and which additional tariff provisions apply. For lithium-ion batteries (8507.60.00) from China, on 2026-10-03:

The census_duties field on each candidate provides this breakdown when Census has data for the subheading. It comes from US Census Bureau import data: duties actually collected divided by dutiable value, per country: what importers paid in the latest published month (the 10-digit line when there is enough trade, else the 6-digit subheading), last 3 months in recent_months, and the 12-month 6-digit average. Past imports, not the duty a particular shipment will owe.

The rate provision breakdown shows each component:

RP CodeLabelWhat It Covers
61Dutiable at the General (MFN) rateStandard Most Favored Nation duty
69Dutiable under HTS chapter 99Section 301, Section 232, reciprocal and other additional duties
64Dutiable at a Special (preferential) rateEntries at a reduced FTA or program rate
10-19FreeEntries free under the general or special column, other legislation, or Chapter 99
00Bonded warehouse or FTZDuty not applicable

This gives logistics software a duty estimate grounded in what CBP actually collected, not a rate table that ignores Section 301. It is still an estimate from historical averages; it does not calculate the duty for a particular shipment.

Compared to Enterprise Solutions

Enterprise trade management platforms like E2open, Descartes, and Thomson Reuters ONESOURCE offer HTS classification as part of broader suites. If you need a full global trade management platform with denied-party screening, license management, and multi-country compliance, those platforms make sense. If you need HTS classification embedded in your existing software, the comparison looks different.

Criteriahtsapi.devE2open / Descartes / Thomson Reuters
Setup timeMinutes. Get API key, make first call.Weeks to months. Sales process, SOW, implementation project.
PricingPay per call. $10 for 100 credits ($0.10/call) or $50 for 1,000 credits ($0.05/call).Enterprise license. $50K-$500K+/year typical.
Integration1 REST endpoint. JSON in, JSON out.SDK, SOAP/XML, or custom connector. Often requires middleware.
Data freshnessHTS schedule and CBP rulings weekly; Census figures cover the latest 3 published months and a 12-month average (about two months behind).Varies. Some update quarterly or on request.
US tariff depthDeep. 10-digit HTS, 220K+ rulings, Census duty-collected figures including Section 301/232.Broad. Global coverage but US-specific detail varies.
CoverageUS HTS only (HS6 maps internationally via WCO system).Multi-country tariff schedules.
Minimum commitmentNone. Start with 100 credits ($10), try it.Annual contract, often multi-year.
SupportEmail, developer docs, API reference.Dedicated account team, professional services.
Bottom line: If your logistics software needs US HTS classification embedded as a feature, htsapi.dev gets you there in an afternoon. If you need a full global trade management suite, evaluate the enterprise platforms.

Integration Patterns

Logistics software integrates HTS classification in four common patterns. Choose based on your workflow.

1. Classify on new product (your webhook handler)

When a new SKU enters your system (from ERP sync, catalog upload, or manual entry), have your own webhook or event handler call /v1/classify and stores the result. The HTS code is ready before anyone needs it.

# Webhook handler - triggered when new product is created
def on_new_product(product):
    resp = requests.post("https://htsapi.dev/v1/classify",
        headers={"X-API-Key": API_KEY},
        json={
            "description": product.description,
            "country_of_origin": product.origin_country
        })
    data = resp.json()
    top = data["candidates"][0]

    product.hts_code = top["hts_code"]
    product.duty_rate = (top.get("census_duties") or {}).get("total_effective_rate_pct")
    product.classification_confidence = top["confidence"]
    product.save()

2. Scheduled batch reclassification

Run a nightly or weekly job that reclassifies products whose HTS codes are older than 90 days, or when tariff rates change. This catches products affected by new trade actions.

3. On-demand at customs filing

When preparing a customs entry, classify (or verify an existing classification). Show the agent the HTS code, confidence level, and ruling citation. If confidence is low, flag for manual review before filing.

4. E-commerce integration

For Shopify, WooCommerce, or custom storefronts that ship internationally: classifying takes 15-35 seconds, so do it ahead of checkout. Use the new-product pattern to pre-classify on product creation, then look up stored codes and Census figures at checkout for a duty estimate.

Getting Started

Three steps to embed HTS classification in your logistics software.

1. Get an API key

Buy a credit pack. $10 for 100 credits or $50 for 1,000 credits. Each /v1/classify call costs 1 credit. All other endpoints (HTS search, rulings, status) are free with a key.

2. Test with curl

curl -X POST https://htsapi.dev/v1/classify \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"description": "corrugated cardboard shipping boxes", "country_of_origin": "Canada"}'

3. Integrate into your application

import requests

def classify_product(description, country):
    """Classify a product and return HTS code + duty rate."""
    resp = requests.post(
        "https://htsapi.dev/v1/classify",
        headers={"X-API-Key": "YOUR_API_KEY"},
        json={"description": description, "country_of_origin": country}
    )
    resp.raise_for_status()
    data = resp.json()
    top = data["candidates"][0]
    return {
        "hts_code": top["hts_code"],
        "duty_rate_pct": (top.get("census_duties") or {}).get("total_effective_rate_pct"),
        "confidence": top["confidence"],
        "ruling": top["rulings"][0]["ruling_number"] if top["rulings"] else None
    }

# Use in your TMS/WMS
result = classify_product("stainless steel pallet racking 3-tier", "Mexico")
print(result)
# {'hts_code': '7326.90.86.88', 'duty_rate_pct': 0.0, 'confidence': 'high', 'ruling': 'N298431'}

For full integration details, error handling, and all available endpoints, see the Developer Integration Guide.

Ready to integrate? Get an API key and classify your first product in under 5 minutes. Questions? [email protected]

Frequently Asked Questions

How fast is the API?

A classification typically takes 15-35 seconds, sometimes up to about 60. An AI agent searches the current USITC schedule and over 220,000 CBP rulings, reads rulings and legal notes, and applies GRI analysis; products that need more of that take longer. The API processes one product per call, so for catalogs, factor in the 10 requests/minute rate limit.

Can I classify products in bulk?

Yes, one call per product: there is no batch endpoint. Loop through your product catalog and call /v1/classify for each item. Each call takes 15-35 seconds, so one at a time a 10,000-SKU catalog takes about 60-115 hours; the rate limit of 10 requests per minute allows a few calls in parallel. The Python example above includes rate-limit handling and progress tracking.

Do you support non-US tariff schedules?

Currently the API covers the US Harmonized Tariff Schedule only. Classifications go down to 10-digit US HTS codes when the facts support it. The first 6 digits follow the WCO Harmonized System used by 200+ countries, so they map internationally. Country-specific subdivisions beyond HS6 are US-only.

How often is the tariff data updated?

The USITC HTS schedule and our copy of the CBP rulings are refreshed weekly. Census Bureau duty figures are the latest 3 months Census has published, about two months behind, with a 12-month average. Check GET /v1/status for HTS and rulings freshness timestamps.

What about uptime and SLA?

There is no SLA or uptime guarantee. The GET /v1/status endpoint reports data freshness for the HTS schedule and CBP rulings. Questions: contact us.

Related guides