mcpField
D
didit-id-document-verification

didit-id-document-verification

github.com/didit-protocolSecurity29266 installsUpdated 2w ago
Repository

About didit-id-document-verification

A skill for calling Didit's ID Verification API with document images or PDFs. Developers can use it to classify identity documents, extract fields, validate document data, and receive an approval status with warnings.

Key features

  1. 01Automatic document classification
  2. 02OCR, MRZ, and barcode extraction
  3. 03Cross-check dates and number formats
  4. 04Screen for replay and image manipulation
  5. 05Return extracted fields and warnings

Use cases

  1. 01Verify identity documents from submitted images
  2. 02Extract document details for an application
  3. 03Check document validity before onboarding

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/didit-protocol/skills --skill didit-id-document-verification

After installing, type/didit-id-document-verificationin Claude Code to confirm it loaded.

Bundled filesscripts/verify_id.py

Details

From the project README

Didit ID Verification API

Overview

Verifies an identity document from images (or PDFs) of its front and back in one synchronous call. Classifies the document automatically (you never declare the country or type), reads the visual zone with OCR, decodes the MRZ and barcodes, cross-checks dates, number formats and MRZ check digits, and by default screens both images for screen replays, printed copies and portrait manipulation. Returns the extracted fields, an Approved or Declined status and a warnings list.

Key constraints:

  • Formats: JPEG, PNG, WebP, TIFF or PDF (extensions jpg, jpeg, png, webp, tiff, pdf). Encrypted PDFs need front_image_password / back_image_password
  • Maximum upload size: 10 MB per side (larger files get 400). Images are compressed server-side
  • Send the full, uncropped capture with all four corners visible; the service detects, aligns and crops the document itself
  • Send back_image whenever the document has a back: many ID cards carry the MRZ or barcode there, and a missing back leaves those fields empty without a warning

Coverage: 14,000+ document types from 220+ countries and territories: passports, national ID cards, driver's licenses, residence permits and more.

Pricing: $0.20 per call that returns 200 (Approved or Declined); 400 responses are not billed, and standalone calls have no free tier. These are the list prices until 1 November 2026, when Didit pricing changes and the 500 free checks a month become $10 of free credit a month. Check didit.me/pricing for current prices. Digital ID wallets are billed separately (see Digital ID Wallets).

Sandbox: sandbox API keys skip processing and billing and return a static Approved mock (a fictional "Sandbox User" USA identity card) after request validation. Nothing is stored.

API Reference: https://docs.didit.me/standalone-apis/id-verification Feature Guide: https://docs.didit.me/core-technology/id-verification/overview Warnings: https://docs.didit.me/core-technology/id-verification/warnings-id-verification Supported Documents: https://docs.didit.me/core-technology/id-verification/supported-documents-id-verification


Authentication

Every request needs the x-api-key header. Use your application's API key from the Didit Business Console under Developers > API keys, or create an account and key programmatically (see Getting Started). Named keys with custom access need Sessions write to run standalone checks; a key limited to some workflows or to approved sessions cannot run them.

Getting Started (No Account Yet?)

If you don't have a Didit API key, create one in 2 API calls:

  1. Register: POST https://apx.didit.me/auth/v2/programmatic/register/ with {"email": "[email protected]", "password": "MyStr0ng!Pass"}
  2. Check email for a 6-character verification code
  3. Verify: POST https://apx.didit.me/auth/v2/programmatic/verify-email/ with {"email": "[email protected]", "code": "A3K9F2"}. The key is in the response at application.api_key.

To add credits: GET /v3/billing/balance/ to check, POST /v3/billing/top-up/ with {"amount_in_dollars": 50} for a Stripe checkout link.

See the didit-verification-management skill for full platform management (workflows, sessions, users, billing).


Endpoint

