EzVerify Reason Codes

Reason codes

Every EzVerify API response carries a machine-readable reason code. Route your integration logic on error.code — never on the free-text message, which may change. Always log the request_id: support needs it to trace a request.

Error envelope
{
  "ok": false,
  "error": {
    "code": "MASK_NO_AADHAAR_FOUND",
    "message": "human-readable detail"
  },
  "request_id": "req_..."
}
Success envelope
{
  "ok": true,
  "data": { ... },
  "request_id": "req_...",
  "took_ms": 123
}

Entries under Response fields are not errors — they are decision fields returned inside data on successful (HTTP 200) responses.

Platform & auth

Codes returned by the platform (console, key management, billing) and the shared auth/limits layer in front of every verification service.

CodeHTTPServicesMeaningWhat to do
AUTH_INVALID_KEY401All verification APIsMissing or invalid X-API-Key header.Send a valid, active API key in the X-API-Key header; mint/rotate keys in the console.
INVALID_KEY401PlatformAPI key is unknown or revoked.Use an active key; rotate/mint a new one in the console if revoked.
RATE_LIMITED429All verification APIsPer-client requests-per-minute limit exceeded; a Retry-After header is set.Back off and retry after the Retry-After interval; upgrade your plan for higher limits.
NOT_FOUND404AllRoute does not exist, async jobs are disabled, the job_id is unknown/expired (job results expire after their TTL), or a referenced account/plan does not exist.Check the URL; poll jobs before they expire; use the synchronous endpoint if async jobs are disabled.
METHOD_NOT_ALLOWED405All verification APIsHTTP method not supported on this route (e.g. GET on a POST endpoint).Use the documented HTTP method (POST for all processing endpoints).
PAYLOAD_TOO_LARGE413All verification APIsRequest body exceeded the allowed size.Reduce the upload size (compress/downscale) and retry.
VALIDATION_ERROR422All verification APIsRequest body/parameters failed validation (missing multipart file, invalid base64 in file_b64, blank name/address, malformed JSON, etc.).Fix the request shape per the API reference (correct field names, valid base64, non-blank inputs) and retry.
INTERNAL500AllUnexpected server-side failure. Also returned with HTTP 503 on /v1/aml/screen when the sanctions snapshot is not provisioned.Retry; if persistent, contact support with the request_id.
UNAUTHORIZED401ConsoleMissing or invalid/expired Bearer JWT — login required.Log in via POST /v1/auth/login and send Authorization: Bearer <token>.
BAD_CREDENTIALS401ConsoleInvalid email or password.Check credentials or use POST /v1/auth/forgot to reset.
SIGNUP_DISABLED403ConsoleSelf-serve signup is off; businesses onboard via KYB verification.Contact onboarding@ezfinanz.com with MCA/GST/PAN details for verified onboarding.
EMAIL_TAKEN409ConsoleThe email is already registered.Log in with the existing account or use password reset.
INVALID_TOKEN400ConsolePassword-reset link/token is invalid or expired.Request a new reset link via POST /v1/auth/forgot.
USER_NOT_FOUND404ConsoleThe user referenced by the reset token no longer exists.Request a fresh reset link; contact support if the account was removed.
WEAK_PASSWORD422ConsoleNew password shorter than 8 characters.Choose a password of at least 8 characters.
UNKNOWN_SERVICE400ConsoleRequested service is not one of aadhaar-mask, id-ocr, match-engine, face-verify.Subscribe using one of the listed service names.
APP_NOT_FOUND404ConsoleApp id does not exist or is not owned by your account.Use an app_id from GET /v1/apps for your own account.
KEY_NOT_FOUND404ConsoleKey id does not exist or belongs to another account.Use a key id listed under your own apps in GET /v1/apps.
ACCOUNT_NOT_VERIFIED403ConsoleBusiness is not KYB-verified yet; live API keys are only issued to verified accounts.Complete business verification (MCA/GST/PAN) with the platform team, then mint keys.
ACCOUNT_SUSPENDED403PlatformThe account is suspended; all its API keys stop validating immediately.Contact EzVerify support/billing to resolve the suspension and reactivate.
SERVICE_NOT_ENABLED403PlatformYour key is valid but the app is not subscribed to the requested service.Subscribe the app via POST /v1/apps/{app_id}/services with the service name.

