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

Extract asynchronously and poll

Submit without holding a connection open, then collect the result.

Goal. Submit a document, get an ID back immediately, and collect the result when it is ready — without a 90-second connection hanging open.

This is the pattern most production integrations use. The request body is identical to the synchronous quickstart; only the URL and the retrieval change.

Generated endpoint reference

Use Extract document data asynchronously to submit the job. Use Get extraction details to retrieve it.

Before you start

  • An API key, exported as $DOCAI_API_KEY.

  • Somewhere to keep the returned ID between the submit and the poll.

Step 1 — Submit the job

Drop /sync from the URL. Everything else stays the same.

curl -X POST "https://api-docai-uat.uptiq.ai/extract" \
  -H "X-Api-Key: $DOCAI_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @request.json

It returns in well under a second:

{
  "data": {
    "_id": "3f2a91c4-7b58-4e12-9d63-0a5e8c1b74df",
    "documentStatus": "Pending",
    "documentType": "BalanceSheet",
    "requestId": "a7d0e514-63b2-4f97-8c05-1d4f9b28e3a6",
    "subtype": null
  },
  "message": "Document queued for extraction",
  "status": "success"
}

Keep data._id. That is what you poll with.

This returns 200, not the 202 Accepted you might expect for queued work — 200 here means accepted, not finished, and documentStatus is Pending.

The same endpoint returns 202 when you send documentTypes for a multi-extraction instead of a single documentType. The code varies with the request, not just the endpoint, so accept any 2xx rather than testing for one value.

Step 2 — Understand the retrieval shape before you write the loop

This is where first attempts go wrong, so it is worth reading the response carefully before writing any code against it.

Compare that with what you submitted, because two things changed:

Submit response
Retrieve response

Wrapper

data

extraction

Job status field

documentStatus

status

The field you want is extraction.status.

Step 3 — Poll until terminal

Pending and Processing are transient; Processed and Failed are terminal. Poll every 5–10 seconds — a tighter loop will not make the job finish sooner, and extraction takes on the order of 90 seconds per page.

Give the loop a hard iteration cap so a stuck job cannot spin indefinitely.

Step 4 — Show progress while you wait

If a person is watching, processingStage is more useful than the raw status:

Step 5 — Read the result

Once extraction.status is Processed, the payload is under extraction.result and has the same shape the synchronous endpoint returns:

The asynchronous record carries more than the synchronous response does — every parameter the job ran with (model, enableCaching, processorId), plus creditReservation, webhookStatus and fraudResults. See Reading fraud and control checks for the last of those.

When it goes wrong

Symptom
Cause
Fix

Loop never exits, status always success

Reading the top-level status

Read extraction.status

404 right after submitting

Polled before the record was visible

Wait a second and retry; treat an early 404 as transient only here

Stuck on Processing

Long or complex document

Cap your attempts and alert; check processingStage.message

status: Failed

The document could not be processed

Inspect result.documentQuality; do not blindly resubmit

Stop polling altogether

Polling is the simple option, not the efficient one. If you control a public HTTPS endpoint, an event-driven pipeline removes the loop entirely — the platform posts to you when the job lands.

Last updated