Use Case: Credit Approval
This use case demonstrates evaluating a credit decision directly via the API, with no process orchestration involved. The decision model is versioned independently, and every evaluation is persisted with a verifiable trail of which rule matched and why.
Scenario
When an application needs to approve or deny credit, it:
- Sends the applicant's credit score and monthly income to a decision model
- Receives an immediate approval outcome and credit limit
- Can later prove, for any past evaluation, exactly which rule fired and against which inputs
No BPMN process is required — the decision model is a standalone API surface.
Step 1: Create the Decision Model
Define a decision that maps credit score and income to an approval outcome:
curl -X POST https://api.stateway.io/v1/decisions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"key": "credit-approval-rules",
"name": "Credit Approval Rules",
"source_type": "json",
"source": {
"key": "credit-approval-rules",
"name": "Credit Approval Rules",
"hitPolicy": "FIRST",
"inputs": [
{ "name": "credit_score", "type": "number" },
{ "name": "monthly_income", "type": "number" }
],
"outputs": [
{ "name": "approved", "type": "boolean", "defaultValue": false },
{ "name": "credit_limit", "type": "number", "defaultValue": 0 }
],
"rules": [
{
"id": "high-score",
"conditions": {
"credit_score": { "operator": ">=", "value": 750 }
},
"outputs": { "approved": true, "credit_limit": 50000 }
},
{
"id": "mid-score-income",
"conditions": {
"credit_score": { "operator": ">=", "value": 600 },
"monthly_income": { "operator": ">=", "value": 5000 }
},
"outputs": { "approved": true, "credit_limit": 15000 }
},
{
"id": "denied",
"conditions": {
"credit_score": { "operator": "<", "value": 600 }
},
"outputs": { "approved": false, "credit_limit": 0 }
}
]
}
}'
{
"data": {
"id": "dmd_01j...",
"key": "credit-approval-rules",
"version": 1,
"is_active": true
}
}
Step 2: Evaluate the Decision
Call the decision directly — no instance, no process, no state to manage:
curl -X POST https://api.stateway.io/v1/decisions/credit-approval-rules/evaluate \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"variables": {
"credit_score": 680,
"monthly_income": 6200
}
}'
{
"data": {
"evaluation_id": "eval_01j...",
"decision_key": "credit-approval-rules",
"decision_version": 1,
"decision_hash": "a3f1c2d4e5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
"matched": true,
"rules_matched": ["mid-score-income"],
"outputs": {
"approved": true,
"credit_limit": 15000
},
"evaluated_at": "2026-05-19T12:00:00Z"
}
}
rules_matched shows exactly which row fired — here, mid-score-income, because the score (680) fell below the high-score threshold (750) but the income requirement was met.
Step 3: Retrieve Evaluation History
Every evaluation is persisted. Query the full history for the decision, or filter by a specific evaluation:
curl "https://api.stateway.io/v1/decisions/credit-approval-rules/evaluations" \
-H "X-API-Key: sw_live_your_key"
{
"data": [
{
"id": "eval_01j...",
"decision_key": "credit-approval-rules",
"decision_version": 1,
"decision_hash": "a3f1c2d4e5b6c7d8e9f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2",
"rules_matched": ["mid-score-income"],
"outputs": { "approved": true, "credit_limit": 15000 },
"evaluated_at": "2026-05-19T12:00:00Z"
}
]
}
Step 4: Change the Rule Without Redeploying Anything
Publish a new version of the decision — for example, raising the income threshold:
curl -X PUT https://api.stateway.io/v1/decisions/credit-approval-rules \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"source_type": "json",
"source": {
"key": "credit-approval-rules",
"name": "Credit Approval Rules",
"hitPolicy": "FIRST",
"inputs": [
{ "name": "credit_score", "type": "number" },
{ "name": "monthly_income", "type": "number" }
],
"outputs": [
{ "name": "approved", "type": "boolean", "defaultValue": false },
{ "name": "credit_limit", "type": "number", "defaultValue": 0 }
],
"rules": [
{ "id": "high-score", "conditions": { "credit_score": { "operator": ">=", "value": 750 } }, "outputs": { "approved": true, "credit_limit": 50000 } },
{ "id": "mid-score-income","conditions": { "credit_score": { "operator": ">=", "value": 600 }, "monthly_income": { "operator": ">=", "value": 7000 } }, "outputs": { "approved": true, "credit_limit": 15000 } },
{ "id": "denied", "conditions": { "credit_score": { "operator": "<", "value": 600 } }, "outputs": { "approved": false, "credit_limit": 0 } }
]
}
}'
{
"data": {
"id": "dmd_02j...",
"key": "credit-approval-rules",
"version": 2,
"is_active": true
}
}
The evaluation from Step 2 keeps its original decision_version: 1 and decision_hash — history is never rewritten. Every evaluation made from now on runs against version 2.
Key Takeaways
- Decisions are a standalone API surface —
POST /v1/decisions/:key/evaluateneeds no process instance, no BPMN diagram, no state. decision_hashproves which exact source produced a given outcome; combine with Hash Verification to compare it against a file you hold.rules_matchedshows which row of the table fired — no guessing which condition applied.- Publishing a new version never rewrites history — past evaluations keep the version and hash they ran against.
- Hit policies (
FIRSTused here;ALL,UNIQUE,COLLECTalso available) control what happens when more than one rule matches — see Decision Models.