Conventions
The request and response patterns every endpoint shares.
The endpoints are consistent about most things and inconsistent about a few. This page covers both, because the inconsistencies are where integrations break.
Requests are JSON
Every request body is application/json. There is no multipart upload endpoint — documents travel either as base64 inside the JSON body or as a URL the platform fetches.
-H "Content-Type: application/json"Sending a document
Two mutually exclusive ways:
content
The file is local to your service
Base64 inflates the payload by about a third
file_url
The file already has a URL the platform can reach
No inflation, but the URL must be publicly reachable for the length of the job
Send one or the other, never both.
Naming the document type
Also mutually exclusive:
documentType
The file is one document of one known type
documentTypes
One file contains several documents to extract separately (multi-extraction)
Values come from the registry — see Document Types, or call GET /listSupportedDocuments to read the current set at build time.
Neither either/or rule is expressed in the spec's required list. Every property on the extraction request is formally optional, so a request can satisfy the schema and still be rejected. The obligations exist only in the property descriptions, and they are real.
Response envelopes differ by operation
This is the single most common source of integration bugs on this API, so it is worth being precise. Submitting a job and retrieving one wrap their payloads differently and name the job status differently.
Three things to notice:
The wrapper is
dataon submit andextractionon retrieve.The job status is
documentStatuson submit andstatuson retrieve.The retrieve response has two
statusfields at different levels.
The top-level status is the envelope status. It reads "success" whenever the HTTP call worked, and it says nothing about the job. A poller that checks the top-level status sees "success" on the very first attempt and never stops polling. The job state you want is extraction.status.
And it is not one pattern with one exception — the wrapper differs per operation. The full set:
POST /extract, /classify/sync … (sync)
none — result at top level
documentStatus
POST /extract (async)
data
data.documentStatus
GET /document-extractions/{id}
extraction
extraction.status
POST /classify (async)
requestInfo
— (queued only)
GET /classifications/{id}
classification
classification.status
POST /extract/bulk, /classify/bulk
results[] — one entry per file
per entry
GET /document-extractions/group/{id}
extractions — keyed by documentType
per child
POST /generate/sync
none — binary file, not JSON
—
Write the unwrapping once, per operation, in one place. Four different wrapper names across eight shapes is the kind of thing that looks fine in a prototype and produces a subtle bug six months later when someone adds a ninth call.
Success codes vary with the request, not just the endpoint
POST /extract returns 200 for a single-type extraction and 202 for a multi-extraction request using documentTypes. POST /generate returns 201. Everything else returns 200.
Treat any 2xx as accepted rather than asserting one specific code.
The processing lifecycle
Pending
Accepted and queued; work has not started
Processing
In flight
Processed
Finished successfully — terminal
Failed
Finished unsuccessfully — terminal
Poll until Processed or Failed. Everything else is transient. Alongside the status, processingStage carries a human-readable progress signal that is useful if you are showing something to a user:
Processed means extraction finished. It does not mean fraud analysis finished — that continues afterwards, and fraudResults.fraudStatus can still read processing at the moment the extraction itself goes terminal. See Reading fraud and control checks.
How long things take
Measured on UAT against a one-page PDF:
POST /extract (accept the job)
~0.6s
POST /classify/sync
~13s
POST /extract/sync
~93s
Extraction is slow because it is doing OCR and model inference, and a longer document takes longer. Set client timeouts well above these figures if you use the synchronous endpoints, and poll no more often than every few seconds — a tight loop will not make the job finish sooner.
Identifiers
_id
The extraction, classification or generation record. This is what you poll with
requestId
The individual API call. Useful when raising a support issue
extractionGroupId
The set, when one file produced several extractions
eventId
A webhook delivery, for idempotency — see Webhook payloads
All are UUIDs.
Usage and cost are on the record
A completed extraction reports what it consumed, which is useful for chargeback or for catching a runaway job:
These fields are not described in any response schema, so treat their exact shape as less stable than the documented fields.
Related pages
Errors — status codes and which failures are worth retrying.
Authentication — the header every request needs.
Extraction API — the full parameter set these conventions apply to.
Extract asynchronously and poll — the envelope trap, in a working example.
Last updated

