Idempotency
Retry extract without a second charge using Idempotency-Key. GET routes are always safe to retry.
Send Idempotency-Key on extract writes so a retry returns the first result instead of charging again.
Idempotency-Key
Supported on:
POST /extractPOST /uploadPOST /extract/batch
Rules:
- Scope is org + key. A key used by org A does not affect org B.
- Value: 1-256 printable ASCII characters, no spaces.
- TTL: 24 hours. After that the same key starts a new extract.
- Same key + same request (file bytes, mode, schema, prompts, pages) within 24h: replay the stored response. No second charge.
- Same key + different request body within 24h: 409
IDEMPOTENCY_KEY_REUSED. - Same key while the first request is still running (up to 15 minutes): 409
IDEMPOTENCY_IN_PROGRESS. Wait, then retry the same key. - Header with no org (anonymous): 401.
- Client errors such as 402 (insufficient credits) are not locked to the key. Top up and retry with the same key.
MCP: pass idempotency_key on extract / extract_batch. The server sends it as this header.
curl -X POST "$API/api/v1/extract" \
-H "Authorization: Bearer docai_sk_live_..." \
-H "Idempotency-Key: le-2026-08-27-001" \
-F "file=@doc.pdf" \
-F "extract_tier=plus"Safe to retry (read)
These are GETs. Retry freely, with or without a key:
GET /jobs/{job_id}GET /batches/{batch_id}GET /billing/usageGET /billing/catalogGET /orgGET /org/api-keysGET /org/schemasGET /historyGET /health
Other writes (not covered by the header)
| Endpoint | Retry risk |
|---|---|
POST /billing/checkout | May create a new checkout session |
POST /org/api-keys | Creates another key |
PATCH /org | Last write wins |
DELETE … | Second call may 404 |
Recommended client pattern
- Generate a key per logical extract (UUID or your order id). Send it on every attempt of that extract.
- On timeout after
POST /extract, retry with the same key. Do not mint a new key. - On 409
IDEMPOTENCY_IN_PROGRESS, wait a few seconds and retry the same key. - On 409
IDEMPOTENCY_KEY_REUSED, you reused a key for a different file or options. Use a new key. - For batch: store
batch_idfrom the first accepted response and pollGET /batches/{id}. The submit itself is covered by the header. - On 429, wait
retry_after_secondsthen retry with the same key. - On 402, top up credits, then retry with the same key.