Skip to main content
Didit’s sandbox is the equivalent of Stripe’s test cards or Sumsub’s document templates: it lets you reproduce any verification outcome deterministically, without touching real providers, real PII, or your balance.
The source of truth for this data is serialize_catalog() in the verification service, served live at GET /v1/sandbox/scenarios/. A drift-tested copy is generated into docs/sandbox/SANDBOX_REFERENCE.md in the service-didit-verification repo via pipenv run python scripts/generate_sandbox_reference.py. This page mirrors that reference — always trust the live catalog endpoint if anything here looks stale.

Environment model

Sandbox is a per-application mode (ApplicationDetail.mode == SANDBOX), the same idea as Stripe test mode. While a session runs under a sandbox application:
  • Every external provider (OCR, AML, face match, liveness, NFC, phone, email, IP, POA, database validation, document AI) is mocked — no third party is ever called.
  • Sessions are never billed and the balance check is bypassed.
  • A per-application quota of 500 session creates / 24h is enforced.
  • Webhooks carry "environment": "sandbox" (live sessions carry "environment": "live").
  • The hosted flow exposes the session environment so the UI can warn users not to upload real PII.
  • The uploaded image is ignored: outcomes come from the scenario / magic value, not the pixels.

How to switch between live and sandbox

Live and sandbox are separate applications, so test traffic and production data never mix. Each application has a mode of live or sandbox:
  • Use a sandbox-mode application’s API key to get mocked, unbilled, simulatable sessions.
  • Use a live-mode application’s API key for real verifications.
The sandbox_scenario field on session create and the simulate endpoints are only accepted on sandbox applications; they are rejected on live applications.

Scenarios

Each scenario is a named bundle of magic values. Pass its slug as sandbox_scenario on session create (or to the simulate endpoint) to reproduce the outcome.
SlugTitleDefault statusDescription
approveHappy path — all features approveApprovedDefault sandbox behaviour: every mocked feature returns its clean APPROVED outcome. Session status ends as APPROVED.
decline_aml_hitAML — politically exposed personDeclinedAML mock returns one hit and the session declines on the AML feature. Decision payload carries a realistic AML row (status=DECLINED, total_hits>=1) and a POSSIBLE_MATCH_FOUND warning Log.
decline_document_expiredOCR — document expiredDeclinedOCR mock returns a passport whose expiry date is in the past. The session declines on ID verification with a DOCUMENT_EXPIRED warning Log.
decline_minimum_ageOCR — under the minimum age policyDeclinedOCR mock returns a DOB making the user roughly 10 years old. Production age check emits MINIMUM_AGE_NOT_MET and the workflow declines.
decline_mrz_validationOCR — MRZ checksum failureDeclinedOCR mock returns a passport with a corrupted MRZ checksum. Production MRZ validator emits MRZ_VALIDATION_FAILED and the session declines.
decline_could_not_recognize_documentOCR — unreadable documentDeclinedOCR mock returns an empty response. Production raises COULD_NOT_RECOGNIZE_DOCUMENT and surfaces it to the SDK.
decline_face_match_low_similarityFace match — similarity below decline thresholdDeclinedFace match mock returns a low score. Production emits LOW_FACE_MATCH_SIMILARITY and the workflow node action mapping declines.
decline_database_no_matchDatabase validation — no match across all servicesDeclinedEvery selected database service returns NO_MATCH. Production emits DATABASE_VALIDATION_NO_MATCH and the workflow declines.
decline_phone_high_riskPhone — Twilio reserved high-risk numberDeclinedPrelude mock blocks the verification (Twilio reserved range). Phone verification ends as BLOCKED and emits HIGH_RISK_PHONE_NUMBER.
decline_email_breachEmail — HIBP breach hitDeclinedHIBP mock returns one breach hit on the address. Email verification emits BREACHED_EMAIL_DETECTED.
decline_ip_blocklistIP analysis — IP address in blocklistDeclinedIP analysis mock declines the location with IP_ADDRESS_IN_BLOCKLIST. Session declines on IP analysis.
decline_poa_address_mismatchPOA — address mismatch with providedDeclinedPOA mock declines the proof-of-address with ADDRESS_MISMATCH_WITH_PROVIDED. Session declines on POA.
decline_liveness_attackLiveness — face attack detectedDeclinedPassive liveness mock detects a face-attack signal and emits LIVENESS_FACE_ATTACK. Session declines on liveness.
decline_nfc_chip_not_verifiedNFC — ePassport chip not verifiedDeclinedePassport mock returns a chip whose SOD/DG signature fails integrity. Production emits NFC_CHIP_NOT_VERIFIED and the session declines on NFC when the workflow declines on unverified chips.
decline_document_ai_unreadableDocument AI — unreadable documentDeclinedDocument AI mock returns no readable fields. Production emits DOCUMENT_AI_UNREADABLE_DOCUMENT and the document settles as declined once the retry budget is exhausted.

