POST /label/chem/classify/batch
Screens a list of substances in a single call: up to 200 entries, each by
cas, ec or exact name, all evaluated at one date, settled with one
x402 payment for the whole batch. Each item runs through the same engine as
GET /label/chem/classify — the harmonised
Annex VI (CLP) classification, versioned by ATP. The lookup is purely local →
response in milliseconds, no network call and no secret.
One settlement for N substances is the BOM / formulation screening path: an
agent checks a bill of materials before shipping a label or a safety data sheet.
The batch is settled as one x402 payment for the whole call and priced per
unit by the gateway (the first substance is roughly the price of the single
call, then each additional substance adds to the total) — see the live
/catalog for the authoritative price.
x402 golden rule: the agent pays for the answer to its question. A
well-formed batch is a successful answer → 200, even when some substances are
not_harmonised and even when a single item is malformed (that item is returned
with { error, code } at its position, without failing the batch). The 4xx
range is reserved for requests the service cannot answer (missing or malformed
body, empty list, batch over the cap).
Request
POST with a JSON body. Set Content-Type: application/json.
POST /label/chem/classify/batch
Content-Type: application/json
{
"items": [{ "cas": "100-41-4" }, { "cas": "7732-18-5" }],
"at": "2026-06-01"
}
| Field | Type | Required | Description |
|---|---|---|---|
items | object[] | yes | 1 to 200 items; each carries exactly one of cas / ec / name, same rules as the single call |
at | string | no | YYYY-MM-DD — common to the whole batch (a BOM is evaluated at one date); defaults to today |
A single at for the whole batch is deliberate: a bill of materials is assessed
against one regulatory version. The cap is checked before any lookup, so
an empty list or one over 200 is rejected without being billed an answer.
200 response — UnifiedResponse
{
"data": {
"count": 2,
"results": [
{ "verdict": "harmonised", "entries": [ ... ] },
{
"verdict": "not_harmonised",
"entries": [],
"note": "Absence does not mean the substance is not hazardous: self-classification under CLP remains the responsibility of the entity placing it on the market."
}
]
},
"provenance": {
"source": "ECHA Annex VI (CLP)",
"fetched_at": "2026-07-24T07:45:50Z",
"freshness": { "kind": "snapshot", "as_of": "2026-05-01T00:00:00Z" }
}
}
count: number of results, equal toresults.lengthand to the number of items submitted.results: one verdict per item, in the same order as the input. Each well-formed element has exactly the same shape as thedataofGET /label/chem/classify—verdict,entries[], andnote/upcomingwhere they apply.- A single
provenanceblock covers the whole batch: every item is resolved against the same Annex VI snapshot, at the sameat.
See the single-call reference for the full field
tables, the ATP versioning (atp + upcoming) and the self-classification note
carried by not_harmonised verdicts.
A malformed item stays at its position
A single bad item does not fail the batch: it is returned in place as
{ error, code }, so a caller can re-pair results without tracking indices.
{
"data": {
"count": 2,
"results": [
{ "error": "invalid CAS check digit: '100-41-5'", "code": "INVALID_INPUT" },
{ "verdict": "harmonised", "entries": [ ... ] }
]
},
"provenance": {
"source": "ECHA Annex VI (CLP)",
"fetched_at": "2026-07-24T07:45:50Z",
"freshness": { "kind": "snapshot", "as_of": "2026-05-01T00:00:00Z" }
}
}
Errors
Only requests the service cannot answer leave the 200 range. The cap is checked before any resolution, so an oversized batch is rejected without being billed.
| Status | code | Case |
|---|---|---|
| 400 | INVALID_INPUT | Body missing or not JSON, not an object, items missing, empty, or over 200; a malformed at |
| 503 | DATA_UNAVAILABLE | The Annex VI dataset has not been ingested yet — there is no snapshot to serve |
| 500 | INTERNAL | Internal error (detail logged, not exposed) |
{ "error": "batch too large: 201 items, the maximum is 200", "code": "INVALID_INPUT" }
See also
GET /label/chem/classify— single-substance reference and full field documentation.- For agents — discovery surfaces, the live
/catalogand how settlement works.