Job lifecycle
| Status | Meaning |
|---|---|
pending | Accepted; waiting for a worker. |
running | Being processed. |
succeeded | Done — result is populated. |
failed | Terminal failure — error.code / error.message explain why. Cancelled jobs also land here with error.code = "cancelled". |
succeeded and failed are terminal; a job never leaves them.
Sync vs. async
Every method comes as a pair:Sync (POST /parse) | Async (POST /parse_async) | |
|---|---|---|
| Returns | 200 with the full job (including result) once finished | 202 with {"job_id": "..."} immediately |
| Best for | Small documents, interactive flows | Large documents, batch pipelines |
| Wait budget | ?timeout_seconds= — default 120, min 1, max 300 | n/a |
200 — finished within the timeout
200 — finished within the timeout
The body is the full job object. Check
status: it is succeeded (read result) or failed (read error).202 — started, but no sync capacity right now
202 — started, but no sync capacity right now
Under load the server starts your job but declines to hold the connection.
The body is
{"job_id": "..."} — poll GET /jobs/{job_id} exactly as if
you had called the async variant.408 — didn't finish within timeout_seconds
408 — didn't finish within timeout_seconds
The job keeps running. The error detail includes the
job_id
(api_request_id); poll GET /jobs/{job_id} for the result.Polling
PollGET /jobs/{job_id} until status is terminal:
Idempotency
Network failures make retries inevitable. To retry a POST safely, set anidempotency_key (any string up to 128 characters — a UUID you mint per logical operation works well):
200 with the existing job’s current state — which may be pending, running, or already succeeded with the result inline. (On the sync endpoints, a replay of a still-running job waits for it, preserving the sync contract.)
Keys are scoped to your tenant and to the method: the same key on /parse and /ground refers to two different jobs.
Listing and cancelling
GET /jobslists your jobs newest-first with cursor pagination and an optionalstatusfilter. Summaries only — no result payloads.POST /jobs/{job_id}/cancelcancels a pending/running job. There is no separatecancelledstatus: the job lands infailedwitherror.code = "cancelled". Cancelling an already-terminal job is a no-op that returns its current state.