One call. Four states. A record you can defend.
Call POST /v1/decide before any debit or credit. The response tells your handler exactly what to do — and writes the evidence at the same instant.
curl -X POST https://api.dev.getfintegrity.com/v1/decide \ -H "Authorization: Bearer $FG_KEY" \ -H "Idempotency-Key: txn_9a7f21" \ -H "Content-Type: application/json" \ -d '{ "customerId": "cus_8f21a", "amount": 45000000, "currency": "NGN", "kycTier": "T2", "direction": "OUTBOUND", "eventType": "transfer", "metadata": { "channel": "mobile" } }'
const decision = await fintegrity.decide({ customerId: "cus_8f21a", amount: 45000000, currency: "NGN", kycTier: "T2", direction: "OUTBOUND", eventType: "transfer", metadata: { channel: "mobile" } }, { idempotencyKey: "txn_9a7f21" }); if (decision.requiredActions.includes("PROCEED")) { await rails.execute(transfer); }
decision = fintegrity.decide(
customer_id="cus_8f21a",
amount=45000000,
currency="NGN",
kyc_tier="T2",
direction="OUTBOUND",
event_type="transfer",
metadata={ "channel": "mobile" },
idempotency_key="txn_9a7f21",
)
if "PROCEED" in decision.required_actions:
rails.execute(transfer){
"decision": "FLAGGED",
"reasons": ["VELOCITY_24H_EXCEEDED"],
"ruleIdsFired": ["velocity.rolling_24h@v4"],
"requiredActions": ["PROCEED"],
"customerRiskState": "ACTIVE",
"caseId": "case_77e10",
"evidenceRef": "b91f4a72-5c1e-4d3a-9f2b-6e0a2c9a5f31",
"timestamp": "2026-04-02T14:37:11.000Z"
}Four states map cleanly to four handler paths
We return the decision. Your handler executes it. Nothing is ambiguous.
No rule fired and the customer is in good standing. The decision is still evidenced.
Worth a second look, not severe enough to stop. A case opens automatically for later review.
Stop before completion. The transaction is held while your compliance team investigates.
Immediate decline — customer state, a hard threshold, or a screening hit.
Every field exists to be defended later
A decision that can’t be explained is not a control. Reasoning and rule versions are recorded at decision time, not reconstructed later.
Idempotent by design
A retried request returns the original decision and evidence ref — never a second record.
Sandbox first
Every state is reproducible with seeded customers before you go live.
Fails safe, loudly
If a decision can't be recorded, it isn't returned. No unevidenced approvals.
Webhooks for state changes
State transitions and case dispositions pushed as they happen.
Wire it into your handler in an afternoon
Sandbox key, the four handler paths, and rules configured against your real transaction shapes.