Skip to the content

Lookups

Classify one product and read the result - the lookup object, the recommended code, the other candidates, the reasons, the sources and what is still missing.

A lookup is one product description classified against one tariff schedule. It is created by POST /api/classify, runs in the background (Asynchronous work) and ends with a proposed code, a request for more information, or a request for review. A result is a suggestion for reference, not a classification decision by a customs authority.

The lookup object

Lists, and POST /api/lookups/{lookup_id}/resolve, return the summary fields. Classify, get, rerun and the decision return the summary fields and the detail fields.

Summary fields:

Field Type Meaning
id string The id of the lookup
created_at string When it was created, ISO 8601, UTC
kind string single, batch for a row of a batch, or sku for a lookup made from the catalog
batch_id, row_index string, integer, or null The batch and the row it belongs to
parent_lookup_id string or null The lookup this one reruns
description string The product description that was sent
market string The import market: US, EU or VN (Tariff data)
dataset_version string The version of the tariff schedule it was classified against
status string queued, processing, proposed, needs_review, needs_info or error
status_label string The status, in the language of the reader
recommended_code string or null The proposed code, formatted as the schedule writes it
recommended_description string or null The official description of that line, with its parents
hs6 string or null The first six digits
confidence number From 0 to 1
review_flags array Why a person should look: each entry has a code and a message in the language of the reader
risk, risk_level integer, string A score computed from the status, the confidence and the flags, and high, medium or low. sort=risk orders by it
resolved boolean Taken out of the review queue
processing_ms integer How long the classification took
decision, decision_label string or null The reviewer's decision: approved, overridden or rejected
final_code, decided_at string or null The code the decision settled on, and when
created_by, created_by_name string or null The account that created it
sku_id integer or null The SKU of the catalog it belongs to
language string or null The answer language (Languages)
comment_count integer or null Comments on the lookup

Detail fields:

Field Type Meaning
input object The fields that were sent: description, material, use, composition, origin, notes, market
origin_label string or null The country of origin, named in the language of the reader
normalized object The description as it was read: the cleaned text, its language, the category, materials and other attributes, and what is missing
result object The full answer, see below. Empty until the lookup is finished
missing_info array What the description leaves open, in the answer language
error string or null The message of a lookup that ended in error
final_description, review_note, decided_by_name string or null The reviewer's decision in words
events array The history: created, rerun, decisions, comments, each with who, when and a note
progress object or null The current stage while processing, otherwise null

The parts of result an integration reads most:

Field Meaning
recommended The proposed line: code, description, full_description, duty_rate, reasoning, citations, a duty estimate basis
alternatives The other candidates, with the same fields as recommended, among them verdict and exclusion_reason
summary, deciding_factors, uncertainties The reasoning in words, in the answer language
questions Questions that would decide between candidates, with their options. Answer them with a rerun
flags The same entries as review_flags
sources What the answer cites: each with a key (as used in citations), url, title and snippet
checks The automatic checks that ran on the answer, each ok or not
legal The legal findings, in the answer language
dataset The tariff schedule and version used
disclaimer The statement that the result is a suggestion, in the language of the reader

result has more fields than these (scores, timings, ranking detail); see the example answer.

Classify a product

POST /api/classify

Changes data in your account when executed. Creates a lookup with the status queued and classifies it in the background. Read GET /api/lookups/{lookup_id} until the status is no longer queued or processing. Spends credits.

Request body (application/json)

Name Type Required Description
description string Yes Product description. Up to 2000 characters
material string No Up to 500 characters
use string No Up to 500 characters
composition string No Up to 500 characters
origin string No Up to 100 characters
notes string No Other additional information. Up to 1000 characters
market string No Import market: US, EU or VN. Up to 8 characters
tariff_version string or null No Up to 64 characters
sku_id integer or null No Link the result to a SKU in the catalog
language string or null No Language the answer is written in: the reasons and explanations, the questions about missing information with their options, the legal findings and the warnings. A tag with a region is read by its primary subtag (en-US is en, ko-KR is ko), in any case. Without it: the language of the request (Accept-Language). Review flags, status labels and the other responses are not affected: they follow Accept-Language. Up to 35 characters

Returns 202 with LookupDetail.

Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.

Try it in the explorer

Only description is required. origin takes a country code from GET /api/countries. Without market, the default market of the service is used; without tariff_version, the active version of that market.

