Use Case: Order Fulfillment
This use case demonstrates an order fulfillment workflow that integrates with external APIs, uses parallel execution, and applies timer-based retry logic.
Scenario
When a customer places an order, the process:
- Checks inventory and validates the shipping address in parallel (two service tasks)
- Routes to shipping if both checks pass
- Waits 5 minutes and retries if stock is unavailable
- Notifies the customer once the order ships
Step 1: Store the External API Credential
Keep the inventory API key out of the process definition:
curl -X POST https://api.stateway.io/v1/credentials \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"name": "inventory_api_key",
"value": "inv_live_abc123"
}'
Step 2: Create the Process Definition
curl -X POST https://api.stateway.io/v1/definitions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"key": "order-fulfillment",
"name": "Order Fulfillment",
"source_type": "json",
"source": {
"key": "order-fulfillment",
"elements": [
{ "id": "start", "type": "startEvent", "outgoing": ["flow-to-fork"] },
{ "id": "fork", "type": "parallelGateway","outgoing": ["flow-check-stock", "flow-validate-addr"] },
{
"id": "check-stock",
"type": "serviceTask",
"name": "Check Inventory",
"taskDefinition": { "type": "http" },
"taskHeaders": {
"url": "https://api.inventory.com/v1/stock",
"method": "GET",
"executionMode": "sync",
"headers": "{\"Authorization\": \"Bearer {{credentials.inventory_api_key}}\"}"
},
"ioMapping": {
"inputs": [{ "source": "=variables.productId", "target": "product_id" }],
"outputs": [
{ "source": "inStock", "target": "variables.inStock" },
{ "source": "quantity", "target": "variables.availableQuantity" }
]
},
"outgoing": ["flow-stock-to-join"]
},
{
"id": "validate-address",
"type": "serviceTask",
"name": "Validate Address",
"taskDefinition": { "type": "http" },
"taskHeaders": {
"url": "https://api.address.com/v1/validate",
"method": "POST",
"executionMode": "sync"
},
"ioMapping": {
"inputs": [{ "source": "=variables.shippingAddress", "target": "address" }],
"outputs": [{ "source": "valid", "target": "variables.addressValid" }]
},
"outgoing": ["flow-addr-to-join"]
},
{ "id": "join", "type": "parallelGateway","outgoing": ["flow-to-gw"] },
{ "id": "gw", "type": "exclusiveGateway","outgoing": ["flow-ship", "flow-wait"] },
{ "id": "ship-order", "type": "userTask", "name": "Ship Order", "outgoing": ["flow-to-notify"] },
{ "id": "wait-restock", "type": "timerEvent", "timerType": "duration", "timerExpression": "PT5M", "outgoing": ["flow-retry"] },
{
"id": "send-confirmation",
"type": "sendTask",
"name": "Send Shipping Confirmation",
"taskDefinition": { "type": "http" },
"taskHeaders": {
"url": "https://api.notifications.com/v1/send",
"method": "POST",
"executionMode": "sync"
},
"ioMapping": {
"inputs": [
{ "source": "=variables.orderId", "target": "order_id" },
{ "source": "=variables.customerEmail", "target": "email" },
{ "source": "=variables.trackingNumber","target": "tracking_number" }
]
},
"outgoing": ["flow-to-end"]
},
{ "id": "end", "type": "endEvent" }
],
"flows": [
{ "id": "flow-to-fork", "sourceRef": "start", "targetRef": "fork" },
{ "id": "flow-check-stock", "sourceRef": "fork", "targetRef": "check-stock" },
{ "id": "flow-validate-addr", "sourceRef": "fork", "targetRef": "validate-address" },
{ "id": "flow-stock-to-join", "sourceRef": "check-stock", "targetRef": "join" },
{ "id": "flow-addr-to-join", "sourceRef": "validate-address", "targetRef": "join" },
{ "id": "flow-to-gw", "sourceRef": "join", "targetRef": "gw" },
{ "id": "flow-ship", "sourceRef": "gw", "targetRef": "ship-order", "condition": "{{variables.inStock == true && variables.addressValid == true}}" },
{ "id": "flow-wait", "sourceRef": "gw", "targetRef": "wait-restock", "condition": "{{variables.inStock == false || variables.addressValid == false}}" },
{ "id": "flow-to-notify", "sourceRef": "ship-order", "targetRef": "send-confirmation" },
{ "id": "flow-retry", "sourceRef": "wait-restock", "targetRef": "check-stock" },
{ "id": "flow-to-end", "sourceRef": "send-confirmation","targetRef": "end" }
]
}
}'
{
"data": {
"id": "def_01j...",
"key": "order-fulfillment",
"version": 1,
"is_active": true
}
}
Step 3: Start an Instance
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": "order-fulfillment",
"correlation_id": "ord-001",
"variables": {
"orderId": "ord-001",
"productId": "prod-001",
"quantity": 2,
"customerEmail": "customer@example.com",
"shippingAddress": "123 Main St, City, State"
}
}'
{
"data": {
"id": "inst_01j...",
"definition_key": "order-fulfillment",
"status": "running"
}
}
Step 4: Monitor Parallel Execution
While both service tasks are running, there are two active tokens:
curl https://api.stateway.io/v1/instances/{instance_id}/tokens \
-H "X-API-Key: sw_live_your_key"
{
"data": [
{ "element_id": "check-stock", "status": "active" },
{ "element_id": "validate-address", "status": "active" }
]
}
Once both complete, the parallel join gate merges them into a single token which proceeds to the exclusive gateway.
Step 5: Complete the Shipping Task
If stock is available and the address is valid, the process pauses at ship-order:
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": {
"trackingNumber": "TRK123456789",
"shippedAt": "2026-04-26T14:00:00Z"
}
}'
The process then fires the send-confirmation send task (fire-and-forget notification) and completes.
Key Takeaways
- Parallel gateways run
check-stockandvalidate-addressconcurrently; the join gate waits for both - Credentials keep external API keys out of the process definition — rotate with
PATCH /credentials/inventory_api_key - Timer events handle retry delays (
PT5M) without external scheduling ioMappingoutputs use"target": "variables.inStock"to write back into the processcorrelation_idlinks the instance to the external order ID for filtering withGET /instances?correlation_id=ord-001