Skip to main content

Use Case: KYC Onboarding

This use case demonstrates routing a new customer through manual compliance review, with an immutable, independently verifiable trail of exactly what happened and when.

Scenario​

When a customer signs up, the process:

  1. Starts with the applicant's data already collected by your application
  2. Routes the case to the compliance team's queue via candidateGroups
  3. Waits for a compliance analyst to approve or reject it
  4. Leaves a complete, tamper-evident audit trail — reconstructible by anyone with API access, without querying the database directly

Step 1: Create the Process Definition​

A single human task, visible to the compliance group:

curl -X POST https://api.stateway.io/v1/definitions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"key": "kyc-onboarding",
"name": "KYC Onboarding",
"source_type": "json",
"source": {
"key": "kyc-onboarding",
"elements": [
{ "id": "start", "type": "startEvent", "outgoing": ["flow-to-review"] },
{
"id": "review-kyc",
"type": "userTask",
"name": "Review KYC Documents",
"candidateGroups": ["compliance"],
"outgoing": ["flow-to-end"]
},
{ "id": "end", "type": "endEvent" }
],
"flows": [
{ "id": "flow-to-review", "sourceRef": "start", "targetRef": "review-kyc" },
{ "id": "flow-to-end", "sourceRef": "review-kyc", "targetRef": "end" }
]
}
}'
{
"data": {
"id": "def_01j...",
"key": "kyc-onboarding",
"version": 1,
"is_active": true
}
}

Step 2: Start an Instance​

Launch the process with the applicant's data collected at sign-up:

curl -X POST https://api.stateway.io/v1/instances \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"definition_key": "kyc-onboarding",
"variables": {
"applicantName": "Maria Silva",
"documentNumber": "123.456.789-00",
"country": "BR"
}
}'
{
"data": {
"id": "inst_01j...",
"definition_key": "kyc-onboarding",
"status": "running",
"variables": { "applicantName": "Maria Silva", "documentNumber": "123.456.789-00", "country": "BR" }
}
}

Step 3: The Compliance Team Lists Its Queue​

Any member of the compliance group lists the tasks visible to it:

curl "https://api.stateway.io/v1/tasks?candidate_group=compliance" \
-H "X-API-Key: sw_live_your_key"
{
"data": [
{
"id": "task_01j...",
"name": "Review KYC Documents",
"status": "pending",
"instance_id": "inst_01j...",
"element_id": "review-kyc",
"candidate_groups": ["compliance"],
"variables": { "applicantName": "Maria Silva", "documentNumber": "123.456.789-00", "country": "BR" }
}
]
}
candidateGroups is metadata, not enforcement

The REST API has no user-identity or group model — it does not check that the caller belongs to compliance before allowing a claim. Your application is responsible for that check before calling /tasks/:id/claim or /complete. See Human Tasks — Authorization.

Step 4: Complete the Review​

curl -X POST https://api.stateway.io/v1/tasks/task_01j.../complete \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"approved": true,
"reviewedBy": "compliance-analyst-42"
}
}'
{
"data": { "id": "task_01j...", "status": "completed" }
}

Step 5: Reconstruct What Happened​

Retrieve the full, ordered path the process took through the diagram — no database access needed:

curl "https://api.stateway.io/v1/instances/inst_01j.../history" \
-H "X-API-Key: sw_live_your_key"
{
"data": [
{
"id": "log_01j...",
"actorType": "engine",
"action": "element.entered",
"payload": { "element_id": "start", "element_type": "startEvent", "token_id": "tok_01j..." },
"createdAt": "2026-05-19T10:00:00Z"
},
{
"id": "log_02j...",
"actorType": "engine",
"action": "element.completed",
"payload": { "element_id": "start", "element_type": "startEvent", "token_id": "tok_01j..." },
"createdAt": "2026-05-19T10:00:00Z"
},
{
"id": "log_03j...",
"actorType": "engine",
"action": "element.entered",
"payload": { "element_id": "review-kyc", "element_type": "userTask", "token_id": "tok_01j..." },
"createdAt": "2026-05-19T10:00:00Z"
},
{
"id": "log_04j...",
"actorType": "engine",
"action": "element.completed",
"payload": { "element_id": "review-kyc", "element_type": "userTask", "token_id": "tok_01j..." },
"createdAt": "2026-05-19T11:32:07Z"
},
{
"id": "log_05j...",
"actorType": "engine",
"action": "element.entered",
"payload": { "element_id": "end", "element_type": "endEvent", "token_id": "tok_01j..." },
"createdAt": "2026-05-19T11:32:07Z"
},
{
"id": "log_06j...",
"actorType": "engine",
"action": "instance.engine_completed",
"payload": { "completed_at": "2026-05-19T11:32:07Z" },
"createdAt": "2026-05-19T11:32:07Z"
}
]
}

Task-level data — who reviewed it and what they submitted — stays queryable on the task and instance resources themselves (GET /v1/tasks/:id, GET /v1/instances/:id); the entries above are the engine's own record of the path the token took.

Step 6: Prove the Trail Was Not Altered​

Every entry is chained by hash. Verify no entry in the period was deleted, inserted, or modified:

curl "https://api.stateway.io/v1/audit/verify?from=2026-05-19T00:00:00Z&to=2026-05-19T23:59:59Z" \
-H "X-API-Key: sw_live_your_key"
{
"data": {
"status": "valid",
"entries_verified": 4,
"first_entry_id": "log_01j...",
"last_entry_id": "log_04j...",
"from": "2026-05-19T00:00:00Z",
"to": "2026-05-19T23:59:59Z"
}
}

A mismatch here means an entry was tampered with — see Chain Integrity for what the response looks like when verification fails.

Key Takeaways​

  • candidateGroups routes a task to a queue without naming an individual — your application still owns membership and claim-time authorization.
  • ?candidate_group=<group> on GET /tasks lists exactly what a queue sees, without exposing tasks assigned elsewhere.
  • GET /instances/:id/history reconstructs the exact path a case took through the diagram — every element entered and completed, in order — without a database query. Combine it with GET /tasks/:id for who reviewed it and what they submitted.
  • GET /audit/verify proves the trail itself hasn't been altered, independent of the process outcome.