API Extract
API

Extract

On this page

Request body

POST /v1/extract GA

One call runs the whole extraction and returns the result in the response. The sync path accepts up to 20 pages; a longer document returns document_too_large. Send it to async jobs instead; the request body is identical.

schema object required
A JSON Schema object describing the output you want. The SDKs accept either this or a Zod/Pydantic model (which they compile to it).
document object required
Exactly one of bytes_base64 (inline, up to 20 MiB) or upload_key (a staged object from `POST /v1/uploads`, up to 50 MiB).
options.doc_class string optional
Opaque tag, echoed back as meta.doc_class. Longer values are truncated to 128 characters.
options.hints object optional
Extraction hints. The SDKs produce these for discriminated unions.

Response

data is the extracted object in the shape of your schema; parse it with your own schema.parse(). fields reports every schema leaf, keyed by RFC 6901 JSON Pointer. meta describes the run.

200 response
{
"data": {
"invoice_number": "INV-2041",
"total": 4210.55,
"currency": "USD"
},
"fields": {
"/invoice_number": {
"state": "present",
"reason": null,
"value": "INV-2041",
"confidence": 0.93,
"anchor": {
"page": 1,
"bbox": [72.0, 96.4, 188.2, 110.1],
"snippet": "Invoice no. INV-2041",
"page_dims": { "width": 612, "height": 792 }
},
"grounding": "verified"
},
"/total": {
"state": "present",
"reason": null,
"value": 4210.55,
"confidence": 0.89,
"anchor": {
"page": 2,
"bbox": [451.0, 700.2, 512.4, 714.0],
"snippet": "Total due $4,210.55",
"page_dims": { "width": 612, "height": 792 }
},
"grounding": "verified"
},
"/currency": {
"state": "present",
"reason": null,
"value": "USD",
"grounding": "ungrounded"
}
},
"meta": {
"model": "gemini-2.5-flash",
"tier": "default",
"batched": false,
"calibrator_version": "cal-2026.08-4",
"routing_policy_version": "dp-sel-1",
"pages": 2,
"billed_pages": 2,
"request_id": "req_a1b2c3…",
"warnings": []
}
}

Field entries

state "present" | "null" | "missing"
A field that cannot be extracted comes back "missing" with a reason, inside a 200. Field failure is not a request error.
reason string | null
Always on the wire: the stable cause when state is "missing" (for example not_found), null otherwise.
value any optional
Present only when state is "present".
confidence number optional
A calibrated score in [0, 1]. Not every field carries one. Measured behavior per calibrator version is published at /reliability.
anchor object optional
Where the value came from: page, bbox as [x0, y0, x1, y1] in page_dims units, and the matched snippet. Absent when the value has no match on the page.
conflict boolean optional
Set when extraction passes disagreed on this field. Route it to review together with missing fields.
grounding "verified" | "cited" | "ungrounded"
On every "present" field. "verified": the value ink itself was located within the cited region. "cited": an anchor is attached but the value was not confirmed there (partial or unconfirmed match). "ungrounded": no accepted span.
a missing field
"/po_number": { "state": "missing", "reason": "not_found" }

Response meta

meta.calibrator_version string
Names the calibrator that produced the confidence scores. Match it against the published curves at /reliability.
meta.billed_pages integer
What the request cost. A failed extraction (422) bills 0.
meta.pages integer
Page count of the parsed document.
meta.request_id string
Names this request. Include it when reporting an issue.
meta.doc_class string optional
Echoed only when the request carried options.doc_class.

meta also carries the run internals: model, tier, batched and routing_policy_version. Log the whole block with the result.

meta.warnings is experimental: the element shape is not specified yet and the array is currently always []. Ignore entries you do not recognize.

Idempotency

POST /v1/extract and POST /v1/jobs accept an Idempotency-Key header: any string up to 255 characters that names one logical request. Retrying with the same key and body is safe; it can never run or bill twice.

Replay
For 24 hours after a success, a request with the same key and body returns the stored original response instead of running again.
Conflict
The same key with a different body, or while the first request is still running, returns 409 idempotency_key_conflict. Do not retry a 409; it is a deterministic answer.
Failures
Only successes are stored. After a non-success response the key is free to retry.
SDKs
Both SDKs attach a generated key per logical request and reuse it across their automatic retries; pass your own to span retries you manage yourself.