Docs
2D-DOC / VDS

Asynchronous processing

Queue a scan or a comparison, then poll the job or receive a webhook

A scan or a comparison reads every page of the file and, for a comparison, reads each page holding a code by OCR. A file of several pages takes tens of seconds, longer than many HTTP clients and proxies wait. Ask for an asynchronous answer instead: the API queues the work, answers 202 at once with a job, and you read the result when it is ready.

The synchronous call stays the default: without the preference, nothing changes.

Request

Send the same request as for POST /2ddoc/scan or POST /2ddoc/compare, with the Prefer header (RFC 7240):

POST /2ddoc/compare
Authorization: Bearer oat_your_key
Prefer: respond-async
Content-Type: multipart/form-data

file: <PDF or image file>

The form field async=true does the same, for clients that cannot set a header.

HTTP/1.1 202 Accepted
Location: /2ddoc/jobs/tdj_adbae78350ca4f80bf5857436722635c
Preference-Applied: respond-async
{
  "id": "tdj_adbae78350ca4f80bf5857436722635c",
  "kind": "compare",
  "status": "queued",
  "step": null,
  "document": null,
  "createdAt": "2026-10-22T19:54:15.120Z",
  "updatedAt": "2026-10-22T19:54:15.120Z",
  "finishedAt": null,
  "error": null,
  "result": null,
  "resultAvailableUntil": null,
  "statusUrl": "/2ddoc/jobs/tdj_adbae78350ca4f80bf5857436722635c"
}

An organization may have 20 jobs queued or running at once; past that, the API answers 429.

Calls made with an SDK token are always answered synchronously, as RFC 7240 lets a server ignore the preference: the app receives its verdict on the response.

Following a job

GET /2ddoc/jobs/{id}
Authorization: Bearer oat_your_key
FieldDescription
statusqueued, running, done or failed
stepWhile running: scanning, verifying or comparing
documentWhile running, in a file of several codes: the one being handled, { "index": 2, "total": 3, "page": 4 }
resultOnce done: the response body the synchronous call would have returned, unchanged
errorOnce failed: a generic reason, never a value of the document
resultAvailableUntilThe job and its result are readable 15 minutes after the end, then deleted

While the job runs, the response carries Retry-After: 2. A job belongs to the organization that created it: any other key gets 404.

Webhook

When a job ends, the API posts twoddoc.job.completed to the organization's verification webhook, the endpoint set for the mobile SDK (same signature X-Webhook-Signature: v1=HMAC-SHA256(secret, "<timestamp>.<body>"), same retries). See native SDK, webhook.

{
  "id": "5f0b6c1e-0c49-4d6e-9a2b-1f6f3d1c8e21",
  "type": "twoddoc.job.completed",
  "timestamp": "2026-10-22T19:54:22.640Z",
  "data": {
    "jobId": "tdj_adbae78350ca4f80bf5857436722635c",
    "kind": "compare",
    "status": "done",
    "documents": [
      { "page": 1, "status": "valid", "documentType": "Avis d'impôt sur les Revenus (V2)", "altered": true, "confidence": 0 }
    ],
    "resultAvailableUntil": "2026-10-22T20:09:22.624Z"
  }
}

The webhook carries no value read from the document: per code, its page, its signature status and, for a comparison, whether the page contradicts it. Read the fields from GET /2ddoc/jobs/{id} with your key.

Data

The file is kept in memory until the job has run, and at most 30 minutes; the result 15 minutes after the end. Each 2D-DOC verified counts as one verification, as for the synchronous call.