Document AI API
Extract the fields you define from any supporting document — payslips, proof of funds, source-of-wealth letters, tax statements, contracts, invoices — in one call. Send the file plus a fields definition (key, name, extraction instruction, type) and get back typed values (text, number, date as YYYY-MM-DD), an optional name-match score against the expected person or company, PDF/EXIF tamper signals, an Approved/Declined/In Review status, and a warnings list explaining every issue found. This is the server-to-server counterpart of the hosted Document AI workflow step (see /core-technology/document-ai/overview); it uses Didit’s default extraction model and does not expose provider selection.
Latency. Extraction is LLM-based: typical calls take 5–15 seconds, multi-page PDFs up to ~30 seconds. Configure a client timeout of at least 45 seconds and do not retry before the call completes.
Request format. multipart/form-data only. fields is one JSON-encoded array string (1–30 items, at most 16 KB); bracket-style form arrays are rejected with 400. Each item is {key, name, instruction, type, required, is_full_name} — key is the JSON key you get back (^[a-z0-9_]{1,64}$, unique), instruction tells the model what to read, type is text (default) | number | date, required raises DOCUMENT_AI_MISSING_REQUIRED_FIELDS when the value cannot be read, and at most one field may set is_full_name: true to mark the value compared against the expected name.
Name matching. Pass expected_first_name + expected_last_name (person) or expected_company_name (+ optional expected_company_country) — not both. The value of the is_full_name field (or, when none is marked, the first text field whose key looks like a name) is compared fuzzily; name_match_score (0–100) and name_on_document are always returned when both sides exist, and a score below document_ai_name_match_score_threshold (default 80) adds DOCUMENT_AI_NAME_MISMATCH, governed by document_ai_name_mismatch_action.
Decision logic. Each risk maps to a configurable action: DECLINE → status: "Declined", REVIEW → status: "In Review", NO_ACTION → informational only. Defaults mirror the workflow step: unreadable document REVIEW, missing required fields REVIEW, suspected manipulation DECLINE, name mismatch NO_ACTION, unsupported file REVIEW. A document that cannot be processed at all returns 400; a readable but problematic document returns 200 with Declined/In Review — always inspect document_ai.status and document_ai.warnings, not just the HTTP code.
Billing. Each 200 response consumes one Document AI API credit — $0.20 per document, no free tier (standalone APIs never have one). When the organization’s balance cannot cover the call, the endpoint returns 403 before any processing. Sandbox API keys return a deterministic mock response and are not charged.
Persistence. With save_api_request=true (default) the call is stored as an API-type session: the document, the extracted values, the field definitions and the name-match snapshot are kept, the session shows up in the Business Console, and request_id works with GET /v3/session/{sessionId}/decision/.
text, number, or date as YYYY-MM-DD), checks the file for manipulation, and optionally compares the name on the document against the person or company you expect. Use it for proof of funds, payslips, bank statements, tax documents, invoices, or any document that does not fit a fixed template.
This is the server-to-server version of the hosted Document AI step. The request is multipart/form-data: the file goes in document, and the field definitions go in fields as one JSON-encoded array string.
Define the fields to extract
fields is a JSON array of 1 to 30 items, sent as a single string. Each item has a key (lowercase letters, digits, and underscores, unique within the request), a human-readable name, an instruction that tells the model what to look for, a type (text, number, or date), and two flags: required and is_full_name.
fields and returns extracted_data keyed by your key values, with null for anything the model could not find. name, instruction, and type are optional on each item (type defaults to text); key is required. Sending fields as bracket-style form keys (fields[0][key]=...) or as anything other than a JSON array returns 400 before any extraction runs, so nothing is billed.
Name matching
Mark at most one field withis_full_name: true and send who you expect the document to belong to:
name_match_score (0 to 100) and name_on_document. A score below document_ai_name_match_score_threshold (default 80) raises the DOCUMENT_AI_NAME_MISMATCH warning and applies document_ai_name_mismatch_action. If no field is marked is_full_name, Didit falls back to the first text field whose key looks like a name (name, holder, full_name, account_holder); mark the field explicitly when you want to control which value is compared. When no name value can be found on the document, or no expected name is sent, the name check is skipped and name_match_score is null.
Risks and actions
Each risk below maps to an action parameter you can set per request:DECLINE, REVIEW, or NO_ACTION. The strictest triggered action decides document_ai.status (Declined > In Review > Approved), and every triggered risk is listed in document_ai.warnings. The defaults match the hosted workflow step; see Document AI rules & warnings for how each risk is detected.
Files, saving, and billing
- Accepted files: PDF (multi-page supported), JPG, JPEG, PNG, TIFF, WebP, or a ZIP containing the document, up to 30 MB. Encrypted PDFs return
400; upload a decrypted PDF or a photo instead. save_api_request(defaulttrue): the request and its result appear in the Business Console under Manual Checks, where your team can review them. Set it tofalseto skip saving.vendor_dataandmetadataare returned unchanged in the response so you can link the result to your own records.- Price: $0.20 per document, billed when the document is processed and a status is returned. Standalone APIs do not include the free monthly workflow tier. See Pricing.
Authorizations
Body
The document to read. Allowed extensions: tiff, jpg, jpeg, png, pdf, webp, zip. Maximum upload size: 30 MB (larger files are rejected with 400). Multi-page PDFs are supported (expect higher latency); encrypted PDFs are rejected with 400. Images are automatically compressed before processing.
One JSON-encoded array string with 1–30 field definitions (maximum 16 KB). Each item: key (required, ^[a-z0-9_]{1,64}$, unique — the key returned in extracted_data), name (≤100 chars, shown in messages), instruction (≤500 chars, what the model should read), type (text default | number | date), required (boolean, default false), is_full_name (boolean, default false, at most one per request). Bracket-style form arrays, invalid JSON, duplicate keys, or more than one is_full_name return 400 before any processing or billing.
"[{\"key\": \"employer_name\", \"name\": \"Employer name\", \"instruction\": \"The employer or company issuing the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": false}, {\"key\": \"employee_name\", \"name\": \"Employee name\", \"instruction\": \"The full name of the employee as printed on the payslip.\", \"type\": \"text\", \"required\": true, \"is_full_name\": true}, {\"key\": \"net_pay\", \"name\": \"Net pay\", \"instruction\": \"The net amount paid to the employee for the period.\", \"type\": \"number\", \"required\": true, \"is_full_name\": false}, {\"key\": \"pay_date\", \"name\": \"Pay date\", \"instruction\": \"The payment date shown on the payslip.\", \"type\": \"date\", \"required\": false, \"is_full_name\": false}]"
First name to verify against the document's name field (fuzzy match, transliteration-aware). Use together with expected_last_name; cannot be combined with expected_company_name.
"Sophia"
Last name to verify against the document's name field, combined with expected_first_name for name_match_score.
"Martinez"
Company name to verify against the document's name field (for business documents). Cannot be combined with expected_first_name / expected_last_name (no example value on purpose — the generated request sample uses the person fields; swap them for this one when verifying a business document).
Optional ISO 3166-1 alpha-2 country code (two ASCII letters, e.g. FR) that tunes company-name normalization for expected_company_name. Only used with expected_company_name.
Minimum name_match_score (0–100) to consider the name matched. A lower score adds DOCUMENT_AI_NAME_MISMATCH, governed by document_ai_name_mismatch_action.
0 <= x <= 10080
What to do when no field could be read from the document (DOCUMENT_AI_UNREADABLE_DOCUMENT).
DECLINE, REVIEW, NO_ACTION What to do when at least one required field could not be read (DOCUMENT_AI_MISSING_REQUIRED_FIELDS; additional_data.missing_fields lists them).
DECLINE, REVIEW, NO_ACTION What to do when PDF/EXIF forensics suspect manipulation — modified after digital signing, known PDF editor, overlay-text manipulation, suspicious re-export, image anomalies (DOCUMENT_AI_SUSPECTED_MANIPULATION).
DECLINE, REVIEW, NO_ACTION What to do when name_match_score is below the threshold (DOCUMENT_AI_NAME_MISMATCH).
DECLINE, REVIEW, NO_ACTION What to do when the upload is empty or not a processable file (DOCUMENT_AI_UNSUPPORTED_FILE).
DECLINE, REVIEW, NO_ACTION When true (default), persists the call as an API-type session — visible in the Business Console, retrievable via GET /v3/session/{sessionId}/decision/ using the returned request_id, with the uploaded document, the extracted values, the field definitions and the name-match snapshot stored. When false, nothing is stored and request_id is a transient UUID for response correlation only; the call is still billed.
true
Optional opaque string (your internal user id, email, UUID…) stored on the persisted session and echoed back in the response. Use it to correlate API calls with your own records and to filter sessions later.
"user-123"
Optional JSON object stored with the session (when save_api_request=true) and echoed back in the response. In multipart requests, send it as a JSON-encoded string field (e.g. metadata={"flow":"onboarding"}) — it is parsed into an object.
Response
Document processed. document_ai.status is Approved, Declined, or In Review; every detected issue is itemized in document_ai.warnings. A problematic document still returns 200 — inspect the body, not just the HTTP code. When save_api_request=true, request_id is the persisted session id.
Persisted session id when save_api_request=true (usable with GET /v3/session/{sessionId}/decision/); otherwise a transient correlation UUID.
Echo of the vendor_data you sent, or null.
Echo of the metadata object you sent, or null.
When the request was processed (UTC, ISO 8601).