ID Verification API
OCR an identity document and run document fraud checks in one call — returns the extracted holder fields, the parsed MRZ, an Approved/Declined status, and a warnings list explaining every issue found. Supports 14,000+ document types from 220+ countries and territories.
How it works. Send the document’s front_image (required) and, for two-sided documents, the back_image. Upload uncropped photos with all four corners of the document visible — the service detects, aligns, and crops the document itself, so do not pre-crop. The document is classified automatically (you never declare the country or document type), the visual zone is read with OCR, and the MRZ and any barcodes are decoded. Cross-checks then validate dates, number formats, and MRZ check digits, and compare the visual zone against the MRZ. With perform_document_liveness=true, the images are additionally screened for screen replays, printed copies, and portrait manipulation.
Decision logic. status is Approved unless at least one warning resolves to a decline. Fraud and hard-failure risks always decline: DOCUMENT_EXPIRED, SCREEN_CAPTURE_DETECTED, PRINTED_COPY_DETECTED, PORTRAIT_MANIPULATION_DETECTED, plus extraction failures (NAME_NOT_DETECTED, DATE_OF_BIRTH_NOT_DETECTED, DOCUMENT_NUMBER_NOT_DETECTED). (PORTRAIT_IMAGE_NOT_DETECTED, COULD_NOT_DETECT_DOCUMENT_TYPE, INVALID_DATE, and MRZ_NOT_DETECTED exist in workflow sessions but are never produced by this standalone endpoint.) Three risk groups are configurable per request via invalid_mrz_action, inconsistent_data_action, and expiration_date_not_detected_action (DECLINE or NO_ACTION). All other warnings (e.g. POSSIBLE_DUPLICATED_USER) are informational and never decline on their own. A document that cannot be processed at all returns 400 with {"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}; a readable but problematic document returns 200 with status: "Declined" — always inspect id_verification.status and id_verification.warnings, not just the HTTP code.
Billing. Each 200 response consumes one ID Verification API credit (standalone APIs have no free tier). When the organization’s balance cannot cover the call, the endpoint returns 403 with the not-enough-credits error before any image processing.
Session persistence (save_api_request, default true). When true, the call is persisted as an API-type session: it appears in the Business Console, the returned request_id is a real session id you can pass to GET /v3/session/{sessionId}/decision/, the cropped document/portrait images are stored and returned as short-lived media URLs (https://<media-host>/ocr/...), and a status.updated webhook is emitted to your configured webhook endpoints. When false, nothing is stored, request_id is a one-off correlation UUID, and portrait_image/front_image/back_image are returned inline as base64-encoded JPEG strings.
Sandbox. Sandbox API keys skip all processing and billing: after request validation (malformed input still returns 400), the endpoint returns a static Approved mock payload (a fictional “Sandbox User” USA identity card), no session is persisted, and no credits are consumed.
Authentication. Send your application’s API key in the x-api-key header. Missing or invalid credentials return 403 ({"detail": "You do not have permission to perform this action."}) — this API never returns 401.
Rate limit. Shared write budget of 300 requests/min per API key across all POST/PATCH/DELETE endpoints; exceeding it returns 429.
Authorizations
Body
Front side of the identity document. Allowed extensions: tiff, jpg, jpeg, png, webp, pdf. Maximum upload size: 10 MB (larger files are rejected with 400). PDFs are rendered to an image before OCR; encrypted PDFs require front_image_password. Images are automatically compressed to ~0.5 MB and EXIF orientation is applied. Upload the full, uncropped capture with all four corners of the document visible.
Password to decrypt front_image when it is an encrypted PDF. Sending an encrypted PDF without (or with a wrong) password returns 400.
Back side of the document — send it whenever the document has one (many ID cards carry the MRZ or a barcode on the back; omitting it simply leaves the MRZ and back-side fields empty in the response — this endpoint does not raise a missing-MRZ warning). Same format and size limits as front_image. When omitted, back_image and back-side fields are null in the response.
Password to decrypt back_image when it is an encrypted PDF.
When true, also screens both images for presentation fraud: screen replays (SCREEN_CAPTURE_DETECTED), printed copies (PRINTED_COPY_DETECTED), and portrait manipulation (PORTRAIT_MANIPULATION_DETECTED). Any of these auto-declines. Adds latency, so enable it only when you need fraud screening.
true
Accepted and validated (1–120) but currently not applied by this endpoint — it never produces a MINIMUM_AGE_NOT_MET warning from this field. Enforce age rules from the returned date_of_birth/age, or use a verification-session workflow with age restrictions.
1 <= x <= 120What to do when no expiration date can be read (EXPIRATION_DATE_NOT_DETECTED). Default NO_ACTION because many identity documents print no expiry date. Note: a detected and past expiry date always declines (DOCUMENT_EXPIRED), regardless of this option.
NO_ACTION, DECLINE What to do when the extracted MRZ fails check-digit validation (MRZ_VALIDATION_FAILED). A missing MRZ raises no warning on this endpoint. Only relevant for documents that carry an MRZ. REVIEW is not supported on this endpoint and returns 400.
NO_ACTION, DECLINE What to do when extracted data is internally inconsistent: DATA_INCONSISTENT, MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME (visual zone disagrees with the MRZ), or DOCUMENT_NAME_DIFFERENT_FROM_OTHER_APPROVED_DOCUMENTS.
NO_ACTION, DECLINE Preferred script for name/address fields on documents that print both Latin and non-Latin text (Arabic, Cyrillic, CJK, …). latin returns transliterated/Latin values; non_latin prefers the native script.
latin, non_latin 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, announced through a status.updated webhook, and with document images returned as media URLs. When false, nothing is stored, request_id is a transient UUID, and images are returned inline as base64 JPEG strings.
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.
{ "flow": "onboarding" }Response
Document processed. id_verification.status is Approved or Declined; every detected issue is itemized in id_verification.warnings. A problematic document still returns 200 with status: "Declined" — inspect the body, not just the HTTP code. When save_api_request=true, request_id is the persisted session id and image fields are short-lived media URLs; with save_api_request=false they are inline base64 JPEG strings.
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.
ISO 8601 timestamp (UTC) of when the response was generated.