Skip to main content

Use Case: Expense Approval

This use case demonstrates a complete expense approval workflow. The process includes a decision model evaluation, conditional routing, and a human review task.

Scenario

When an employee submits an expense report, the process:

  1. Evaluates a decision model to determine whether manager review is required
  2. Auto-approves small amounts immediately
  3. Routes larger amounts to a human task for manager review
  4. Completes once a decision is made

Step 1: Create the Decision Model

Create a decision that maps expense amount to whether review is required:

curl -X POST https://api.stateway.io/v1/decisions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"key": "expense-approval-rules",
"name": "Expense Approval Rules",
"source_type": "json",
"source": {
"key": "expense-approval-rules",
"hitPolicy": "FIRST",
"inputs": [
{ "id": "amount", "label": "Amount", "type": "number" }
],
"outputs": [
{ "id": "requiresReview", "label": "Requires Review", "type": "boolean" }
],
"rules": [
{ "id": "auto-approve", "conditions": ["<= 100"], "outputs": { "requiresReview": false } },
{ "id": "needs-review", "conditions": ["> 100"], "outputs": { "requiresReview": true } }
]
}
}'
{
"data": {
"id": "dmd_01j...",
"key": "expense-approval-rules",
"version": 1,
"is_active": true
}
}

Step 2: Create the Process Definition

Define the process with a decision task, gateway, and human task:

curl -X POST https://api.stateway.io/v1/definitions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"key": "expense-approval",
"name": "Expense Approval",
"source_type": "json",
"source": {
"key": "expense-approval",
"elements": [
{ "id": "start", "type": "startEvent", "outgoing": ["flow-to-rules"] },
{
"id": "evaluate-rules",
"type": "businessRuleTask",
"name": "Evaluate Approval Rules",
"taskDefinition": { "type": "decision" },
"taskHeaders": { "decisionKey": "expense-approval-rules" },
"ioMapping": {
"inputs": [{ "source": "=variables.amount", "target": "amount" }],
"outputs": [{ "source": "requiresReview", "target": "variables.requiresReview" }]
},
"outgoing": ["flow-to-gw"]
},
{ "id": "gw", "type": "exclusiveGateway", "outgoing": ["flow-auto", "flow-review"] },
{ "id": "review", "type": "userTask", "name": "Review Expense", "outgoing": ["flow-end"] },
{ "id": "auto-approved", "type": "endEvent" },
{ "id": "end", "type": "endEvent" }
],
"flows": [
{ "id": "flow-to-rules", "sourceRef": "start", "targetRef": "evaluate-rules" },
{ "id": "flow-to-gw", "sourceRef": "evaluate-rules", "targetRef": "gw" },
{ "id": "flow-auto", "sourceRef": "gw", "targetRef": "auto-approved", "condition": "{{variables.requiresReview == false}}" },
{ "id": "flow-review", "sourceRef": "gw", "targetRef": "review", "condition": "{{variables.requiresReview == true}}" },
{ "id": "flow-end", "sourceRef": "review", "targetRef": "end" }
]
}
}'
{
"data": {
"id": "def_01j...",
"key": "expense-approval",
"version": 1,
"is_active": true
}
}

Step 3: Start an Instance

Launch the process with expense data:

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": "expense-approval",
"variables": {
"amount": 250,
"description": "Team lunch",
"requester": "john@acme.com"
}
}'
{
"data": {
"id": "inst_01j...",
"definition_key": "expense-approval",
"status": "running",
"variables": { "amount": 250, "description": "Team lunch", "requester": "john@acme.com" }
}
}

Because amount is 250 (> 100), requiresReview is set to true and the process pauses at the review user task.

Step 4: Check Where the Process Is Waiting

curl https://api.stateway.io/v1/instances/{instance_id}/tokens \
-H "X-API-Key: sw_live_your_key"
{
"data": [
{
"id": "tok_01j...",
"element_id": "review",
"element_type": "userTask",
"status": "waiting"
}
]
}

Step 5: Complete the Human Task

List and complete the task:

curl https://api.stateway.io/v1/tasks?instance_id={instance_id} \
-H "X-API-Key: sw_live_your_key"
curl -X POST https://api.stateway.io/v1/tasks/{task_id}/complete \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"approved": true,
"reviewerNotes": "Within budget — approved"
}
}'
{
"data": { "id": "task_01j...", "status": "completed" }
}

Step 6: Verify Completion

curl https://api.stateway.io/v1/instances/{instance_id} \
-H "X-API-Key: sw_live_your_key"
{
"data": {
"id": "inst_01j...",
"status": "completed",
"variables": {
"amount": 250,
"requiresReview": true,
"approved": true,
"reviewerNotes": "Within budget — approved"
}
}
}

Key Takeaways

  • Decision models separate business rules from process flow — update the decision without touching the process
  • Exclusive gateways route based on decision outputs using {{expressions}}
  • User tasks pause execution until a human (or agent) calls /complete
  • ioMapping explicitly maps process variables to decision inputs and outputs back to process variables
  • Tokens show exactly where the process is waiting — use /instances/:id/tokens to build a live status view