Alerts & cases
Anti-Fraud alerts are the post-hoc record of every flagged or blocked evaluation. They feed analyst review queues, workflow automations, and ML-training labels.
Alert lifecycle
created → open → ┐
├→ resolved (analyst dismissed; treated as false positive)
├→ escalated (promoted to a case for deeper investigation)
└→ dismissed (no-action close; lower-priority than resolved)Both resolved and dismissed close the alert but tag it differently — resolved typically means "investigated and benign", dismissed means "too low-priority to investigate". You can use either for ML labels; we use both as negative-class supervision.
List
/api/alertsFilters:
| Param | Example | Notes |
|---|---|---|
status | open · in_review · escalated · resolved · dismissed | Comma-separated for multi-status |
lane | onboarding · transaction | |
customerId | cus_01HXY... | Single-customer scope |
externalId | tx-2026-05-24-001 | Find alert from your own ref |
shape | lean · ui | Raw projection vs UI-enriched |
summary | true | Adds aggregate counts |
Default shape=ui returns enriched fields for dashboard rendering. shape=lean is the canonical projection — use it for ML pipelines and exports.
Response sample (shape=lean):
{
"data": [
{
"id": "alt_01HXY...",
"customerId": "cus_01HXY...",
"fraudScore": 65,
"appliedRuleIds": ["rul_01HXY..."],
"lane": "transaction",
"status": "open",
"amount": 80000000,
"currency": "IDR",
"txChannel": "transfer",
"triggerType": "rule_hit | ml_score | velocity | threshold",
"deadline": "2026-05-25T12:00:00Z",
"assignedToId": null,
"createdAt": "..."
}
],
"total": 287,
"page": 1,
"limit": 20
}Read
/api/alerts/{id}Returns the alert plus the resolved evaluation payload (so you can see exactly which fields drove the decision) and the customer's device-flags snapshot at the time.
Mutations
/api/alerts/{id}/assign{ "assignedToId": "usr_01HXY..." }/api/alerts/{id}/escalate{ "reason": "Possible mule pattern — multiple alerts across 24h." }Auto-creates or auto-links a case.
/api/alerts/{id}/resolve{ "disposition": "false_positive | true_positive | confirmed_fraud | dismissed", "reason": "..." }disposition feeds the ML training pipeline. Be honest — true_positive is what allows the model to improve.
Cases
Cases are deeper investigations grouping multiple alerts on the same customer or pattern.
| Endpoint | Purpose |
|---|---|
GET /api/cases | List with status/priority filters |
GET /api/cases/{id} | Full case + linked alerts |
POST /api/cases/{id}/notes | Append a note |
POST /api/cases/{id}/reject-customer | Final adverse action — freeze acct + write audit row |
Reject-customer
This is the strong action. Calling it:
- Freezes the customer's ability to transact (within Anti-Fraud's view).
- Writes a
reject_customeraudit row. - Fires
customer.rejectedwebhook so your core banking system can mirror the freeze.
POST /api/cases/{id}/reject-customer
{
"reason": "Confirmed mule via account-correlation analysis with three other rejected customers.",
"evidence": ["alt_01HXY...", "alt_01HXZ..."]
}Anti-Fraud doesn't write Identity Platform's KYC tier
Rejecting a customer here marks them as fraud-rejected in Anti-Fraud's customer table — it does not change Customer.kycLevel on Identity Platform. That stays as Identity's source-of-truth. If you want to mark the customer KYC-failed too, call Identity's analyst-downgrade endpoint separately.
ML training feedback loop
Every resolved alert with a disposition becomes a labelled training example for the next ML model retrain. Models retrain weekly per-org once you have 5,000+ labeled alerts.
Until then, ML scoring uses a baseline cross-org model. Quality of your dispositions directly correlates with how fast the per-org model takes over from the baseline.