Errors are JSON, always the same shape, and carry a stable machine-readable `code` alongside a human-readable message. Match on the code; the message is for your logs.
{ "error": {
"code": "match_below_threshold",
"message": "No confident match for that reference.",
"status": 422,
"request_id": "req_01JQ8Z3M4K",
"docs": "https://commercecensus.com/docs/errors/#match_below_threshold" } }| Status | Code | Retry? | Cause |
|---|---|---|---|
| 400 | invalid_request | No | Malformed parameters. Fix the call. |
| 401 | invalid_key | No | Missing, malformed or revoked key. |
| 403 | insufficient_scope | No | Key lacks the required scope. |
| 404 | not_found | No | No such product, watch or memory. |
| 409 | cursor_expired | Restart | Cursor older than 24 hours. |
| 422 | match_below_threshold | No | Reference resolved nothing confident. Not an error to retry — send more identifying detail. |
| 429 | rate_limited | Yes | Back off by Retry-After, with jitter. |
| 500 | internal | Yes | Ours. Retry with backoff; if it persists, send the request_id. |
| 503 | source_unavailable | Yes | An upstream seller is not answering. Cached values still return with an older observed_at. |
`match_below_threshold` means we refused to guess. Returning a low-confidence match silently would be worse: a confidently wrong GTIN corrupts every join built on it. Send more detail, or accept the flagged low-confidence result explicitly with `allow_low_confidence: true`.
It is on every response, success or failure, and it is the only thing that lets support find your exact call.