POST /api/classify
curl -X POST "https://htspilot.com/api/classify" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{
  "description": "Men'\''s T-shirt, knitted, 100% cotton, short sleeves, crew neck",
  "material": "cotton",
  "use": "apparel",
  "composition": "100% cotton",
  "origin": "VN",
  "notes": "",
  "market": "US",
  "language": "en"
}'
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://htspilot.com/api/classify",
    data=json.dumps({
        "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
        "material": "cotton",
        "use": "apparel",
        "composition": "100% cotton",
        "origin": "VN",
        "notes": "",
        "market": "US",
        "language": "en",
    }).encode(),
    headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))
const response = await fetch("https://htspilot.com/api/classify", {
  method: "POST",
  headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "material": "cotton",
    "use": "apparel",
    "composition": "100% cotton",
    "origin": "VN",
    "notes": "",
    "market": "US",
    "language": "en"
  }),
});
console.log(await response.json());
Response 202
{
  "id": "bcb6a35ae2694828b191f78ed704a9a9",
  "created_at": "2026-10-03T16:07:51.322570",
  "kind": "single",
  "batch_id": null,
  "row_index": null,
  "parent_lookup_id": null,
  "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
  "market": "US",
  "dataset_version": "2026-SAMPLE",
  "status": "queued",
  "status_label": "New – queued",
  "recommended_code": null,
  "recommended_description": null,
  "hs6": null,
  "confidence": 0,
  "review_flags": [],
  "risk": 0,
  "risk_level": "low",
  "resolved": false,
  "processing_ms": 0,
  "decision": null,
  "decision_label": null,
  "final_code": null,
  "decided_at": null,
  "created_by": "d10db811d389470a8210b8210c023289",
  "created_by_name": "Administrator",
  "sku_id": null,
  "language": "en",
  "comment_count": 0,
  "input": {
    "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "material": "cotton",
    "use": "apparel",
    "composition": "100% cotton",
    "origin": "VN",
    "market": "US"
  },
  "origin_label": "Vietnam (VN)",
  "normalized": {},
  "result": {},
  "missing_info": [],
  "error": null,
  "final_description": null,
  "review_note": null,
  "decided_by_name": null,
  "events": [],
  "progress": null
}

Get a lookup

GET /api/lookups/{lookup_id}

Path parameters

Name Type Description
lookup_id string -

Returns 200 with LookupDetail.

Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.

Try it in the explorer

