Platform · Workflows
Decide what a verification means, per use case.
A workflow is the configuration a session runs: which steps the person completes, which background checks run at submit, the thresholds, the accepted documents and countries, and whether a failed check declines or goes to review.
- configurable steps and checks
- 9
- fixed hosted-flow positions, consent to submit
- 7
- default workflow per app
- 1
What it checks
Workflows, check by check.
Each rule below is what the engine actually runs.
Steps
Email OTP, document, Aadhaar, PAN and liveness are steps the person completes, always in the order consent, email, document, Aadhaar, PAN, liveness, review.
Background checks
Face match, AML, age and duplicate run at submit, from what the steps collected.
The decision rule
Any failed check declines (or goes to review with auto-decline off); any check in review or error goes to review; otherwise approved.
Redirect
Send the person back to your app when they finish, with an optional redirect URL.
Try it
Build a workflow and read its consequences.
Toggle steps and checks. The journey redraws in the hosted flow's fixed order, the config is generated as the console saves it, and the same validation rules tell you what would be refused.
- The rules are ported line for line from the Rust engine, and the page names the file.
- Everything runs locally in this tab. No request is made while you type.
- Reset puts the example back; nothing is saved.
Workflow builder, in miniature
1 to 4.
The hosted flow, in its fixed order
- Consent
- Document
- Liveness
- Submit
Then, at submit
- Face match
- AML
- Duplicate
- IP (always)
Valid configuration
{
"steps": {
"document": {
"enabled": true,
"allowed_types": [
"passport",
"id_card",
"driving_licence",
"residence_permit",
"aadhaar",
"pan",
"voter_id"
],
"allowed_countries": [],
"reject_expired": true,
"max_attempts": 3
},
"liveness": {
"enabled": true,
"challenges": 3,
"max_attempts": 3
},
"face_match": {
"enabled": true,
"threshold": 0.363,
"review_threshold": 0.3
},
"aadhaar": {
"enabled": false,
"methods": [
"secure_qr",
"offline_xml"
],
"max_xml_age_days": 3,
"require_signature": true
},
"pan": {
"enabled": false,
"require_card_image": false
},
"email": {
"enabled": false
},
"aml": {
"enabled": true,
"lists": [
"ofac_sdn",
"un_consolidated"
],
"match_threshold": 0.9,
"review_threshold": 0.82
},
"age": {
"enabled": false,
"min_age": 18
},
"duplicate": {
"enabled": true,
"face_threshold": 0.55,
"scope": "app"
}
},
"decision": {
"auto_decline": true
},
"redirect_url": null
}Logic ported from backend/crates/kyc-api/src/workflow_config.rs. Nothing you type leaves this page.
How it works
What happens, in order.
- 1
Build
Toggle steps, set thresholds with live previews, pick countries and document types in the console.
- 2
Preview
The journey preview shows exactly which screens the person will see.
- 3
Use
Pass
workflow_idwhen you create a session, or let the app's default workflow apply.
Configuration
The workflow keys and their defaults.
{
"steps": {
"document": { "enabled": true },
"liveness": { "enabled": true, "challenges": 3 },
"face_match": { "enabled": true, "threshold": 0.363 },
"aml": { "enabled": true },
"duplicate": { "enabled": true }
},
"decision": { "auto_decline": true },
"redirect_url": null
}| Key | Default | Meaning |
|---|---|---|
| decision.auto_decline | true | A failed check declines; off sends it to review instead. |
| redirect_url | null | Where the hosted flow sends the person at the end. |
Reference
Every step, its default and its knobs.
| Key | Default | Settings |
|---|---|---|
| off | - | |
| document | on | allowed_types, allowed_countries, reject_expired, max_attempts |
| aadhaar | off | methods, max_xml_age_days, require_signature |
| pan | off | require_card_image |
| liveness | on | challenges (1-4), max_attempts |
| face_match | on | threshold, review_threshold |
| aml | on | lists, match_threshold, review_threshold |
| age | off | min_age |
| duplicate | on | face_threshold, scope (app or org) |
| decision | auto_decline on | auto_decline |
What the console refuses
The same validation runs on every save, from the console or the database.
| Code | Outcome | When |
|---|---|---|
| A workflow needs at least one user-facing step | refused | Email, document, Aadhaar, PAN or liveness must be on. |
| Face match needs the liveness (selfie) step | refused | There is no selfie to compare without liveness. |
| Age check needs a document or Aadhaar step | refused | There is no date of birth to read otherwise. |
| Liveness challenges must be 1-4 | refused | There are four challenge types and each is issued at most once. |
| review threshold must be <= the match threshold | refused | Applies to face match and AML alike. |
API
Choose a workflow per session.
List the app's workflows, then pass a workflow_id when you create a session. Without one, the app's default workflow applies.
Choose a workflow per session.
curl https://kycverify.me/api/v1/workflows -H "x-api-key: $KYC_API_KEY"
curl -X POST https://kycverify.me/api/v1/sessions \
-H "x-api-key: $KYC_API_KEY" \
-H "content-type: application/json" \
-d '{ "workflow_id": "wf_…", "vendor_data": "user-42", "expires_in_hours": 48 }'201 Created
{
"session_id": "ses_…",
"status": "not_started",
"url": "https://kycverify.me/verify/q3Xf…",
"workflow_id": "wf_…",
"vendor_data": "user-42",
"expires_at": "2026-10-05T09:12:44Z"
}Limits
What it does not do.
Stated up front, so you can decide what to pair it with.
- Step order in the hosted flow is fixed. Workflows choose which steps appear, not their order.
FAQ
Workflows: questions.
Can workflows be versioned?
Every workflow change is recorded in the audit log. Archiving a workflow keeps the sessions that used it intact.
Can I list workflows from the API?
Yes, GET /v1/workflows returns the app's workflows so your backend can choose one.
Try it in the sandbox today.
Every check is available from the first sign-up, with test keys and a default workflow. Talk to us when you are ready to verify real people.

