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

# Classify a product

> Get HS code suggestions for a product description, image, or listing URL.

Requires the `classify:read` scope.

Provide a `description`, an `image_url`, a `product_url`, or a combination
(`image_url` and `product_url` are mutually exclusive). Image and URL inputs
require a vision/url-enabled mode — see
[`GET /classify/modes`](/api-reference/classify/modes).

<ParamField body="description" type="string">
  What the product is, in plain language (up to 2000 chars). The more
  specific — material, use, who it's for — the better the suggestion.
</ParamField>

<ParamField body="image_url" type="string">
  A product photo: an `http(s)://` URL, a `gs://` Cloud Storage URI, or a
  `data:image/*;base64,` data URL (max \~9 MB). Vision-enabled modes only —
  a mode without image support returns `400`.
</ParamField>

<ParamField body="product_url" type="string">
  An `http(s)://` product-listing URL (up to 2000 chars). The page is read
  and the product identified from it (url-enabled modes only). The response
  carries `used_url: true` and echoes what was read as `url_description`.
</ParamField>

<ParamField body="destination_country" type="string" required>
  ISO 3166-1 alpha-2 destination (case-insensitive) — determines which
  tariff schedule the code is resolved against.
</ParamField>

<ParamField body="mode" type="string">
  Classification mode slug. See
  [`GET /classify/modes`](/api-reference/classify/modes); omit for the
  default mode.
</ParamField>

<ParamField body="title" type="string">
  Product title (e.g. the listing name), up to 500 chars.
</ParamField>

<ParamField body="brand" type="string">
  Brand name, up to 200 chars.
</ParamField>

<ParamField body="sku" type="string">
  Your item reference, up to 100 chars.
</ParamField>

<ParamField body="type" type="string">
  Product type/category hint, up to 200 chars.
</ParamField>

<ParamField body="country_of_origin" type="string">
  ISO alpha-2 origin, if known.
</ParamField>

<ParamField body="price" type="number">
  Unit price — some headings split on value.
</ParamField>

<ParamField body="currency" type="string">
  ISO 4217 currency of `price` (3 letters).
</ParamField>

<ParamField body="hs_code" type="string">
  A known partial code (2–10 digits, dots allowed) to narrow the search.
</ParamField>

## Response

Returns `200` with the suggestions, or `422` when the input could not be
classified (`success: false` with `unclassifiable: true` and a `reason`).

<ResponseField name="success" type="boolean">
  Whether a classification was produced.
</ResponseField>

<ResponseField name="message" type="string">
  Empty on success; the failure reason otherwise.
</ResponseField>

<ResponseField name="original_description" type="string">
  The description you sent (or the derived one for image/URL requests).
</ResponseField>

<ResponseField name="customs_description" type="string | null">
  The customs-style description the classifier worked from.
</ResponseField>

<ResponseField name="top_result" type="object | null">
  The best suggestion: `chapter`, `heading`, `subheading`, and `tariff`
  blocks (each `{ name, number, description }`), plus `confidence`
  (`high` | `medium` | `low`), `score` (0–1), and `reasoning` when the mode
  produces one.
</ResponseField>

<ResponseField name="results" type="array">
  All suggestions, best first. Each entry carries `code` (the full tariff
  code), `country`, the same `chapter`/`heading`/`subheading`/`tariff`
  hierarchy blocks, `score`, `confidence`, and optional `reasoning`.
</ResponseField>

<ResponseField name="country" type="string">
  The destination you asked for.
</ResponseField>

<ResponseField name="classification_source_country" type="string">
  Present when the destination classifies via a shared schedule (e.g.
  `DE` → `EU`): the schedule that answered.
</ResponseField>

<ResponseField name="mode" type="string">
  The mode that ran.
</ResponseField>

<ResponseField name="data_source" type="object | null">
  Which dataset version answered: `{ version, source, imported_at }`.
</ResponseField>

<ResponseField name="request_id" type="string | null">
  Log id of this request — appears in your classification history
  (`GET /usage-history/classify`).
</ResponseField>

<ResponseField name="used_image" type="boolean">
  Present (`true`) when an image was classified; `image_description` then
  carries what the vision pass saw.
</ResponseField>

<ResponseField name="used_url" type="boolean">
  Present (`true`) when a `product_url` was read; `url_description` then
  carries what the page said.
</ResponseField>

<ResponseField name="rulings" type="array">
  Present when the mode consulted precedent rulings: citations of
  `{ ruling_number, code, subject, url }`.
</ResponseField>

<ResponseField name="blocked" type="boolean">
  Present (`true`) when every suggestion was on your organization's
  [blocklist](/api-reference/classify/blocklist-list).
</ResponseField>

<RequestExample>
  ```bash cURL theme={null}
  curl -X POST https://{partner}.mytraddal.com/admin/api/v1/classify \
    -H 'Content-Type: application/json' \
    -H 'Authorization: Bearer {access_token}' \
    -d '{
      "description": "Men'\''s waterproof hiking backpack, 40L, nylon shell",
      "destination_country": "US"
    }'
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "message": "",
    "success": true,
    "original_description": "Men's waterproof hiking backpack, 40L, nylon shell",
    "customs_description": "Backpack with outer surface of man-made textile materials (nylon)",
    "usedWebSearch": false,
    "top_result": {
      "chapter": { "name": "Chapter", "number": "42", "description": "Articles of leather; travel goods, handbags and similar containers" },
      "heading": { "name": "Heading", "number": "4202", "description": "Trunks, suitcases, backpacks and similar containers" },
      "subheading": { "name": "Subheading", "number": "420292", "description": "With outer surface of sheeting of plastics or of textile materials" },
      "tariff": { "name": "Tariff", "number": "4202923120", "description": "Backpacks, of man-made fibers" },
      "confidence": "high",
      "score": 0.94
    },
    "results": [
      {
        "code": "4202923120",
        "country": "US",
        "chapter": { "name": "Chapter", "number": "42", "description": "Articles of leather; travel goods, handbags and similar containers" },
        "heading": { "name": "Heading", "number": "4202", "description": "Trunks, suitcases, backpacks and similar containers" },
        "subheading": { "name": "Subheading", "number": "420292", "description": "With outer surface of sheeting of plastics or of textile materials" },
        "tariff": { "name": "Tariff", "number": "4202923120", "description": "Backpacks, of man-made fibers" },
        "score": 0.94,
        "confidence": "high"
      }
    ],
    "country": "US",
    "mode": "pro",
    "data_source": {
      "version": "2026 Rev 7",
      "source": "hts_2026_rev7.csv",
      "imported_at": "2026-06-30T08:11:02.000Z"
    },
    "request_id": "0d4c7c58-2f5a-4a6f-9a41-b1f6f9f1d2aa"
  }
  ```

  ```json 422 theme={null}
  {
    "message": "Not a physical product",
    "success": false,
    "original_description": "One hour of consulting",
    "customs_description": null,
    "usedWebSearch": false,
    "unclassifiable": true,
    "reason": "Not a physical product",
    "top_result": null,
    "results": [],
    "country": "US",
    "mode": "pro",
    "data_source": { "version": "2026 Rev 7", "source": "hts_2026_rev7.csv", "imported_at": "2026-06-30T08:11:02.000Z" },
    "request_id": "7b2f0a7e-6f3d-4b25-a6c9-2f4f2f9f1e01"
  }
  ```
</ResponseExample>