POST https://verification.didit.me/v3/id-verification/
Headers
HeaderValueRequired
x-api-keyYour API keyYes
Content-Typemultipart/form-data (set by your HTTP client)Yes
Request Parameters (multipart/form-data)
ParameterTypeRequiredDefaultDescription
front_imagefileYes-Front of the document. JPEG/PNG/WebP/TIFF/PDF, max 10 MB
front_image_passwordstringNo-Password of an encrypted front_image PDF
back_imagefileNo-Back of the document. Same formats and limit
back_image_passwordstringNo-Password of an encrypted back_image PDF
perform_document_livenessbooleanNotrueScreen both images for screen capture, printed copy and portrait manipulation. Any hit declines. false skips it and lowers latency
invalid_mrz_actionstringNoDECLINEDECLINE or NO_ACTION for MRZ_VALIDATION_FAILED
inconsistent_data_actionstringNoDECLINEDECLINE or NO_ACTION for DATA_INCONSISTENT and MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME
expiration_date_not_detected_actionstringNoNO_ACTIONDECLINE or NO_ACTION for EXPIRATION_DATE_NOT_DETECTED (many documents print no expiry). A detected past expiry always declines
critical_field_occlusion_actionstringNoDECLINEDECLINE or NO_ACTION for CRITICAL_FIELD_OCCLUSION_DETECTED
document_or_personal_number_format_mismatch_actionstringNoNO_ACTIONDECLINE or NO_ACTION for DOCUMENT_NUMBER_FORMAT_MISMATCH and PERSONAL_NUMBER_FORMAT_MISMATCH
preferred_charactersstringNolatinlatin or non_latin: which script to return for names and addresses on documents that print both
save_api_requestbooleanNotruetrue: store the call as a session (see below). false: store nothing
vendor_datastringNo-Your identifier for the user, echoed back and stored on the session
metadataJSON objectNo-Send as a JSON-encoded string field (e.g. {"flow":"onboarding"}); echoed back and stored on the session

Action fields accept only DECLINE or NO_ACTION; REVIEW returns 400. minimum_age is accepted but not applied by this endpoint: enforce age rules from the returned date_of_birth / age, or use a workflow with age restrictions.

save_api_request=true (default): the call is stored as an API session, visible in the Business Console. request_id is a real session id usable with GET /v3/session/{sessionId}/decision/, the cropped images come back as short-lived media URLs, and a status.updated webhook is sent to your webhook destinations. false: nothing is stored, request_id is a one-off UUID, and portrait_image, front_image and back_image come back inline as base64 JPEG strings.

Example
import json
import requests

with open("front.jpg", "rb") as front, open("back.jpg", "rb") as back:
    response = requests.post(
        "https://verification.didit.me/v3/id-verification/",
        headers={"x-api-key": "YOUR_API_KEY"},
        files={
            "front_image": ("front.jpg", front, "image/jpeg"),
            "back_image": ("back.jpg", back, "image/jpeg"),
        },
        data={
            "vendor_data": "user-123",
            "perform_document_liveness": "true",
            "metadata": json.dumps({"flow": "onboarding"}),
        },
        timeout=120,
    )

if response.status_code != 200:
    raise SystemExit(f"{response.status_code}: {response.text}")
id_v = response.json()["id_verification"]
print(id_v["status"], id_v.get("full_name"), [w["risk"] for w in id_v["warnings"]])
const formData = new FormData();
formData.append("front_image", frontImageFile);
formData.append("back_image", backImageFile);
formData.append("vendor_data", "user-123");
formData.append("metadata", JSON.stringify({ flow: "onboarding" }));

const response = await fetch("https://verification.didit.me/v3/id-verification/", {
  method: "POST",
  headers: { "x-api-key": "YOUR_API_KEY" },
  body: formData,
});
const body = await response.json();
console.log(body.id_verification.status, body.id_verification.warnings.map((w) => w.risk));
Response (200 OK)

Images are media URLs here because save_api_request was true.