Aadhaar Mask & OCR

Codes from the document service: masking, detection, extraction (Aadhaar/PAN/passport/Voter ID/DL), document classification, Secure QR verification, and async jobs.

CodeHTTPMeaningWhat to do
MASK_INGEST_ERROR422Generic document-ingestion failure (parent of the more specific MASK_* ingest errors).Re-submit a valid JPG/PNG/PDF document.
MASK_FILE_TOO_LARGE413Uploaded file exceeds the 15 MB limit (or the async job input cap).Compress or downscale the file below 15 MB and re-submit.
MASK_UNSUPPORTED_TYPE415Content-Type is not multipart/form-data or application/json, or the file is not a supported image/PDF format.Send multipart/form-data with a file field or JSON with file_b64; upload JPG/PNG/PDF only.
MASK_INVALID_DOCUMENT422The document could not be decoded/processed (corrupt or truncated image/PDF page).Re-submit a valid, uncorrupted document (re-scan/re-photograph if needed).
MASK_TOO_MANY_PAGES422PDF exceeds the 10-page limit.Split the PDF and submit up to 10 pages per request.
MASK_INCOMPLETE422An Aadhaar was detected but its number could not be masked on one or more pages; the request is rejected rather than returning an unmasked Aadhaar (fail-closed policy).Re-submit a clearer, higher-resolution image of the card.
MASK_NO_AADHAAR_FOUND422No valid Aadhaar number was found in the document (only raised when fail_if_none=true; otherwise the original file is returned unmodified).Confirm the upload is an Aadhaar; send a sharper image, or omit fail_if_none to receive the file back unchanged.
ID_TYPE_NOT_SUPPORTED422The requested id_type is not supported on this endpoint (mask/detect/process/jobs are Aadhaar-only; extract supports aadhaar, pan, passport, voter, dl).Use a supported id_type, or the dedicated /v1/<doc>/extract route for that document.
CONSENT_REQUIRED400A consent field was supplied but is not a positive value (yes/true/y/1).Capture the data principal's consent and send consent=yes (or omit the field if consent is recorded upstream).
EXTRACT_NOT_AADHAAR422No Aadhaar document was detected in the upload.Verify the correct document was uploaded; use /v1/doc/classify to identify the document type first.
EXTRACT_NOT_PAN422No PAN card was detected in the upload.Upload a clear image of a PAN card, or classify the doc first via /v1/doc/classify.
EXTRACT_NOT_PASSPORT422No passport was detected in the upload.Upload the passport bio page (MRZ visible) and retry.
EXTRACT_NOT_VOTER422No Voter ID (EPIC) was detected in the upload.Upload a clear Voter ID image and retry.
EXTRACT_NOT_DL422No Driving Licence was detected in the upload.Upload a clear Driving Licence image and retry.
QR_NOT_FOUND422No decodable QR code found on the document (the Secure QR is dense and needs resolution).Send a sharper/higher-resolution scan (QR region ≥ ~400 px wide) or pass the scanner output as qr_text.
QR_NOT_AADHAAR422A QR was decoded but it is neither a UIDAI Secure QR big-integer nor legacy Aadhaar XML.Verify the document carries an Aadhaar QR; re-scan the correct card.
QR_PARSE_ERROR422The Aadhaar QR payload is malformed/truncated and could not be parsed.Re-scan the QR at higher resolution, or pass a complete qr_text payload.
CERT_PARSE500The bundled UIDAI public certificate could not be parsed server-side (a deployment issue, not a problem with your input).Contact support with the request_id — this is a server-side certificate provisioning problem.
JOBS_UNAVAILABLE503The async job store is unavailable.Use the synchronous endpoint (/v1/aadhaar/mask or /v1/aadhaar/process) or retry later.

Match Engine & AML

