Error Format
Handle Talonic API errors with a consistent JSON envelope: machine-readable code, human-readable message, HTTP status, and a retryable flag for safe retries.
Every Talonic API error returns the same JSON envelope: an HTTP statusCode, a machine-readable code, a human-readable message, and a retryable flag that tells you whether the same request can be retried. Because the shape is identical across all endpoints, you can write one error handler for the entire API and reuse it for every integration you build on /v1.
Most integrations branch on the code field for programmatic error handling and display the message field to users. A typical error handler checks retryable first: if true, queue the request for retry with exponential backoff; if false, surface the message to the caller and stop. Validation failures fold multiple field problems into one message, joined with semicolons (for example "name must be shorter than or equal to 100 characters; name must be a string"), so log the full string rather than the first clause.
Every error also carries a request_id (prefixed req_), which is echoed in the X-Request-Id response header on both successes and failures. It identifies the server-side trace for that exact request, so persist it alongside your own job records. The path field confirms which endpoint produced the error, and timestamp records when it occurred in ISO 8601 format.
When an error has structured context beyond the envelope, it appears under an optional details object. A 403 scope failure includes details.required_scopes and details.key_scopes so you can see exactly which scope the key is missing; a daily rate-limit 429 includes details.limit, details.used, and details.reset_at. Treat details keys as endpoint-specific: rely on the envelope fields for control flow and read details only for diagnostics you know that endpoint emits.
request_id from the error body (or the X-Request-Id header). It links directly to the server-side request trace and is the fastest way to get a specific failure diagnosed.Error response envelope
{
"statusCode": 400,
"code": "VALIDATION_ERROR",
"error": "Bad Request",
"message": "name must be shorter than or equal to 100 characters; name must be a string",
"retryable": false,
"request_id": "req_0468dcdadafb4488",
"timestamp": "2026-08-29T11:36:35.281Z",
"path": "/v1/schemas"
}Envelope fields
Scope failure with structured details (403)
{
"statusCode": 403,
"code": "INSUFFICIENT_PERMISSIONS",
"error": "insufficient_scope",
"message": "This action requires scopes: write",
"retryable": false,
"details": {
"required_scopes": ["write"],
"key_scopes": ["read", "extract"]
},
"request_id": "req_3f9a76b19bd948fc",
"timestamp": "2026-08-29T11:35:05.630Z",
"path": "/v1/schemas"
}Authentication failures are the one place the error label does the distinguishing work: a missing or malformed Authorization header, an invalid or revoked tlnc_ key, and an expired OAuth access token all return 401 with error: "unauthorized" and code: "AUTH_REQUIRED", differing only in message. Extraction errors from POST /v1/extract can additionally carry a links.dashboard URL pointing at the affected document in the Talonic app, which is useful to surface to operators triaging failed documents.
Pair error handling with the [Error Codes](error-codes) reference to map each code value to the correct remediation action, and with [Rate Limits](rate-limits) for the 429 family. statusCode always matches the HTTP response status, so you can branch on either; if you cache responses or run requests through a proxy that strips bodies, branching on the HTTP status plus X-Request-Id still gives you enough to log and retry correctly.