Skip to main content

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.

When contacting support about a failed request, include the 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

statusCodeintegerHTTP status code (matches the response status).
codestringMachine-readable error code (e.g. `VALIDATION_ERROR`, `RESOURCE_NOT_FOUND`). See [Error Codes](error-codes).
errorstringShort error label. Often the HTTP status text, but guards emit lowercase identifiers such as `unauthorized`, `insufficient_scope`, or `rate_limit_exceeded` — treat it as informational and branch on `code` or `statusCode`.
messagestringHuman-readable explanation. Multiple validation failures are joined with `;`.
retryableboolean`true` if the same request may succeed on retry (e.g. queue overload, upstream timeouts).
detailsobjectOptional structured context, e.g. `required_scopes`/`key_scopes` on scope failures or `limit`/`used`/`reset_at` on daily rate limits.
request_idstringServer-side trace id, prefixed `req_`. Also sent as the `X-RequestId`-style header `X-Request-Id` on every response.
timestampstringISO 8601 timestamp of when the error occurred.
pathstringThe request path that produced the error.

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.

Frequently asked questions

What does a Talonic API error look like?+
A JSON object with statusCode, code (machine-readable), error (short label), message (human-readable), retryable (boolean), request_id, timestamp, and path, plus an optional details object with structured context. The shape is identical across all endpoints.
How do I know if a Talonic API error is retryable?+
Check the retryable field in the error response. If true, retry the same request with exponential backoff. If false, fix the request before sending it again — with one exception: a 429 daily rate limit reports retryable false but is safe to retry after the window resets.
Does the Talonic API include a request ID in error responses?+
Yes — every error body includes a request_id prefixed with req_, and the same value is echoed in the X-Request-Id response header on successes and failures alike. Include it in support requests; it links directly to the server-side trace.
What is the details field in a Talonic API error?+
An optional object carrying structured, endpoint-specific context: 403 scope failures include required_scopes and key_scopes, and daily rate-limit 429s include limit, used, and reset_at. Use envelope fields for control flow and details only for diagnostics.