The match engine has no service-specific error codes: name/address/person matching and AML screening return only the shared codes from Platform & auth. One shared code has an AML-specific variant:

CodeHTTPMeaningWhat to do
INTERNAL503On /v1/aml/screen only: the sanctions snapshot is not provisioned on the server.Retry later; if persistent, contact support with the request_id.

Match and AML results (decision, band, match_found) are decision fields, not errors — see Response fields.

Face Verify

Codes from face compare, liveness, hosted capture sessions, active-liveness challenges, and 1:N enroll/search.

CodeHTTPMeaningWhat to do
BAD_IMAGE422One or more supplied base64 images could not be decoded into an image.Send valid base64-encoded JPG/PNG bytes in the *_b64 fields.
FACE_NOT_FOUND422No face was detected in the supplied image.Re-capture with the full face visible, well-lit, and centered.
FACE_MULTIPLE422More than one face detected where exactly one is required.Re-capture with only the subject's face in frame.
FACE_TOO_SMALL422Detected face is below the minimum pixel size for reliable matching (strict live-selfie paths).Move the camera closer / capture at higher resolution.
IMAGE_BLURRY422Image sharpness is below the blur threshold for a live selfie.Hold the camera steady and re-capture in better light.
SESSION_NOT_FOUND404Unknown or expired hosted-verification session id.Create a new session via POST /v1/face/session and reissue the capture link.
SESSION_EXPIRED410The capture link/session has expired or never existed.Issue a fresh session/capture link to the end user.
PHOTO_NOT_FOUND404No selfie has been captured for this session yet.Wait until the end user completes the capture flow (session status decided) before fetching the photo.
NO_ACTIVE_CHALLENGE404 / 409The session has no active-liveness challenge issued (session not created with active:true).POST /v1/face/session/{sid}/challenge to issue one, or create the session with active:true.
CHALLENGE_ALREADY_USED409The one-shot active-liveness challenge was already consumed by a prior submission.Rotate the challenge (POST .../challenge) to get a fresh one, then resubmit.
CHALLENGE_EXPIRED410The active-liveness challenge expired before (or during) submission.Request a new challenge and complete it within its expiry window.
CHALLENGE_NONCE_MISMATCH403Submitted nonce does not match the issued challenge (does not consume the challenge).Submit with the nonce returned by the challenge issue/fetch call.
FACE_ID_NOT_FOUND404No enrolled face with that id in your account's namespace.Verify the face_id belongs to your account (from your enroll response).

Response-field reason codes

These are not errors. They arrive inside data on successful (HTTP 200) responses and tell you what the service decided. Route your workflow on these fields.

Aadhaar Mask & OCR

Field / valuesWhereMeaningWhat to do
status: queued | running | done | failedGET /v1/jobs/{job_id}Async job lifecycle state. A failed job carries data.error = {code, message} with the same codes as the sync endpoints.Poll until done/failed; on failed, act on the embedded error.code exactly as for the sync endpoint.
doc_type: aadhaar | pan | passport | voter | dl | unknown/v1/doc/classifyDocument classification verdict; unknown when confidence < 0.3, low_confidence flags a degraded capture; secondary_types lists other IDs found in a collage.Route the doc to the matching extract endpoint; on unknown/low_confidence, request a clearer capture.
signature_valid: true | false | null/v1/aadhaar/verify-qrOffline UIDAI signature verdict for the Secure QR: true = cryptographically genuine, false = tampered/forged (still HTTP 200), null = legacy XML QR (not signature-verifiable).Treat false as a forged/tampered card — reject or escalate; treat null as unverifiable and use other checks.

Match Engine & AML

