> ## Documentation index
> Fetch the complete documentation index at: https://docs.htspilot.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 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](/asynchronous-work.md)) 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](/tariff-data.md#markets)) |
| `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](/languages.md)) |
| `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 |
| `retrieval` | How the candidate lines were found: `mode` is `hybrid` (text and vector search) or `lexical` (text search alone), with a `reason` when the search was narrower than usual, and how many `lines` of the schedule had a vector (`embedded`) |
| `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.

**Example request**

```bash
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"
}'
```

**Example response** `202`

```json
{
  "id": "f4a2251d5dc941ec99f7d459e05082a5",
  "created_at": "2026-10-03T19:48:02.932457",
  "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": "processing",
  "status_label": "Processing",
  "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": "a7ba4a2440c7422fb695a1fd80d65ce5",
  "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
}
```

Try it: https://docs.htspilot.com/explorer/#/Lookups/classifyProduct

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.

## 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.

**Example request**

```bash
curl "https://htspilot.com/api/lookups/f4a2251d5dc941ec99f7d459e05082a5" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
```

**Example response** `200` (long lists and texts are cut)

```json
{
  "id": "f4a2251d5dc941ec99f7d459e05082a5",
  "created_at": "2026-10-03T19:48:02.932457",
  "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": 55,
  "decision": null,
  "decision_label": null,
  "final_code": null,
  "decided_at": null,
  "created_by": "a7ba4a2440c7422fb695a1fd80d65ce5",
  "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,
        "min_pct": null,
        "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,
          "min_pct": null,
          "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-03T19:48:02.982666+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-03T19:48:02.982666+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/"
      }
    ],
    "retrieval": {
      "mode": "hybrid",
      "reason": null,
      "embedded": 71,
      "lines": 71
    },
    "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": 13,
      "retrieve": 17,
      "legal": 15,
      "evidence": 0,
      "llm": 0,
      "validate": 3,
      "duty": 2
    },
    "dataset": {
      "id": "76235cf1803b4782be050a08c64c3cad",
      "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-03T19:48:02.737682",
      "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-03T19:48:02.993175"
    },
    {
      "id": 2,
      "action": "rerun",
      "user_name": "Administrator (API: Documentation examples)",
      "user_role": "admin",
      "from_code": null,
      "to_code": null,
      "note": "Rerun with additional details → 2655d2f9c3b047c6906b25d45a24c522",
      "dataset_version": "2026-SAMPLE",
      "created_at": "2026-10-03T19:48:03.200629"
    }
  ],
  "progress": null
}
```

Try it: https://docs.htspilot.com/explorer/#/Lookups/getLookup

## 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.

**Example request**

```bash
curl "https://htspilot.com/api/lookups?page=1&page_size=20" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
```

**Example response** `200`

```json
{
  "items": [
    {
      "id": "f4a2251d5dc941ec99f7d459e05082a5",
      "created_at": "2026-10-03T19:48:02.932457",
      "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": 55,
      "decision": null,
      "decision_label": null,
      "final_code": null,
      "decided_at": null,
      "created_by": "a7ba4a2440c7422fb695a1fd80d65ce5",
      "created_by_name": "Administrator",
      "sku_id": null,
      "language": "en",
      "comment_count": 0
    }
  ],
  "total": 1,
  "page": 1,
  "page_size": 20
}
```

Try it: https://docs.htspilot.com/explorer/#/Lookups/listLookups

A key with the `entry` role lists the lookups of its own account. `status` may be repeated to ask for several
states. See [Pagination](/pagination.md).

## Rerun a lookup with more information

`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.

**Example request**

```bash
curl -X POST "https://htspilot.com/api/lookups/f4a2251d5dc941ec99f7d459e05082a5/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"
}'
```

**Example response** `202`

```json
{
  "id": "2655d2f9c3b047c6906b25d45a24c522",
  "created_at": "2026-10-03T19:48:03.200629",
  "kind": "single",
  "batch_id": null,
  "row_index": null,
  "parent_lookup_id": "f4a2251d5dc941ec99f7d459e05082a5",
  "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": "a7ba4a2440c7422fb695a1fd80d65ce5",
  "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
}
```

Try it: https://docs.htspilot.com/explorer/#/Lookups/rerunLookup

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.

## 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.

**Example request**

```bash
curl "https://htspilot.com/api/stats" \
  -H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"
```

**Example response** `200`

```json
{
  "by_status": {
    "proposed": 1
  },
  "total": 1,
  "pending_review": 0,
  "open_alerts": 0
}
```

Try it: https://docs.htspilot.com/explorer/#/Lookups/getLookupCounts
