Requests & documents
A Request is one OCR job — a batch of files uploaded into a single session, processed against one document type or custom schema. Each file/page in the request becomes a Document with its own status, confidence, and extracted JSON.
You key downstream pipelines against request_id (for the whole batch)
or document_id (for the page). Both IDs are stable and idempotent.
Anatomy of a request
{
"id": "req_3fa1c4e2b9d1", // request_id — stable
"merchant_id": "merchant_abc123",
"name": "AP batch 04/2026", // human label, freeform
"session_id": "f47ac10b-58cc-4372",
"document_type": "trade_invoice_jp",
"status": "processing", // queued | processing | success | failed | partial
"total_images": 240,
"success_images": 217,
"failed_images": 3,
"created_at": "2026-04-30T03:18:02Z",
"completed_at": null
}Anatomy of a document
{
"id": "doc_8a7c2e0fa912", // document_id — stable
"request_id": "req_3fa1c4e2b9d1",
"status": "completed", // queued | llm_processing | completed | failed | rejected | confirmed
"document_type": "trade_invoice_jp",
"source_url": "https://.../sakura_t1234.pdf",
"fields": {
"vendor": "株式会社サクラ商事",
"t_number": "T1234567890123",
"t_number_valid": true, // verified live against NTA
"issue_date": "2026-04-30",
"total": "¥495,800",
"tax_10_amount": "¥45,000",
"tax_8_amount": "¥8,800"
},
"confidence": {
"vendor": 0.99,
"t_number": 0.99,
"total": 0.99,
"tax_10_amount": 0.98,
"tax_8_amount": 0.97
},
"created_at": "2026-04-30T03:18:02Z",
"completed_at": "2026-04-30T03:18:06Z"
}State machine
┌──────────────┐
upload │ │ LLM fail / timeout
─────────▶│ queued ├────────────────────┐
│ │ │
└──────┬───────┘ │
│ worker picks up ▼
▼ ┌──────────┐
┌──────────────┐ │ failed │
│llm_processing│ │ (retry) │
└──────┬───────┘ └────┬─────┘
│ extracted │
▼ │
┌──────────────┐ reject by LLM │
│ completed │◀───────────────────┘
└──────┬───────┘ (low confidence,
│ wrong doc type)
human review (optional)
│
▼
┌──────────────┐
│ confirmed │
└──────────────┘queued→llm_processing→completedis the happy pathfailedis automatically retried (default 3 attempts with exponential backoff)rejectedis what the LLM returns when it can’t extract — never billedconfirmedis set when an operator clicks Approve in the correction UI (or via the confirmation API)
Retry semantics
You can re-run a single document or the whole request:
| Endpoint | Effect |
|---|---|
POST /api/v1/ocr/documents/{id}/retry | Re-run one page (idempotent) |
POST /api/v1/ocr/requests/{id}/retry | Replay every failed/rejected page in batch |
Retries are billed exactly once per successful extraction — failed retries don’t accrue.
For the canonical event names emitted as a request moves through these states, see Webhooks → Overview.