Field / valuesWhereMeaningWhat to do
decision: ACCEPT | REVIEW | REJECT/v1/match/name, /v1/match/address, /v1/match/personThe one field to route on: ACCEPT = auto-pass, REVIEW = human queue, REJECT = auto-fail; p_match is the calibrated probability (0–100) the two records are the same person.Auto-accept on ACCEPT, auto-fail on REJECT, queue REVIEW for a human checker.
band: AUTO_MATCH | REVIEW | NO_MATCHSame endpointsScore band (AUTO_MATCH ≥ 90, REVIEW 75–89, NO_MATCH < 75; tunable). Accompanied by reasons[] / fields explainability strings.Use band (or decision) for routing; inspect reasons/fields when auditing a REVIEW.
match_found: true | false/v1/aml/screenWhether any sanctions-list entry (UN SC Consolidated + OFAC SDN) scored at or above the requested threshold; matches[] carries list, uid, score, matched name, programs.On true, route to human AML review — a hit is a name-similarity signal, not a legal determination.
dob_conflict: true | false/v1/aml/screen (per match, when a DOB was supplied)All DOBs listed for the matched sanctions entry clearly contradict the supplied DOB (> 2-year tolerance) — a de-prioritisation signal for the reviewer, never an auto-drop.Reviewers may down-weight the hit but should not auto-clear on this flag alone.

Face Verify

Field / valuesWhereMeaningWhat to do
verdict: MATCH | REVIEW | NO_MATCH/v1/face/compare, kyc-check.face, liveness-selfie.face_match1:1 face-match verdict from similarity vs thresholds; a NO_MATCH against a low-quality reference photo is downgraded to REVIEW with reference_low_quality=true.Auto-pass MATCH, auto-fail NO_MATCH, queue REVIEW; on reference_low_quality, supply a better reference photo.
band: high | medium | review | lowSame responsesConfidence band alongside the verdict: high = well above match threshold, medium = at threshold, review/low = below.Optionally apply stricter downstream policy to medium matches than high.
verdict (liveness): LIVE | REVIEW | SPOOF/v1/face/liveness, kyc-check.liveness, /v1/face/liveness-selfieLiveness decision: LIVE = passed; REVIEW = low passive score, failed challenge, model not provisioned, or accessory/injection flags; SPOOF = hard reject.Step-up (retry or manual review) on REVIEW; reject on SPOOF; check the accompanying reason/flags fields for why.
reason (liveness): liveness_model_not_provisioned | face-error code/v1/face/liveness, kyc-check.livenessWhy liveness could not be scored: the passive anti-spoof model is absent (verdict REVIEW, never a faked LIVE) or the face failed quality gates (e.g. FACE_NOT_FOUND, verdict SPOOF).liveness_model_not_provisioned is a server config state — rely on the active challenge or contact support; face-error reasons need a recapture.
decision (KYC): PASS | REVIEW (webhook also FAILED)/v1/face/kyc-check, liveness-selfie.kyc_decision, session webhookComposite KYC outcome: PASS only when face MATCH + liveness LIVE (if required) + geo in India; anything else REVIEW; the webhook sends FAILED when the selfie raised a face error.Complete onboarding on PASS; route REVIEW to a checker; on FAILED, have the user retry the capture.
active_live: true | falsePOST .../active-liveness; GET /v1/face/session/{sid}Server-verified active-liveness outcome (frame order, same-face, geometry, timing); per-frame details may carry face-error codes or UNKNOWN_CHALLENGE for an unrecognised challenge name.On false, rotate the challenge and have the user redo the sequence.
injection_flags: virtual_camera_label | uniform_frame_timing | mock_location/v1/face/liveness-selfie (also in webhook)Advisory stream-injection heuristics (virtual camera software, impossibly uniform frame cadence, mocked GPS); any flag forces verdict REVIEW, never auto-reject.Treat flagged sessions as higher risk; ask the user to retry from a real device camera.
retake_reasons / accessories.detected: glasses | sunglasses | cap | mask/v1/face/liveness-selfie; POST .../accessory-hintAccessory detected on the final selfie; by default any accessory downgrades a LIVE verdict to REVIEW.Instruct the user to remove the listed accessory and retake the selfie.
status (session): created | opened | capturing | decidedGET /v1/face/session/{sid}; webhookHosted capture-session state machine; decided means a result (or error) is available; binding_violations counts link-forwarding to a second device.Poll or take the webhook; fetch data.result once status is decided.