Magic values

A magic value is a specific input that makes one mocked feature emit a specific risk. Set the input field to the magic value (directly, or via a scenario) to trigger it.
FeatureInput fieldMagic valueRiskDescription
AMLuser_emailsandbox+aml_hit@didit.testPOSSIBLE_MATCH_FOUNDAML — politically exposed person; AML mock returns one hit, session declines on AML.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOCUMENT_EXPIREDDOCUMENT_EXPIREDOCR — document expired; session declines on ID verification.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_MINIMUM_AGE_NOT_METMINIMUM_AGE_NOT_METOCR — date of birth makes the user below the configured minimum age; session declines.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_MAXIMUM_AGE_EXCEEDEDMAXIMUM_AGE_EXCEEDEDOCR — extracted DOB exceeds the configured maximum age policy.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOCUMENT_NUMBER_FORMAT_MISMATCHDOCUMENT_NUMBER_FORMAT_MISMATCHOCR — extracted document number does not match the document’s expected format regex from the document registry.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_PERSONAL_NUMBER_FORMAT_MISMATCHPERSONAL_NUMBER_FORMAT_MISMATCHOCR — extracted personal number fails the document registry’s format check.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOCUMENT_NOT_SUPPORTED_FOR_APPLICATIONDOCUMENT_NOT_SUPPORTED_FOR_APPLICATIONOCR — extracted document type is outside the application’s documents_allowed policy.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_FULL_NAME_MISMATCH_WITH_PROVIDEDFULL_NAME_MISMATCH_WITH_PROVIDEDOCR — name on the document doesn’t match the name the customer prefilled in expected_details above the name-match threshold.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_GENDER_MISMATCH_WITH_PROVIDEDGENDER_MISMATCH_WITH_PROVIDEDOCR — extracted gender disagrees with expected_details.gender.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOB_MISMATCH_WITH_PROVIDEDDOB_MISMATCH_WITH_PROVIDEDOCR — extracted date of birth disagrees with expected_details.date_of_birth.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_COUNTRY_MISMATCH_WITH_PROVIDEDCOUNTRY_MISMATCH_WITH_PROVIDEDOCR — issuing state disagrees with expected_details.country (or id_country).
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_NATIONALITY_MISMATCH_WITH_PROVIDEDNATIONALITY_MISMATCH_WITH_PROVIDEDOCR — extracted nationality disagrees with expected_details.nationality.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_IDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDEDIDENTIFICATION_NUMBER_MISMATCH_WITH_PROVIDEDOCR — extracted document/personal/tax number doesn’t match expected_details.identification_number.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_COULD_NOT_RECOGNIZE_DOCUMENTCOULD_NOT_RECOGNIZE_DOCUMENTOCR pipeline returns empty / unrecognizable; production raises COULD_NOT_RECOGNIZE_DOCUMENT.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_MRZ_NOT_DETECTEDMRZ_NOT_DETECTEDOCR — document expects an MRZ but the pipeline could not locate one.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_MRZ_VALIDATION_FAILEDMRZ_VALIDATION_FAILEDOCR — MRZ was found but failed checksum / format validation.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAMEMRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAMEOCR — MRZ identity fields disagree with VIZ-extracted fields.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_BARCODE_NOT_DETECTEDBARCODE_NOT_DETECTEDOCR — document expects a barcode but none was found.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_BARCODE_VALIDATION_FAILEDBARCODE_VALIDATION_FAILEDOCR — barcode was decoded but failed cross-field validation.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_QR_NOT_DETECTEDQR_NOT_DETECTEDOCR — document expects a QR code but none was found.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_QR_VALIDATION_FAILEDQR_VALIDATION_FAILEDOCR — QR code was decoded but failed cross-field validation.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DATA_INCONSISTENTDATA_INCONSISTENTOCR — internal consistency checks on VIZ fields disagree.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOCUMENT_SIDES_MISMATCHDOCUMENT_SIDES_MISMATCHOCR — front and back document_name do not pair as the same document.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_NAME_NOT_DETECTEDNAME_NOT_DETECTEDOCR — neither first nor last name could be extracted from the document.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DATE_OF_BIRTH_NOT_DETECTEDDATE_OF_BIRTH_NOT_DETECTEDOCR — document class expects a DOB but extraction returned none.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_EXPIRATION_DATE_NOT_DETECTEDEXPIRATION_DATE_NOT_DETECTEDOCR — document class expects an expiry date but extraction returned none.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_DOCUMENT_NUMBER_NOT_DETECTEDDOCUMENT_NUMBER_NOT_DETECTEDOCR — neither document number nor personal number could be extracted.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_COULD_NOT_DETECT_DOCUMENT_TYPECOULD_NOT_DETECT_DOCUMENT_TYPEOCR — classifier could not map the capture to a supported document type.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_PORTRAIT_IMAGE_NOT_DETECTEDPORTRAIT_IMAGE_NOT_DETECTEDOCR — pipeline could not isolate a portrait region on the document.
ID_VERIFICATIONexpected_details.first_nameSANDBOX_OCR_UNPARSED_ADDRESSUNPARSED_ADDRESSOCR — document has an address field but geocoding / parsing returned nothing usable.
DATABASE_VALIDATIONexpected_details.first_nameSANDBOX_DB_NO_MATCHDATABASE_VALIDATION_NO_MATCHDatabase validation — every government/registry service returns NO_MATCH; session declines on database validation.
FACEMATCHexpected_details.first_nameSANDBOX_FACE_LOW_MATCHLOW_FACE_MATCH_SIMILARITYFace match — similarity score below the decline threshold; session declines on face match.
PHONEphone_number+15005550009HIGH_RISK_PHONE_NUMBERPhone — Twilio-style undeliverable / high-risk number; phone verification mock returns failure.
EMAILuser_emailsandbox+breach@didit.testBREACHED_EMAIL_DETECTEDEmail — HIBP returns a breach hit on this address.
LOCATIONexpected_details.first_nameSANDBOX_IP_BLOCKLISTIP_ADDRESS_IN_BLOCKLISTIP analysis — caller IP appears in the application blocklist; session declines on IP analysis.
PROOF_OF_ADDRESSexpected_details.first_nameSANDBOX_POA_ADDRESS_MISMATCHADDRESS_MISMATCH_WITH_PROVIDEDPOA — address on uploaded document disagrees with the address the customer prefilled in expected_details; session declines on POA.
LIVENESSexpected_details.first_nameSANDBOX_LIVENESS_ATTACKLIVENESS_FACE_ATTACKLiveness — passive liveness mock detects a face-attack signal; session declines on liveness.
NFCexpected_details.first_nameSANDBOX_NFC_CHIP_NOT_VERIFIEDNFC_CHIP_NOT_VERIFIEDNFC — ePassport mock returns a chip whose SOD/DG signature fails integrity; production emits NFC_CHIP_NOT_VERIFIED and declines when the workflow declines on unverified chips.
DOCUMENT_AIexpected_details.first_nameSANDBOX_DOCUMENT_AI_UNREADABLEDOCUMENT_AI_UNREADABLE_DOCUMENTDocument AI — extraction returns no readable fields; production emits DOCUMENT_AI_UNREADABLE_DOCUMENT and the document settles as declined once the retry budget is exhausted.

