Skip to main content
POST
Document AI (custom field extraction + tamper checks)
Send one document and the list of fields you want read from it. Didit runs its default extraction model over the file, returns every field typed (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.
In a multipart request the whole array is one form value:
The response echoes the normalized 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 with is_full_name: true and send who you expect the document to belong to: Send one group or the other, not both. When a name is extracted and an expected name is present, the response includes 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 (default true): the request and its result appear in the Business Console under Manual Checks, where your team can review them. Set it to false to skip saving.
  • vendor_data and metadata are 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.
Need the user to upload the document themselves, collect up to 3 documents in one flow, auto-translate the upload screen, or cross-reference extracted fields against ID or questionnaire data? Use the hosted Document AI workflow step instead.

Authorizations

x-api-key
string
header
required

Body

multipart/form-data
document
file
required

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.

fields
string
required

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.

Example:

"[{\"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}]"

expected_first_name
string

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.

Example:

"Sophia"

expected_last_name
string

Last name to verify against the document's name field, combined with expected_first_name for name_match_score.

Example:

"Martinez"

expected_company_name
string

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).

expected_company_country
string

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.

document_ai_name_match_score_threshold
integer
default:80

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.

Required range: 0 <= x <= 100
Example:

80

document_ai_unreadable_document_action
enum<string>
default:REVIEW

What to do when no field could be read from the document (DOCUMENT_AI_UNREADABLE_DOCUMENT).

Available options:
DECLINE,
REVIEW,
NO_ACTION
document_ai_missing_required_fields_action
enum<string>
default:REVIEW

What to do when at least one required field could not be read (DOCUMENT_AI_MISSING_REQUIRED_FIELDS; additional_data.missing_fields lists them).

Available options:
DECLINE,
REVIEW,
NO_ACTION
document_ai_document_tampering_action
enum<string>
default:DECLINE

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).

Available options:
DECLINE,
REVIEW,
NO_ACTION
document_ai_name_mismatch_action
enum<string>
default:NO_ACTION

What to do when name_match_score is below the threshold (DOCUMENT_AI_NAME_MISMATCH).

Available options:
DECLINE,
REVIEW,
NO_ACTION
document_ai_unsupported_file_action
enum<string>
default:REVIEW

What to do when the upload is empty or not a processable file (DOCUMENT_AI_UNSUPPORTED_FILE).

Available options:
DECLINE,
REVIEW,
NO_ACTION
save_api_request
boolean
default:true

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.

Example:

true

vendor_data
string

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.

Example:

"user-123"

metadata
object

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.

Example:

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.

request_id
string<uuid>

Persisted session id when save_api_request=true (usable with GET /v3/session/{sessionId}/decision/); otherwise a transient correlation UUID.

document_ai
object
vendor_data
string | null

Echo of the vendor_data you sent, or null.

metadata
object | null

Echo of the metadata object you sent, or null.

created_at
string<date-time>

When the request was processed (UTC, ISO 8601).