{
  "request_id": "11111111-2222-3333-4444-555555555555",
  "id_verification": {
    "status": "Approved",
    "document_type": "Identity Card",
    "document_subtype": "ID_CARD_GENERIC",
    "document_number": "YZA123456",
    "personal_number": "X9876543L",
    "portrait_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-portrait_image.jpg?signature=...",
    "front_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-front_image.jpg?signature=...",
    "back_image": "https://<media-host>/ocr/11111111-2222-3333-4444-555555555555-back_image.jpg?signature=...",
    "front_image_camera_front": null,
    "back_image_camera_front": null,
    "front_image_camera_front_face_match_score": null,
    "back_image_camera_front_face_match_score": null,
    "front_image_quality_score": {
      "focus_score": 78.0,
      "brightness_score": 83.2,
      "brightness_issue": "ok",
      "is_document_fully_visible": true,
      "resolution_score": 40.7,
      "overall_score": 70.2
    },
    "back_image_quality_score": null,
    "date_of_birth": "1985-03-15",
    "age": 41,
    "expiration_date": "2030-08-21",
    "date_of_issue": "2020-08-21",
    "issuing_state": "ESP",
    "issuing_state_name": "Spain",
    "first_name": "Elena",
    "last_name": "Martinez Sanchez",
    "full_name": "Elena Martinez Sanchez",
    "gender": "F",
    "address": "Calle Mayor 10, Madrid",
    "formatted_address": "Calle Mayor 10, 28013 Madrid, Spain",
    "place_of_birth": "Valencia",
    "marital_status": "UNKNOWN",
    "nationality": "ESP",
    "extra_fields": {"first_surname": "Martinez", "second_surname": "Sanchez"},
    "mrz": {
      "surname": "MARTINEZ SANCHEZ",
      "name": "ELENA",
      "country": "ESP",
      "nationality": "ESP",
      "birth_date": "850315",
      "expiry_date": "300821",
      "sex": "F",
      "document_type": "ID",
      "document_number": "YZA123456",
      "personal_number": "X9876543L",
      "mrz_type": "TD1",
      "warnings": [],
      "errors": []
    },
    "parsed_address": {
      "street_1": "Calle Mayor 10",
      "street_2": null,
      "city": "Madrid",
      "region": "Comunidad de Madrid",
      "postal_code": "28013",
      "country": "ES",
      "formatted_address": "Calle Mayor 10, 28013 Madrid, Spain",
      "is_verified": true
    },
    "warnings": [],
    "barcodes": []
  },
  "vendor_data": "user-123",
  "metadata": {"flow": "onboarding"},
  "created_at": "2026-06-12T02:21:56.013573+00:00"
}

A declined result has the same shape, with "status": "Declined" and the reasons in warnings, for example:

{
  "risk": "DOCUMENT_EXPIRED",
  "feature": "ID_VERIFICATION",
  "additional_data": null,
  "log_type": "error",
  "short_description": "Document expired",
  "long_description": "The document's expiration date has passed, rendering it no longer valid for use."
}
Status Values
StatusMeaning
"Approved"No warning resolved to a decline
"Declined"At least one warning has log_type: "error" (see warnings)

This endpoint never returns In Review. A readable but problematic document still returns HTTP 200 with Declined: always check id_verification.status, not only the HTTP code.

Error Responses
CodeMeaningAction
400Invalid requestRead the field errors in the response body
400{"error": "COULD_NOT_RECOGNIZE_DOCUMENT"}No document found in the image: retake with all four corners visible
400{"detail": "The PDF is encrypted..."} or {"detail": "The PDF password is incorrect..."}Send front_image_password / back_image_password, or a photo
400{"error": "Failed to convert front image PDF."} (or back)Send an image or a valid PDF
401The API key has expiredRotate it or create a new key in Developers > API keys
403Missing, wrong or revoked API key; a scoped key without access to this endpoint; a request from outside the key's IP allowlist; or not enough creditsRead the message in detail or error: fix the x-api-key header or the key's access, or top up
429Rate limit: 300 POST/PATCH/DELETE and 600 GET requests a minute per keyWait the Retry-After seconds, then retry

The credit check runs before the images are processed: an empty balance returns 403 with {"error": "You don't have enough credits to perform this request. ..."}.


Response Field Reference

All fields are inside id_verification unless noted.