The 10 sample documents

In sandbox the uploaded image is always ignored. The OCR provider is mocked, so the extracted document and any warning come entirely from the scenario or magic value on the session — never from the pixels you upload. Never upload real identity documents in sandbox.
These are the user-facing sandbox templates. Sample specimen images for each are maintained in the service-didit-verification repo under docs/sandbox/sample-documents/<slug>.png (added separately; they may not all be present yet).
DocumentHow it’s surfaced
Brazil - ePassport (2023) #1Default OCR render — returned when no ID-verification magic value is set (e.g. the approve scenario). Also the base for most SANDBOX_OCR_* magic values (expired, age, name/DOB/gender mismatch, MRZ, portrait, etc.).
Pakistan - Passport (2017)SANDBOX_OCR_BARCODE_NOT_DETECTED, SANDBOX_OCR_BARCODE_VALIDATION_FAILED, SANDBOX_OCR_MRZ_AND_DATA_EXTRACTED_FROM_OCR_NOT_SAME
Iraq - Passport (2017)Reference template for document pickers (Arabic script); default render is the Brazil ePassport.
China - Id Card (2004)Reference template for document pickers (Chinese script, front + back).
Israel - ePassport (2013)Reference template for document pickers (Hebrew script).
China - Residence Permit #3Reference template for document pickers.
Australia - Victoria Driving License (2009-2022)SANDBOX_OCR_UNPARSED_ADDRESS
Costa Rica - Id Card (2019)SANDBOX_OCR_DATA_INCONSISTENT (front + back)
Argentina - Id Card (2009)SANDBOX_OCR_DOCUMENT_SIDES_MISMATCH (front + back)
Bahamas - Driving License #1Reference template for document pickers.

