Errors
Inferio splits errors across two surfaces:
- Transport layer — HTTP 4xx / 5xx for auth, network, and Inferio-side incidents. Your client retry logic handles these.
- Application layer — HTTP 200 with a JSON body containing
error_code. These mean the request was understood but business logic said no (session expired, file too large, etc.). Your application logic handles these.
Transport-layer errors
| HTTP code | Meaning | Retry? |
|---|---|---|
400 | Malformed request — bad JSON, missing required field | No (fix the call) |
401 | Missing / malformed / revoked Authorization header | No (rotate token) |
403 | Token valid but X-Merchant-ID mismatch | No (fix header) |
404 | Resource not found (request_id, document_id, session_id) — could be soft-deleted | No (verify ID) |
409 | Idempotency-Key collision with a different payload | No (use new key) |
413 | File too large at the transport layer (before per-merchant limits) | No (split file) |
429 | Rate-limited | Yes (exponential backoff) |
5xx | Inferio-side incident | Yes (3 attempts, exp. backoff) |
Application-layer errors (HTTP 200 + error_code)
Returned with shape:
{
"error_code": "UPLOAD_SESSION_EXPIRED",
"message": "Upload session expired at 2026-04-30T03:18:02Z",
"details": { "session_id": "f47ac10b-…", "expired_at": "..." },
"trace_id": "trace_3fa1c4e2b9d1"
}Upload-session codes
error_code | Meaning |
|---|---|
UPLOAD_SESSION_NOT_FOUND | Bad session_id — typo or expired |
UPLOAD_SESSION_EXPIRED | TTL elapsed (default 24h) |
UPLOAD_SESSION_MISMATCH | Session belongs to a different merchant |
FILE_TOO_LARGE | Over per-file limit_size_mb |
FILE_COUNT_EXCEEDED | Past limit_file in this session |
UNSUPPORTED_FILE_TYPE | Not PDF / PNG / JPG / TIFF |
Request codes
error_code | Meaning |
|---|---|
INVALID_DOCUMENT_TYPE | document_type not in the built-in template list or custom-schema set |
WEBHOOK_URL_INVALID | webhook_url not HTTPS or unreachable |
MERCHANT_CREDITS_EXHAUSTED | Trial credits gone + no billing on file |
Document / extraction codes
error_code | Meaning |
|---|---|
LLM_REJECTED | LLM declined to extract — wrong doc type, unreadable, etc. Not billed. |
EXTRACTION_TIMEOUT | LLM took longer than request_timeout_ms (default 60s) |
VALIDATION_FAILED | Domain-validator caught a bad value (e.g. invalid T-number format) |
T-number-specific codes
error_code | Meaning |
|---|---|
T_NUMBER_INVALID_FORMAT | Extracted T-number doesn’t match the 13-digit shape T\d{13} |
T_NUMBER_NOT_REGISTERED | NTA API returns “not found” for the number |
T_NUMBER_REVOKED | NTA API returns “revoked” — invoice is no longer tax-deductible |
T_NUMBER_API_UNAVAILABLE | NTA public API is down — document marked as “needs review” and you can re-validate later |
Always log trace_id
Every error response carries a trace_id. Surface it in your logs and
quote it when contacting support — we can pull the full request +
extraction trail from a single trace_id, often skipping the
back-and-forth.