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

# Classifying Products with AI

> Suggest Numeral tax categories for your catalog from product names and descriptions

Every product you register with Numeral needs a [product category](https://docs.numeral.com/essentials/product-categories.md), and the list is long. The classify endpoint suggests a category for each product from its name and description, so you can categorize a catalog in batches instead of by hand. It runs on AI provider keys you store in the dashboard, and it can create the products for you in the same call.

> [!WARNING]
>
> Product classification is in limited availability. Accounts that are not enabled receive `404 ENDPOINT_NOT_FOUND` from the endpoint. Contact your Numeral representative to enable it for your account.

## Prerequisites

**1. Use API version 2026-01-01 or later**

Send `X-API-Version: 2026-01-01` or newer. Older versions reject the endpoint with a message naming the required version. See [versioning](https://docs.numeral.com/api-reference/versioning.md).

**2. Store your AI provider keys**

In the dashboard, open **Developers > Product Classification AI API Keys and Settings** and save a key for each environment you'll call from. The test and production environments keep separate keys: a request made with a `sk_test_...` API key uses the test-environment keys, and a production key uses the production ones.

Classification has two steps, embeddings and category selection, and each provider covers one or both:

| Provider | Embeddings | Category selection |
| - | - | - |
| OpenAI | Yes | Yes |
| Gemini | Yes | No |
| Anthropic | No | Yes |

One OpenAI key is enough on its own. If you store Gemini and Anthropic keys as well, that pair is used instead of OpenAI. Keys are checked against the provider when you save them.

**3. Confirm the endpoint is enabled**

Call the endpoint with a test key. A `404 ENDPOINT_NOT_FOUND` means your account is not enabled yet.

> [!NOTE]
>
> Product names and descriptions are sent to your AI provider under your own account, so your provider's usage and data terms apply, and usage is billed to you by the provider.

## Step 1: Classify a batch

Send up to 20 products per request. Leave `create_products` off while you review results.

```bash theme={null}
curl https://api.numeralhq.com/tax/products/classify \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Version: 2026-11-01' \
  -d '{
    "create_products": false,
    "products": [
      {
        "reference_product_id": "sku-shirt-001",
        "reference_product_name": "Cotton crew neck t-shirt",
        "reference_product_description": "Unisex short-sleeve shirt, 100% cotton"
      },
      {
        "reference_product_id": "sku-saas-plan",
        "reference_product_name": "Monthly analytics subscription",
        "reference_product_description": "Hosted dashboard, billed monthly, no download"
      },
      {
        "reference_product_id": "sku-mystery-box",
        "reference_product_name": "Mystery box"
      }
    ]
  }'
```

```json Response theme={null}
{
  "object": "list",
  "create_products": false,
  "product_categories": [
    {
      "reference_product_id": "sku-shirt-001",
      "status": "classified",
      "product_category": "CLOTHING_GENERAL",
      "confidence_score": 0.94,
      "product_creation_status": "not_requested"
    },
    {
      "reference_product_id": "sku-saas-plan",
      "status": "classified",
      "product_category": "GENERAL_SAAS_NO_MS_SERVER",
      "confidence_score": 0.81,
      "product_creation_status": "not_requested"
    },
    {
      "reference_product_id": "sku-mystery-box",
      "status": "fallback",
      "product_category": "GENERAL_MERCHANDISE",
      "confidence_score": null,
      "product_creation_status": "not_requested"
    }
  ],
  "testmode": true
}
```

Results come back in request order, one per product, matched by `reference_product_id`.

> [!TIP]
>
> A short description makes a real difference for names that could mean several things. "Monthly analytics subscription" alone could be software, a newsletter or a service; "hosted dashboard, no download" settles it.

## Step 2: Read the results

Each result has a `status`:

| `status` | What you get | What to do |
| - | - | - |
| `classified` | A category code and a `confidence_score` from `0` to `1` | Accept high scores. Have someone review lower ones before they reach production. |
| `fallback` | `GENERAL_MERCHANDISE` with no score | The classifier could not pick a category. Categorize this product by hand. |
| `failed` | No category | The product could not be processed this time. Send it again in a later batch. |

`product_category` is always a code from the [product categories](https://docs.numeral.com/essentials/product-categories.md) list, so you can pass it to `POST /tax/products` or as a line item `product_category` without translation.

Pick a confidence threshold that fits your review capacity. Scores are the classifier's own estimate, not a guarantee, so a review pass on anything below your threshold is worth the time: the category sets the tax rate on every sale of that product.

## Step 3: Create the products

Once you trust the results, either register the reviewed categories yourself with [`POST /tax/products`](https://docs.numeral.com/api-reference/v2026-11-01/endpoint/products), or let the classify call do it by setting `create_products` to `true`.

```json theme={null}
{
  "create_products": true,
  "products": [
    { "reference_product_id": "sku-shirt-001", "reference_product_name": "Cotton crew neck t-shirt" }
  ]
}
```

With `create_products` on, `product_creation_status` tells you what happened to each record:

| `product_creation_status` | Meaning |
| - | - |
| `created` | The product was registered with the suggested category. |
| `already_exists` | A product with this `reference_product_id` was already registered. It was not changed, even if its category differs. |
| `not_classified` | The result was `fallback` or `failed`, so nothing was created. Categorize it by hand. |
| `failed` | The product classified but could not be saved. Retry it. |
| `not_requested` | `create_products` was `false`. |

Two rules apply when creating: `reference_product_id` must be unique within the batch, and only `classified` products are created. Fallback products are never registered as `GENERAL_MERCHANDISE` automatically.

## Batching, concurrency and retries

* **20 products per request.** Split larger catalogs into batches and send them one after another.
* **One request at a time per account.** A second request while one is in flight returns `429 PRODUCT_CLASSIFICATION_CAPACITY_EXCEEDED` with a `Retry-After` header. Wait that many seconds and resend.
* **Allow time.** A full batch can take tens of seconds. Set your HTTP client timeout to at least 60 seconds.
* **Retry on `429` and `503`** with the `Retry-After` value when present, and exponential backoff otherwise. `429 PRODUCT_CLASSIFICATION_PROVIDER_QUOTA` means your AI provider throttled the request, so slow down rather than retry immediately.
* **Partial results are normal.** A batch where some products are `failed` still returns `200`. Only a batch where every product failed returns `503`.

## Errors

| HTTP | `type` | When |
| - | - | - |
| 400 | `PRODUCT_CLASSIFICATION_CREDENTIALS_MISSING` | No AI provider keys are stored for this environment. |
| 400 | `PRODUCT_CLASSIFICATION_CREDENTIALS_INVALID` | The stored keys were rejected by the provider. Re-enter them in the dashboard. |
| 404 | `ENDPOINT_NOT_FOUND` | Product classification is not enabled for this account. |
| 429 | `PRODUCT_CLASSIFICATION_CAPACITY_EXCEEDED` | Another request is in progress for this account, or the service is at capacity. |
| 429 | `PRODUCT_CLASSIFICATION_PROVIDER_QUOTA` | Your AI provider rate limited the request. |
| 503 | `PRODUCT_CLASSIFICATION_UNAVAILABLE` | The service is temporarily unavailable, or every product in the batch failed. |

Validation errors such as `MISSING_FIELD` and `UNRECOGNIZED_FIELD` apply as on every endpoint. See [Error Codes](https://docs.numeral.com/api-reference/v2026-11-01/error-codes.md).

## Learn more

[Classify Products endpoint](https://docs.numeral.com/api-reference/v2026-11-01/endpoint/classify_products)

[Managing Product Categories](https://docs.numeral.com/essentials/integration-guides/products-and-categories.md)

[Product Categories](https://docs.numeral.com/essentials/product-categories.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.