OTP codes and email opt-in

  • Phone OTP: the sandbox phone check accepts only the magic code 123456.
  • Email OTP: the sandbox email check accepts only the magic code 123456.
By default sandbox sessions do not send emails (review alerts, status change, OTP, resubmit, new-session-link, etc.). To deliver an email anyway, use one of these opt-in patterns on the recipient address:
Opt-in patternExample
<local>+sandbox@<domain>alice+sandbox@example.com
*@didit.testalice@didit.test

Driving outcomes: scenarios, magic values, and the simulate endpoint

There are three ways to control a sandbox session’s outcome.

1. sandbox_scenario at session create

Set the scenario slug when creating the session (POST /v3/session/). The create flow expands the scenario’s bundled magic values into the session’s input fields, so the mocked providers emit the intended outcome through the real workflow pipeline.
{
  "workflow_id": "<your-workflow-uuid>",
  "sandbox_scenario": "decline_document_expired"
}

2. Magic values typed by hand

Set the individual input fields yourself (for example expected_details.first_name = "SANDBOX_OCR_DOCUMENT_EXPIRED", or user_email = "sandbox+aml_hit@didit.test"). See the magic values table above for the full registry.

3. The simulate endpoint

Force a terminal status after the fact:
  • Console / API key (requires the write:sessions privilege): POST /v3/session/{session_id}/simulate/
  • Hosted flow (Session-Token header): POST /v3/session/{session_id}/sandbox/simulate/
Body fields: new_status, scenario, risk, comment, node_id — all optional, but at least one of new_status, scenario, or risk is required. When only scenario or risk is given, new_status defaults to that scenario’s / risk’s default status, and the matching warning Log is written.
{
  "scenario": "decline_aml_hit"
}