GET /api/lookups/{lookup_id}
curl "https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9",
    headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
    method="GET",
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))
const response = await fetch("https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9", {
  headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());
Response 200
{
  "id": "bcb6a35ae2694828b191f78ed704a9a9",
  "created_at": "2026-10-03T16:07:51.322570",
  "kind": "single",
  "batch_id": null,
  "row_index": null,
  "parent_lookup_id": null,
  "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
  "market": "US",
  "dataset_version": "2026-SAMPLE",
  "status": "proposed",
  "status_label": "Proposed",
  "recommended_code": "6109.10.00.14",
  "recommended_description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > Other T-shirts",
  "hs6": "610910",
  "confidence": 0.75,
  "review_flags": [
    {
      "code": "no_official_evidence",
      "message": "No official source confirms the proposed code"
    },
    {
      "code": "demo_data",
      "message": "Tariff data is incomplete"
    }
  ],
  "risk": 18,
  "risk_level": "low",
  "resolved": true,
  "processing_ms": 41,
  "decision": null,
  "decision_label": null,
  "final_code": null,
  "decided_at": null,
  "created_by": "d10db811d389470a8210b8210c023289",
  "created_by_name": "Administrator",
  "sku_id": null,
  "language": "en",
  "comment_count": 0,
  "input": {
    "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "material": "cotton",
    "use": "apparel",
    "composition": "100% cotton",
    "origin": "VN",
    "market": "US"
  },
  "origin_label": "Vietnam (VN)",
  "normalized": {
    "raw_description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "clean_description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "search_text": "men's t-shirt, knitted, 100% cotton, short sleeves, crew neck cotton 100% cotton apparel t-shirts",
    "language": "en",
    "category": "apparel",
    "materials": [
      {
        "name": "cotton",
        "group": "textile",
        "percent": 100
      }
    ],
    "construction": "knitted",
    "gender": "men",
    "state": null,
    "electrical": false,
    "extra": {
      "material": "cotton",
      "use": "apparel",
      "composition": "100% cotton",
      "origin": "VN"
    },
    "missing": [],
    "flags": [],
    "product_type": null,
    "function": null,
    "search_terms": [],
    "extraction": {
      "method": "rules"
    },
    "hs_headings": [],
    "abbreviations": {},
    "translation": null,
    "material_groups": [
      "textile"
    ]
  },
  "result": {
    "status": "proposed",
    "status_label": "Proposed",
    "lang": "en",
    "recommended": {
      "code": "6109.10.00.14",
      "code_digits": "6109100014",
      "hs6": "610910",
      "hs6_display": "6109.10",
      "national_extension": "0014",
      "description": "Other T-shirts",
      "full_description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > Other T-shirts",
      "duty_rate": "16.5%",
      "retrieval_score": 0.9223,
      "scores": {
        "bm25": 11.6074,
        "vector": 0.4017,
        "rrf": 0.03226,
        "overlap": 0.5,
        "leaf_overlap": 1,
        "attributes": 0.8,
        "tree": 1,
        "cross": 0,
        "final": 0.9223,
        "legal": 0
      },
      "verdict": "recommended",
      "reasoning": "Tariff line: “Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > Other T-shirts”. Matches: heading usually used for 'apparel' products; matches main material: cotton; matches construction: knitted; matches intended user: men.",
      "exclusion_reason": "",
      "citations": [
        "W1",
        "N1"
      ],
      "signals": [
        "heading usually used for 'apparel' products",
        "matches main material: cotton"
      ],
      "legal": {
        "status": "ok",
        "penalty": 0,
        "findings": []
      },
      "precedents": [],
      "duty": {
        "available": true,
        "rate_text": "16.5%",
        "rate_basis": "general",
        "effective_pct": 16.5,
        "max_pct": 16.5,
        "additional_pct": 0,
        "additional": [],
        "may_apply": [],
        "specific": false,
        "currency": "USD"
      }
    },
    "tentative": false,
    "alternatives": [
      {
        "code": "6109.10.00.12",
        "code_digits": "6109100012",
        "hs6": "610910",
        "hs6_display": "6109.10",
        "national_extension": "0012",
        "description": "T-shirts, all white, short hemmed sleeves, hemmed bottom, crew or round neckline, or V-neck, without pockets, trim or embroidery",
        "full_description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > T-shirts, all white, short hemmed sleeves, hemmed bottom, crew or round neckline, or V-neck, without pockets, trim or embroidery",
        "duty_rate": "16.5%",
        "retrieval_score": 0.8596,
        "scores": {
          "bm25": 22.6626,
          "vector": 0.4315,
          "rrf": 0.03279,
          "overlap": 0.9,
          "leaf_overlap": 0.357,
          "attributes": 0.8,
          "tree": 1,
          "cross": 0,
          "final": 0.8596,
          "legal": 0
        },
        "verdict": "possible",
        "reasoning": "Tariff line: “nglets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > T-shirts, all white, short hemmed sleeves, hemmed bottom, crew or round neckline, or V-neck, without pockets, trim or embroidery”. Matches: heading usually used for 'apparel' products; matches main material: cotton; matches construction: knitted; matches intended user: men.",
        "exclusion_reason": "Same HS6 subheading, but the national line matches the details (user/style) less well than the top candidate.",
        "citations": [
          "W2",
          "N1"
        ],
        "signals": [
          "heading usually used for 'apparel' products",
          "matches main material: cotton"
        ],
        "legal": {
          "status": "ok",
          "penalty": 0,
          "findings": []
        },
        "precedents": [],
        "duty": {
          "available": true,
          "rate_text": "16.5%",
          "rate_basis": "general",
          "effective_pct": 16.5,
          "max_pct": 16.5,
          "additional_pct": 0,
          "additional": [],
          "may_apply": [],
          "specific": false,
          "currency": "USD"
        }
      },
      {
        "code": "6110.20.20.20",
        "code_digits": "6110202020",
        "hs6": "611020",
        "hs6_display": "6110.20",
        "national_extension": "2020",
        "description": "Men's or boys' sweatshirts of cotton",
        "full_description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > Sweaters, pullovers, sweatshirts, waistcoats (vests) and similar articles, knitted or crocheted > Of cotton > Men's or boys' sweatshirts of cotton",
        "duty_rate": "",
        "retrieval_score": 0.8095,
        "scores": {
          "bm25": 8.2297,
          "vector": 0.3145,
          "rrf": 0.02986,
          "overlap": 0.4,
          "leaf_overlap": 0.5,
          "attributes": 0.88,
          "tree": 0.9171,
          "cross": 0,
          "final": 0.8095,
          "legal": 0
        },
        "verdict": "possible",
        "reasoning": "Tariff line: “ 61: Articles of apparel and clothing accessories, knitted or crocheted > Sweaters, pullovers, sweatshirts, waistcoats (vests) and similar articles, knitted or crocheted > Of cotton > Men's or boys' sweatshirts of cotton”. Matches: heading usually used for 'apparel' products; matches main material: cotton; matches construction: knitted; matches intended user: men.",
        "exclusion_reason": "Different HS subheading 611020; matches the description less well than the top candidate.",
        "citations": [
          "W3",
          "N1"
        ],
        "signals": [
          "heading usually used for 'apparel' products",
          "matches main material: cotton"
        ],
        "legal": {
          "status": "ok",
          "penalty": 0,
          "findings": []
        },
        "precedents": [],
        "duty": {
          "available": false,
          "rate_text": ""
        }
      }
    ],
    "confidence": 0.75,
    "flags": [
      {
        "code": "no_official_evidence",
        "message": "No official source confirms the proposed code"
      },
      {
        "code": "demo_data",
        "message": "Tariff data is incomplete"
      }
    ],
    "uncertainties": [],
    "missing_info": [],
    "questions": [],
    "summary": "Proposed 6109.10.00.14 based on how well the description and attributes match.",
    "deciding_factors": [
      "6109.10.00.14: heading usually used for 'apparel' products",
      "6109.10.00.14: matches main material: cotton"
    ],
    "duty": {
      "origin": "VN",
      "country": "VN",
      "codes_compared": 2,
      "min_pct": 16.5,
      "max_pct": 16.5,
      "spread_pp": 0
    },
    "raw_confidence": 0.75,
    "sources": [
      {
        "key": "W1",
        "url": "https://hts.usitc.gov/",
        "title": "Loaded tariff data – US 2026-SAMPLE – 6109.10.00.14",
        "publisher": "Mô phỏng theo cấu trúc bản xuất JSON của USITC (hts.usitc.gov). Dòng thuế 8–10 số và mô tả được rút gọn/minh họa.",
        "snippet": "6109.10.00.14: Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > Other T-shirts",
        "accessed_at": "2026-10-03T16:07:51.362411+00:00",
        "is_official": false,
        "is_demo": true,
        "provider": "tariff_data",
        "related_codes": [
          "6109100014"
        ]
      },
      {
        "key": "W2",
        "url": "https://hts.usitc.gov/",
        "title": "Loaded tariff data – US 2026-SAMPLE – 6109.10.00.12",
        "publisher": "Mô phỏng theo cấu trúc bản xuất JSON của USITC (hts.usitc.gov). Dòng thuế 8–10 số và mô tả được rút gọn/minh họa.",
        "snippet": "6109.10.00.12: Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > T-shirts, all white, short hemmed sleeves, hemmed bottom, crew or round neckline, or V-neck, without pockets, trim or embroidery",
        "accessed_at": "2026-10-03T16:07:51.362411+00:00",
        "is_official": false,
        "is_demo": true,
        "provider": "tariff_data",
        "related_codes": [
          "6109100012"
        ]
      }
    ],
    "precedents": [],
    "legal": {
      "guidance": [
        {
          "rule": "gri6-same-level",
          "effect": "guidance",
          "ref": "GRI 6",
          "note_ref": "GRI6",
          "params": {
            "dominant": "cotton",
            "percent": "100"
          },
          "message": "Subheadings are compared only with subheadings at the same level, by their terms and the related notes."
        }
      ],
      "excluded": [
        {
          "code": "6205202046",
          "code_display": "6205.20.20.46",
          "findings": [
            {
              "rule": "ch62-not-knitted",
              "effect": "exclude",
              "ref": "HS Chapter 62, Note 1",
              "note_ref": "62",
              "params": {
                "dominant": "cotton",
                "percent": "100"
              },
              "message": "Chapter 62 excludes knitted or crocheted articles (other than those of heading 62.12); the product is knitted."
            }
          ]
        },
        {
          "code": "6205202016",
          "code_display": "6205.20.20.16",
          "findings": [
            {
              "rule": "ch62-not-knitted",
              "effect": "exclude",
              "ref": "HS Chapter 62, Note 1",
              "note_ref": "62",
              "params": {
                "dominant": "cotton",
                "percent": "100"
              },
              "message": "Chapter 62 excludes knitted or crocheted articles (other than those of heading 62.12); the product is knitted."
            }
          ]
        }
      ],
      "rules_fired": [
        "gender_line",
        "ch62-not-knitted"
      ]
    },
    "pipeline": {
      "understanding": {
        "method": "rules"
      },
      "translation": null,
      "sufficient_info": true,
      "early_exit": false,
      "tree": {
        "chapters": [
          {
            "code": "61",
            "title": "Articles of apparel and clothing accessories, knitted or crocheted",
            "score": 1.15
          },
          {
            "code": "62",
            "title": "Articles of apparel and clothing accessories, not knitted or crocheted",
            "score": 1.087
          }
        ],
        "headings": [
          {
            "code": "6109",
            "title": "T-shirts, singlets, tank tops and similar garments, knitted or crocheted",
            "score": 1.15
          },
          {
            "code": "6205",
            "title": "Men's or boys' shirts (not knitted or crocheted)",
            "score": 1.087
          }
        ],
        "hs6": 26,
        "leaves": 43,
        "widened": false
      },
      "retrievers": {
        "bm25": 24,
        "vector": 40,
        "cross": 0,
        "precedents": 0
      },
      "reranker": "default",
      "calibrated": false,
      "pool": 32,
      "legal_excluded": 5,
      "shortlist": null,
      "top_k": 16,
      "top_k_codes": [
        "6109100014",
        "6109100012"
      ],
      "line_select": null,
      "national_line": null
    },
    "ranking": {
      "model": "default",
      "candidates": [
        {
          "code": "6109100014",
          "hs6": "610910",
          "features": {
            "rrf": 0.9839,
            "bm25": 0.5122,
            "vector": 0.4017,
            "overlap": 0.5,
            "leaf_overlap": 1,
            "attributes": 0.8,
            "tree": 1,
            "cross": 0,
            "legal": 0,
            "xrerank": 0
          }
        },
        {
          "code": "6109100012",
          "hs6": "610910",
          "features": {
            "rrf": 1,
            "bm25": 1,
            "vector": 0.4315,
            "overlap": 0.9,
            "leaf_overlap": 0.3571,
            "attributes": 0.8,
            "tree": 1,
            "cross": 0,
            "legal": 0,
            "xrerank": 0
          }
        }
      ]
    },
    "notes": [
      {
        "key": "N1",
        "doc_type": "chapter_note",
        "ref_code": "61",
        "title": "Chapter 61 – Scope",
        "content": "Chapter 61 applies only to made up knitted or crocheted articles. Heading 6109 covers T-shirts, singlets and tank tops. Articles of apparel that are not knitted or crocheted fall in Chapter 62. [Illustrative summary for demo mode – check against the official text before use.]",
        "source_url": "https://hts.usitc.gov/"
      },
      {
        "key": "N2",
        "doc_type": "gri",
        "ref_code": "GRI1",
        "title": "GRI 1 – Terms of headings and legal notes",
        "content": "Classification is determined according to the terms of the headings and any relative Section or Chapter Notes; titles of sections and chapters are for ease of reference only. [Illustrative summary for demo mode – check against the official text before use.]",
        "source_url": "https://hts.usitc.gov/"
      }
    ],
    "checks": [
      {
        "check": "evidence_matches_source",
        "ok": true,
        "detail": "W1",
        "label": "Evidence matches source"
      },
      {
        "check": "evidence_matches_source",
        "ok": true,
        "detail": "W2",
        "label": "Evidence matches source"
      }
    ],
    "warnings": [],
    "timings_ms": {
      "understand": 11,
      "retrieve": 16,
      "legal": 3,
      "evidence": 0,
      "llm": 0,
      "validate": 3,
      "duty": 1
    },
    "dataset": {
      "id": "00641a7ade5b4bf6afe5db0a0d2ee585",
      "market": "US",
      "version": "2026-SAMPLE",
      "name": "HTSUS – bộ dữ liệu mẫu (DEMO, không phải dữ liệu chính thức)",
      "is_demo": true,
      "source_name": "Mô phỏng theo cấu trúc bản xuất JSON của USITC (hts.usitc.gov). Dòng thuế 8–10 số và mô tả được rút gọn/minh họa.",
      "source_url": "https://hts.usitc.gov/",
      "loaded_at": "2026-10-03T16:07:51.131282",
      "national_digits": 10,
      "effective_date": "2026-01-01"
    },
    "disclaimer": "This result is an automated suggestion for reference only, not an official classification decision. The declarant is responsible for the declared code; for complex cases, request an advance ruling from the customs authority."
  },
  "missing_info": [],
  "error": null,
  "final_description": null,
  "review_note": null,
  "decided_by_name": null,
  "events": [
    {
      "id": 1,
      "action": "created",
      "user_name": "Administrator",
      "user_role": "admin",
      "from_code": null,
      "to_code": "6109.10.00.14",
      "note": "AI: Proposed",
      "dataset_version": "2026-SAMPLE",
      "created_at": "2026-10-03T16:07:51.371470"
    },
    {
      "id": 2,
      "action": "rerun",
      "user_name": "Administrator (API: Documentation examples)",
      "user_role": "admin",
      "from_code": null,
      "to_code": null,
      "note": "Rerun with additional details → 654260f79ab647b699d7f69796bb7da4",
      "dataset_version": "2026-SAMPLE",
      "created_at": "2026-10-03T16:07:51.562452"
    }
  ],
  "progress": null
}

List lookups

GET /api/lookups

Query parameters

Name Type Required Description
q string or null No Up to 200 characters
status string[] or null No -
market string or null No -
kind string or null No -
decision string or null No -
page integer No Minimum 1, default 1
page_size integer No Minimum 1, maximum 200, default 20
sort one of: newest, oldest, confidence, risk No Newest (default), oldest, confidence (least certain first), or risk (highest first, then oldest first). With confidence, queued, processing and failed lookups (confidence 0.0) come first. Default "newest"
date_from string or null No Created on or after this day (UTC)
date_to string or null No Created on or before this day (UTC)
created_by string or null No User id, or 'me'. Up to 32 characters
confidence_min number or null No Minimum 0, maximum 1
confidence_max number or null No Minimum 0, maximum 1
flag string or null No Review flag code, e.g. low_confidence. Pattern ^[a-z0-9_]{1,40}$

Returns 200 with Page.

Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.

Try it in the explorer

A key with the entry role lists the lookups of its own account. status may be repeated to ask for several states. See Pagination.

GET /api/lookups
curl "https://htspilot.com/api/lookups?page=1&page_size=20" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://htspilot.com/api/lookups?page=1&page_size=20",
    headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
    method="GET",
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))
const response = await fetch("https://htspilot.com/api/lookups?page=1&page_size=20", {
  headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());
Response 200
{
  "items": [
    {
      "id": "bcb6a35ae2694828b191f78ed704a9a9",
      "created_at": "2026-10-03T16:07:51.322570",
      "kind": "single",
      "batch_id": null,
      "row_index": null,
      "parent_lookup_id": null,
      "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
      "market": "US",
      "dataset_version": "2026-SAMPLE",
      "status": "proposed",
      "status_label": "Proposed",
      "recommended_code": "6109.10.00.14",
      "recommended_description": "Chapter 61: Articles of apparel and clothing accessories, knitted or crocheted > T-shirts, singlets, tank tops and similar garments, knitted or crocheted > Of cotton > Men's or boys' > Other T-shirts",
      "hs6": "610910",
      "confidence": 0.75,
      "review_flags": [
        {
          "code": "no_official_evidence",
          "message": "No official source confirms the proposed code"
        },
        {
          "code": "demo_data",
          "message": "Tariff data is incomplete"
        }
      ],
      "risk": 18,
      "risk_level": "low",
      "resolved": false,
      "processing_ms": 41,
      "decision": null,
      "decision_label": null,
      "final_code": null,
      "decided_at": null,
      "created_by": "d10db811d389470a8210b8210c023289",
      "created_by_name": "Administrator",
      "sku_id": null,
      "language": "en",
      "comment_count": 0
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}

POST /api/lookups/{lookup_id}/rerun

Changes data in your account when executed. Runs the lookup again with the fields you send added to, or replacing, the ones it had. The answer is a new lookup; the old one is marked resolved. It is written in the language of the lookup it continues, unless the request names another language. Spends credits.

Path parameters

Name Type Description
lookup_id string -

Request body (application/json)

Name Type Required Description
description string or null No Up to 2000 characters
material string or null No Up to 500 characters
use string or null No Up to 500 characters
composition string or null No Up to 500 characters
origin string or null No Up to 100 characters
notes string or null No Up to 1000 characters
market string or null No Up to 8 characters
tariff_version string or null No Up to 64 characters
language string or null No Language the answer is written in: the reasons and explanations, the questions about missing information with their options, the legal findings and the warnings. A tag with a region is read by its primary subtag (en-US is en, ko-KR is ko), in any case. Without it: the language of the lookup that is run again. Review flags, status labels and the other responses are not affected: they follow Accept-Language. Up to 35 characters

Returns 202 with LookupDetail.

Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.

Try it in the explorer

Send only the fields that change. The answer is a new lookup with parent_lookup_id set; the old one is marked resolved. This is how a needs_info lookup is continued: add what missing_info and result.questions ask for.

POST /api/lookups/{lookup_id}/rerun
curl -X POST "https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9/rerun" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
  -H "Content-Type: application/json" \
  -d '{
  "composition": "60% cotton, 40% polyester",
  "notes": "Crew neck, no pockets"
}'
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9/rerun",
    data=json.dumps({"composition": "60% cotton, 40% polyester", "notes": "Crew neck, no pockets"}).encode(),
    headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))