FieldTypeDescription
request_id (top level)uuidSession id when save_api_request=true; otherwise a one-off UUID
statusstring"Approved" or "Declined"
document_typestring or null"Passport", "Identity Card", "Driver's License", "Residence Permit", "Health Insurance Card", "Tax Card"; null when the document could not be classified
document_subtypestring or nullFiner subtype, e.g. ID_CARD_GENERIC, EPASSPORT
document_number, personal_numberstring or nullDocument number and secondary personal/national number
first_name, last_name, full_namestring or nullHolder names
date_of_birth, expiration_date, date_of_issuestring or nullYYYY-MM-DD
ageinteger or nullAge computed from date_of_birth
genderstring or null"M", "F" or null
nationality, issuing_statestring or nullISO 3166-1 alpha-3; issuing_state_name is the country name
address, formatted_addressstring or nullAddress as printed, and its geocoded form
parsed_addressobject or nullstreet_1, street_2, city, region, postal_code, country (alpha-2), formatted_address, is_verified, document_location, label, category
place_of_birth, marital_statusstring or nullmarital_status is UNKNOWN unless printed
extra_fieldsobject or nullDocument-specific extras (e.g. first_surname, second_surname)
mrzobjectParsed MRZ: surname, name, country, nationality, birth_date / expiry_date (raw YYMMDD), sex, document_type, document_number, personal_number, optional_data, check digits, mrz_type (TD1/TD2/TD3), mrz_string, errors, warnings. {} when the document has no MRZ or it could not be read
barcodesarrayDecoded barcodes: type (e.g. PDF417, QR_CODE), data, data_raw, side, position
portrait_image, front_image, back_imagestring or nullMedia URL (saved) or base64 JPEG (save_api_request=false); back_image is null without a back upload
front_image_quality_score, back_image_quality_scoreobject or nullfocus_score, brightness_score, brightness_issue, is_document_fully_visible, resolution_score, overall_score (0-100)
front_image_camera_front, back_image_camera_front and their *_face_match_scorenullAlways null on this endpoint (filled only in hosted sessions)
warningsarray{risk, feature, additional_data, log_type, short_description, long_description}; log_type is error (declines) or information
vendor_data, metadata, created_at (top level)Echo of your values and the response timestamp

Warning Tags

Only DECLINE or NO_ACTION exist on this endpoint: a warning is either log_type: "error" (status becomes Declined) or log_type: "information" (reported, no effect on status).

Always decline
TagDescription
DOCUMENT_EXPIREDExpiration date is in the past
SCREEN_CAPTURE_DETECTEDPhoto of a screen, not the physical document (only with perform_document_liveness=true)
PRINTED_COPY_DETECTEDPrinted copy, not the original (only with perform_document_liveness=true)
PORTRAIT_MANIPULATION_DETECTEDPortrait replaced or altered (only with perform_document_liveness=true)
PUBLIC_DOCUMENT_IMAGE_DETECTEDImage matches a known public internet document image (specimen, press or stock photo)
NAME_NOT_DETECTEDFirst and/or last name could not be read
DATE_OF_BIRTH_NOT_DETECTEDDate of birth could not be read on a document that has one
DOCUMENT_NUMBER_NOT_DETECTEDNeither a document number nor a personal number could be read
COULD_NOT_DETECT_DOCUMENT_TYPENothing could be read from the upload; comes with PORTRAIT_IMAGE_NOT_DETECTED when no portrait was found either
Configurable per request
Request parameter (default)Tags
invalid_mrz_action (DECLINE)MRZ_VALIDATION_FAILED (MRZ check digits or format failed). A missing MRZ raises no warning here
inconsistent_data_action (DECLINE)DATA_INCONSISTENT (front and back disagree), MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME (visual zone disagrees with the MRZ)
critical_field_occlusion_action (DECLINE)CRITICAL_FIELD_OCCLUSION_DETECTED: an identity number, name, date of birth or expiry date was physically covered. additional_data.covered_fields lists them; the matching *_NOT_DETECTED warning usually follows
expiration_date_not_detected_action (NO_ACTION)EXPIRATION_DATE_NOT_DETECTED
document_or_personal_number_format_mismatch_action (NO_ACTION)DOCUMENT_NUMBER_FORMAT_MISMATCH, PERSONAL_NUMBER_FORMAT_MISMATCH (additional_data has expected_format, extracted_value)
Informational on this endpoint (never decline)
TagDescription
POSSIBLE_DUPLICATED_USERAnother document in your application has the same date of birth, issuing country and a very similar name under a different vendor_data. additional_data.duplicated_session_id
ID_DOCUMENT_IN_BLOCKLISTThe document matches your document blocklist. Informational here (it auto-declines in workflows): check for it and decide yourself
ID_DOCUMENT_IN_ALLOWLISTThe document number is on your allowlist
DOCUMENT_SIDES_MISMATCHFront and back do not belong to the same document
UNPARSED_ADDRESSThe document has an address field that could not be parsed or geolocated

Workflow-only tags (never produced here): DOCUMENT_NOT_SUPPORTED_FOR_APPLICATION, MINIMUM_AGE_NOT_MET, MRZ_NOT_DETECTED, INVALID_DATE, the *_MISMATCH_WITH_PROVIDED family (needs expected_details on a session) and the front-camera selfie tags.


Digital ID Wallets (standalone)

