Errors
How the API reports failures: status codes and the error body shape.
Errors come back as JSON with a snake_case code and a matching HTTP status:
Some errors carry extra detail alongside the code (for example a list of offending field keys). Always branch on the HTTP status first, then on the error code.
Status codes
The 404-as-leak-guard convention matters. A 404 on a space-scoped resource can mean “does not exist” or “you cannot see it.” The API deliberately does not distinguish the two. You cannot probe for resources you lack access to.
Common error codes
Errors on capability endpoints
The capability endpoints (/v1/…) use a richer envelope. The legacy { "error": … } shape above is unchanged on every other route.
invalid_request
400. The body or query is malformed: a missing field, a bad type, or a mutually exclusive pair sent together (file and files, schema and action, spaceId and space on keep). It also covers a parameter that does not apply to the input, such as style on a PDF or mode on audio. It also covers a saved sign action passed as another verb’s action. message names the offending field. Fix the call. An identical retry fails identically.
A slow run is never an error. At the synchronous cap, the call returns 202 with the run handle. A run that waits on a human returns 202 with needs_input. Both are successes with a body to poll.
invalid_schema
400. The schema you sent to extract breaks the extraction schema dialect. docUrl points at the exact rule. message points at the exact node.
not_found
404. No such run, file, template, action, webhook endpoint, or produced output. The API also returns it when a sub-route addresses a step the run does not have, for example GET /v1/runs/plr_…/envelope on a pipeline with no sign step. Right after a synchronous run returns, GET /v1/runs/:id/output/:name can 404 for a moment while the produced file registers. Re-fetch the run and use output.file.url.
Other capability codes
New codes can appear over time. Branch on the codes you handle. Treat an unknown code as a plain failure of its HTTP status class.
Retrying
503 auth_unavailableand503downstream errors are transient. Retry with exponential backoff.410 expiredis terminal for that resource. Do not retry.429 rate_limitedis also transient. Sleep for theRetry-Afterseconds, then back off exponentially. Rate limits covers the budget and the tactics.402 credits_exhaustedis not transient. A retry burns nothing, but it cannot succeed until you top up the balance.4xxother than429means a bad request. Fix the call instead of retrying.