const response = await fetch("https://htspilot.com/api/lookups/bcb6a35ae2694828b191f78ed704a9a9/rerun", {
  method: "POST",
  headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
  body: JSON.stringify({
    "composition": "60% cotton, 40% polyester",
    "notes": "Crew neck, no pockets"
  }),
});
console.log(await response.json());
Response 202
{
  "id": "654260f79ab647b699d7f69796bb7da4",
  "created_at": "2026-10-03T16:07:51.562452",
  "kind": "single",
  "batch_id": null,
  "row_index": null,
  "parent_lookup_id": "bcb6a35ae2694828b191f78ed704a9a9",
  "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
  "market": "US",
  "dataset_version": "2026-SAMPLE",
  "status": "queued",
  "status_label": "New – queued",
  "recommended_code": null,
  "recommended_description": null,
  "hs6": null,
  "confidence": 0,
  "review_flags": [],
  "risk": 0,
  "risk_level": "low",
  "resolved": false,
  "processing_ms": 0,
  "decision": null,
  "decision_label": null,
  "final_code": null,
  "decided_at": null,
  "created_by": "d10db811d389470a8210b8210c023289",
  "created_by_name": "Administrator",
  "sku_id": null,
  "language": "en",
  "comment_count": 0,
  "input": {
    "description": "Men's T-shirt, knitted, 100% cotton, short sleeves, crew neck",
    "material": "cotton",
    "use": "apparel",
    "composition": "60% cotton, 40% polyester",
    "origin": "VN",
    "notes": "Crew neck, no pockets",
    "market": "US",
    "tariff_version": "2026-SAMPLE"
  },
  "origin_label": "Vietnam (VN)",
  "normalized": {},
  "result": {},
  "missing_info": [],
  "error": null,
  "final_description": null,
  "review_note": null,
  "decided_by_name": null,
  "events": [],
  "progress": null
}

Count lookups

GET /api/stats

Returns 200 with a JSON object, as in the example.

Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.

Try it in the explorer

GET /api/stats
curl "https://htspilot.com/api/stats" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
import json
import os
import urllib.request

request = urllib.request.Request(
    "https://htspilot.com/api/stats",
    headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
    method="GET",
)
with urllib.request.urlopen(request) as response:
    print(json.load(response))
const response = await fetch("https://htspilot.com/api/stats", {
  headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());
Response 200
{
  "by_status": {
    "proposed": 1
  },
  "total": 1,
  "pending_review": 0,
  "open_alerts": 0
}