Verify a person through a national or bank digital ID they already hold, from your own app, with no workflow. The user always authenticates in the wallet and approves sharing; you cannot verify someone from their identifier alone. Endpoints are v3 only.

Wallets available in production (per the docs; always confirm with the catalog call, which reports availability for your application and environment):

WalletStart endpointCountriesInteractionList price per verified sign-in
MitIDPOST /v3/id-verification/wallets/mitid/DNKredirect$0.25
BankID SwedenPOST /v3/id-verification/wallets/bankid-se/SWEredirect$0.20
iDINPOST /v3/id-verification/wallets/idin/NLDredirect$0.85 (full identification)
Finnish Trust NetworkPOST /v3/id-verification/wallets/ftn/FINredirect$0.25
Smart-IDPOST /v3/id-verification/wallets/smart-id/EST, LVA, LTU, BELin appsee pricing
Mobile-IDPOST /v3/id-verification/wallets/mobile-id/EST, LTUin appsee pricing

Other wallets have start endpoints but are Coming soon: they fail closed with 403 wallet_unavailable. Billing: once per request, only when the identity is verified; cancelled, expired or failed sign-ins are free, and the 500 free document checks do not apply.

OperationEndpoint
Catalog: every wallet with id, name, path, countries, interaction, required_fields, availableGET /v3/id-verification/wallets/
Start a sign-inPOST /v3/id-verification/wallets/<wallet>/ (the catalog path)
Read status and resultGET /v3/id-verification/wallets/verifications/{request_id}/
Ask the wallet for a phone approval (Smart-ID, Mobile-ID)POST /v3/id-verification/wallets/verifications/{request_id}/poll/
Cancel a pending sign-in (never billed)POST /v3/id-verification/wallets/verifications/{request_id}/cancel/
Start request
FieldWalletsRequiredDescription
return_urlredirect walletsYesHTTPS URL the browser returns to, with request_id and result appended. Its host must be registered first (below)
deviceredirect walletsNosame_device (default) or cross_device (e.g. a QR code scanned with the phone)
countryallYes for Smart-ID and Mobile-IDISO 3166-1 alpha-3; defaults to the only country of single-country wallets
personal_codeSmart-ID, Mobile-IDYesThe user's national personal identification code (digits and hyphens, 6 to 20 characters). Never collect the PIN
phone_numberMobile-IDYesE.164 number registered with Mobile-ID in that country
vendor_dataallNoYour reference, up to 2,000 UTF-8 bytes
metadataallNoJSON object returned with the result and webhook
sandbox_scenarioallNoSandbox applications only: wallet_cancelled, wallet_timeout or wallet_provider_error; anything else verifies. Rejected on live applications

Header Idempotency-Key (optional, max 255 characters): use a new key per attempt and resend the same key on retries; the same key with another wallet or body returns 409 idempotency_key_reused.

Register the return host once (redirect wallets): PATCH https://verification.didit.me/v3/webhook/ with {"allowed_return_hosts": ["app.example.com"]}. Bare hostnames only (no scheme, path or wildcard), up to 20; the list is replaced on every update, and GET /v3/webhook/ shows it. Your white-label domain is always allowed.

Response (201 on start, 200 on read, poll and cancel)
{
  "request_id": "00000000-0000-4000-8000-000000000001",
  "wallet_verification": {
    "wallet": {"id": "ftn", "name": "Finnish Trust Network", "issuing_authority": "Finnish banks and mobile operators (FTN)"},
    "country": "FIN",
    "status": "Not Finished",
    "outcome": "pending",
    "error": null,
    "interaction": "redirect",
    "simulated": false,
    "expires_at": "2026-01-01T10:10:00Z",
    "next_action": {"type": "redirect", "url": "https://wallet.example.com/authorize"},
    "identity": null,
    "attributes": null,
    "level_of_assurance": null,
    "verified_at": null,
    "signature_valid": null,
    "credential_type": "person_identification"
  },
  "vendor_data": "user-123",
  "metadata": null,
  "created_at": "2026-01-01T10:00:00Z"
}
  • next_action.type: redirect (send the browser to url) or confirm_in_app (show verification_code, the 4-digit code the wallet app also shows; the user confirms in the app; poll every poll_interval_seconds). Didit also polls in the background, so the webhook fires even if you stop polling.
  • outcome: pending, verified, cancelled, timeout, failed. status is Not Finished, then Approved (verified) or Declined.
  • identity once verified: full_name, first_name, last_name, date_of_birth, nationality (only when the wallet asserts it), issuing_state. attributes holds the wallet's own claims and varies by wallet.
  • Use the identity only when outcome is verified and simulated is false. Never trust the result query parameter on return_url; read the result from your backend.
  • The status.updated webhook carries session_id equal to the request_id; the identity appears in decision.id_verifications with verification_method: "wallet".
