For the complete documentation index, see llms.txt. This page is also available as Markdown.

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:

Property
Use when
Trade-off

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:

Property
Use when

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.

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 data on submit and extraction on retrieve.

  • The job status is documentStatus on submit and status on retrieve.

  • The retrieve response has two status fields at different levels.

And it is not one pattern with one exception — the wrapper differs per operation. The full set:

Operation
Wrapper
Job status at

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}

extractionskeyed by documentType

per child

POST /generate/sync

none — binary file, not JSON

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

Status
Meaning

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:

How long things take

Measured on UAT against a one-page PDF:

Operation
Observed

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

Field
What it identifies

_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.

Last updated