Skip to content

Decision states

created ──► doc_uploaded ──► processing ──► approved
│ │ rejected
│ └─(challenge frames)──► manual_review ──► approved | rejected
└── token expires (30 min) → verification simply never progresses

next_step (device view) maps: created → upload_document, doc_uploaded → upload_selfie, processing → processing, final states → done.

StateReversible?Produced by
approvedAttestable; product-level revocation onlyPipeline (all checks pass) or reviewer
rejectedCreate a new verification to retryPipeline hard-fail or reviewer
manual_reviewYes — resolves to approved/rejectedAny uncertainty or suspicion
  • uploaded image is not an identity document
  • document expired on YYYY-MM-DD
  • liveness check failed (+ the specific pose/consistency signals)
  • face match below threshold (0.xx)
  • Reviewer rejection (with note)
  • Any tamper signal: … from AI inspection
  • MRZ validation failed: … (check digits)
  • MRZ/visual disagreement: …
  • low extraction confidence (0.xx) / quality: … / missing core identity fields
  • liveness not confirmed / no active challenge issued
  • face match could not be computed / no face found on the document
  • Biometric stack unavailable (face stack not installed)
  • pipeline error: … (any exception — fail safe)

Full explanations of each signal: Fraud signals.

Always present on final states; an ordered list of human-readable strings. Reviewer decisions append (manual review (approve): <note>) so the full causal history survives. Treat the strings as display/monitoring text, not a stable enum — match on prefixes (tamper signal:, MRZ validation failed:) if you automate on them.