Wallet errors
CodeerrorMeaning
400field errors, return_url_invalid, return_url_not_allowed, invalid_personal_code, invalid_phone_number, idempotency_key_invalidFix the request; register the return_url host
403{"detail": ...}, wallet_unavailable, insufficient_creditsBad key, wallet not live for you, or top up
404not_foundNo wallet verification of this application has that request_id
409idempotency_key_reused, idempotency_key_in_progress, verification_in_progress (cancel while the user is completing)Use a new key, or wait Retry-After seconds
502wallet_provider_unavailableThe wallet could not start; nothing was created or billed
503wallet_not_configuredThis environment cannot reach the wallet
import uuid
import requests

BASE = "https://verification.didit.me/v3/id-verification/wallets"
headers = {"x-api-key": "YOUR_API_KEY"}

catalog = requests.get(f"{BASE}/", headers=headers, timeout=30).json()
live = {w["id"]: w for w in catalog["wallets"] if w["available"]}

if "ftn" in live:
    start = requests.post(
        f"{BASE}/ftn/",
        headers={**headers, "Idempotency-Key": str(uuid.uuid4())},
        json={"return_url": "https://app.example.com/identity/complete", "vendor_data": "user-123"},
        timeout=30,
    ).json()
    request_id = start["request_id"]
    print("Send the browser to:", start["wallet_verification"]["next_action"]["url"])

    # After the user returns (or on the webhook), read the result server-side
    result = requests.get(f"{BASE}/verifications/{request_id}/", headers=headers, timeout=30).json()
    wv = result["wallet_verification"]
    if wv["outcome"] == "verified" and not wv["simulated"]:
        print("Verified:", wv["identity"]["full_name"], wv["identity"]["date_of_birth"])

API Reference: https://docs.didit.me/standalone-apis/digital-id-wallets


Workflow-Only ID Methods

These are not available on the standalone endpoints; use a workflow and session (see the didit-kyc-onboarding skill):


Common Workflows

Basic ID Verification
1. POST /v3/id-verification/ -> front_image (+ back_image if the document has a back)
2. If 400 COULD_NOT_RECOGNIZE_DOCUMENT -> ask for a new photo with all corners visible
3. If "Approved" -> use first_name, last_name, date_of_birth, document_number, issuing_state
   If "Declined" -> read warnings with log_type "error":
     DOCUMENT_EXPIRED -> ask for a valid document
     SCREEN_CAPTURE_DETECTED / PRINTED_COPY_DETECTED -> ask for a photo of the physical document
     MRZ_VALIDATION_FAILED / NAME_NOT_DETECTED -> ask for a sharper image (and the back side)
4. Check informational warnings too: ID_DOCUMENT_IN_BLOCKLIST, POSSIBLE_DUPLICATED_USER
Full Identity Verification Pipeline (standalone)
1. POST /v3/id-verification/ -> verify document, keep portrait_image
2. POST /v3/passive-liveness/ -> verify a real person took the selfie
3. POST /v3/face-match/ -> compare selfie to the document portrait
4. POST /v3/aml/ -> screen the extracted name, date of birth and nationality; convert nationality
   from alpha-3 (ESP) to alpha-2 (ES) first, or /v3/aml/ returns 400
5. All Approved -> verified identity

For a hosted flow that captures the document and selfie for you, use a workflow session (didit-kyc-onboarding skill).


Utility Scripts

export DIDIT_API_KEY="your_api_key"

python scripts/verify_id.py front.jpg
python scripts/verify_id.py front.jpg back.jpg --vendor-data user-123
python scripts/verify_id.py scan.pdf --front-password secret --no-document-liveness
python scripts/verify_id.py front.jpg back.jpg --preferred-characters non_latin --no-save
python scripts/verify_id.py front.jpg --format-mismatch-action DECLINE --metadata '{"flow": "onboarding"}'

Comments

Markdown supported