Triage customer calls, chats and messages for fraud reports
Grayson reads a call transcript, chat or secure message with the account's recent sign-ins, payments and contacts, and decides what it's about, whether to freeze now, where to route it and whether the customer is vulnerable.
Grayson reads a customer contact (a call transcript, a chat or a secure message) next to what your systems already know about the account, and returns what the contact is really about, whether to stop money leaving now, whether it goes to a fraud specialist now, the fraud queue or the support team for its topic, and whether the customer shows signs of vulnerability. It costs about $0.41 to $0.59 per 1,000 decisions.
- Decides: Find fraud reports and scams in progress among customer contacts; decide whether to freeze now and where to route.
- Call it: When a call, chat or message reaches your contact center, and while a call or chat is in progress
- Questions: 2 choice, 2 yes/no
- Cost: $0.00041 to $0.00059 per decision ($0.41 to $0.59 per 1,000) for these examples' 11,711 to 16,961 input tokens
- Latency: 197 to 272 ms for these examples, the median of 5 calls each through api.finic.ai from US-West
Examples
Three contacts, each sent with the customer's profile and contact-detail changes, 60 days of transactions and digital banking sessions, payees, fraud rule hits, a phone-number check and a year of earlier contacts. They are a call about being locked out from a customer whose mobile number was just taken over, an angry secure message headed "FRAUD" about a gym membership and a hotel hold, and a chat from a recently widowed customer asking to raise her P2P limit for a roofer's deposit.
Open in Playground
A customer calls about being locked out while someone empties his account after a SIM swap. Kevin Marsh called the general line from his desk phone because he can't sign in and his cell has had no service since lunch. The SIM on his number changed at 12:58; 24 minutes later someone reset his password with a texted code, signed in on a new Android phone, changed his email, turned off alerts, sent $2,500 by P2P and queued a $4,800 same-day ACH and a $9,500 wire that are still pending.
| Question | Grayson's answer |
|---|---|
intent | unauthorized_activity, confidence 98% |
freeze_now | 97% true |
route | fraud_now, confidence 99% |
vulnerable | 2% true |
16,961 input tokens, $0.00059 per decision, answered in 272 ms.
The request, with long lists cut short. The full request is fraud.json (61 KB).
{
"model": "grayson-1",
"state": {
"customer": {
"customer_id": "C-0284113",
"name": "Kevin R. Marsh",
"age": 44,
"customer_since": "2014-03-18",
"occupation": "Project manager at a commercial HVAC contractor (employer pays by direct deposit every other Friday)",
"address": "Raleigh, NC 27609; unchanged since 2018",
"household": "Lives with his wife, Alicia Marsh, who banks elsewhere; he sends her $650 on the 1st for shared bills",
"preferred_language": "English",
"trusted_contact_person": null,
"profile_flags": []
},
"contact_details": {
"mobile_phone": "919-555-0148, on file since 2014, last verified 2026-02-11",
"email": "kmarsh.nc80@example.net, changed 2026-10-07 13:29 from kevin.marsh@example.com (on file since 2016) in online banking, from the Samsung Galaxy A15; change notice emailed to the old address",
"mailing_address": "Unchanged since 2018",
"alerts": "Texts for transfers over $500, new payees and sign-ins on new devices: turned off 2026-10-07 13:31 from the Samsung Galaxy A15. Emails for password, email and phone changes (always on, cannot be turned off).",
"one_time_codes": "Sent by text to the mobile phone on file"
},
"accounts_and_limits": {
"columns": [
"account",
"type",
"opened",
"ledger_balance_usd",
"available_balance_usd",
"limits"
],
"rows": [
[
"checking x4402",
"checking",
"2014-03-18",
14600.69,
300.69,
"P2P $2,500/day; external transfers $10,000/day; online wires $25,000/day, a new beneficiary is released only after our callback to the mobile phone on file"
],
[
"savings x9187",
"savings",
"2014-03-18",
8641.58,
8641.58,
"Transfers to checking only"
]
]
},
"cards": [
{
"card": "Debit x7716 on checking x4402",
"status": "Active",
"issued": "2026-02-13 (replacement for an expired card)",
"digital_wallets": [
"Apple Pay on iPhone 13, added 2023-06-02",
"Google Pay on Samsung Galaxy A15, added 2026-10-07 13:56 with a code texted to 919-555-0148; not used yet"
]
}
],
"devices": {
"columns": [
"device",
"first_seen",
"last_seen",
"trusted",
"sessions_60_days"
],
"rows": [
[
"iPhone 13, app",
"2023-06-02",
"2026-10-07 07:31",
true,
null
],
[
"Windows 11 laptop, Chrome",
"2024-01-08",
"2026-10-07 14:04",
true,
null
],
[
"Samsung Galaxy A15, Android 14, app",
"2026-10-07 13:22",
"2026-10-07 13:57",
true,
3
]
]
},
"phone_number_check": {
"checked_at": "2026-10-07T14:10:40-04:00",
"source": "Your phone intelligence vendor, queried by the contact-center platform when the call reached an agent",
"mobile_on_file": {
"number": "919-555-0148",
"line_type": "Mobile, postpaid",
"carrier": "Unchanged since 2014",
"last_sim_change": "2026-10-07T12:58-04:00 (1 hour 12 minutes before this check); previous SIM change 2023-06-01",
"device_change": "The handset on the line changed at the same time",
"ported": "No",
"name_match": "Kevin Marsh: match"
},
"caller_number": {
"number": "919-555-0173",
"line_type": "Business landline (VoIP), Raleigh NC",
"on_file": false,
"registered_to": "His employer's main business line",
"spoofing_risk": "Low (network signature verified)"
}
},
"payees_and_recipients": {
"columns": [
"payee",
"type",
"added",
"added_from",
"payments_12_months",
"notes"
],
"rows": [
[
"Alicia Marsh",
"P2P recipient",
"2021-05-03",
"iPhone 13",
12,
"Same last name and address"
],
[
"Derrick Owens",
"P2P recipient",
"2024-04-14",
"iPhone 13",
2,
"Softball teammate"
],
[
"Checking x7731 at an online bank",
"external account",
"2026-10-07 13:33",
"Samsung Galaxy A15",
0,
"Verified instantly by signing in to the other bank; name on that account KEVIN MARSH; opened there 2026-10-01"
],
[
"Jalen Price",
"P2P recipient",
"2026-10-07 13:35",
"Samsung Galaxy A15",
1,
"Phone token x4410; network: enrolled 2026-10-01 at a digital bank; first payment from any of our customers"
],
[
"Jalen Price",
"wire beneficiary",
"2026-10-07 13:49",
"Samsung Galaxy A15",
0,
"Account at a digital bank, x0926"
]
]
},
"transactions_60_days": {
"note": "Posted and pending items on both accounts from 2026-08-08 to the contact; amounts signed, debits negative; local time (UTC-4)",
"columns": [
"ts",
"account",
"type",
"description",
"amount_usd",
"status",
"detail"
],
"rows": [
[
"2026-08-08T10:24:47-04:00",
"checking x4402",
"card purchase",
"CHICK-FIL-A #01842 RALEIGH NC",
-50.78,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-08T16:59:26-04:00",
"checking x4402",
"card purchase",
"HARRIS TEETER #0342 RALEIGH NC",
-106.53,
"posted",
"chip"
],
[
"2026-08-08T18:49:45-04:00",
"checking x4402",
"card purchase",
"AMAZON MKTPL*N7JBYZYJF AMZN.COM/BILL WA",
-42.07,
"posted",
"chip"
],
[
"2026-08-09T07:47:27-04:00",
"checking x4402",
"card purchase",
"SHELL OIL 57444219 RALEIGH NC",
-51.72,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-10T06:26:50-04:00",
"checking x4402",
"ACH debit",
"SPECTRUM PPD",
-89.99,
"posted",
null
],
"… 131 more in fraud.json"
]
},
"digital_banking_sessions_60_days": {
"note": "Every online and mobile banking session from 2026-08-08 to the contact; local time (UTC-4)",
"columns": [
"ts",
"device",
"network",
"sign_in",
"activity"
],
"rows": [
[
"2026-08-08T20:58:32-04:00",
"iPhone 13, app (trusted)",
"192.0.2.141, mobile carrier, Raleigh NC",
"Face ID",
"mobile check deposit screen opened, no deposit"
],
[
"2026-08-09T18:08:55-04:00",
"iPhone 13, app (trusted)",
"192.0.2.141, mobile carrier, Raleigh NC",
"Face ID",
"viewed checking activity"
],
[
"2026-08-10T12:31:23-04:00",
"iPhone 13, app (trusted)",
"192.0.2.141, mobile carrier, Raleigh NC",
"Face ID",
"viewed balances"
],
[
"2026-08-10T20:05:52-04:00",
"Windows 11 laptop, Chrome (trusted)",
"198.51.100.67, business fiber, Raleigh NC (employer)",
"password + device cookie",
"viewed checking activity"
],
[
"2026-08-11T22:11:02-04:00",
"iPhone 13, app (trusted)",
"192.0.2.141, mobile carrier, Raleigh NC",
"Face ID",
"viewed checking activity"
],
"… 57 more in fraud.json"
]
},
"fraud_rules_and_alerts_90_days": {
"columns": [
"ts",
"source",
"rule_or_alert",
"detail",
"outcome"
],
"rows": [
[
"2026-08-21T19:44:10-04:00",
"card fraud model",
"Card-not-present airline and hotel bookings, $612.40",
"Score 701",
"Text alert sent; cardholder replied YES 19:46; approved"
],
[
"2026-10-07T13:23:41-04:00",
"digital banking rules",
"DB-11 password reset from a new device",
"Score 340",
"Logged; no action"
],
[
"2026-10-07T13:36:02-04:00",
"digital banking rules",
"ATO-03 password reset, new device and new payee within 30 minutes",
"Score 712 (automatic hold at 800)",
"Alert A-88213 created; in the fraud alert queue, not yet assigned (position 41)"
],
[
"2026-10-07T13:37:14-04:00",
"P2P rules",
"New recipient over $1,000",
"Code texted to the phone on file was entered",
"Passed; payment sent"
],
[
"2026-10-07T13:49:05-04:00",
"wire rules",
"Online wire to a new beneficiary",
"Standard control",
"Held for callback to the phone on file; callback queue position 6"
]
]
},
"open_cases": [],
"contact_history_12_months": {
"columns": [
"ts",
"channel",
"reason",
"summary"
],
"rows": [
[
"2026-02-11T12:20:00-04:00",
"phone",
"card services",
"Replacement debit card for an expired card hadn't arrived; reissued, verified mobile number"
],
[
"2026-06-03T20:12:00-04:00",
"chat",
"mobile deposit",
"Asked about the mobile check deposit limit; explained the $5,000/day limit"
],
[
"2026-08-21T19:46:00-04:00",
"two-way text",
"card alert",
"Replied YES to a card alert for airline and hotel bookings"
]
]
},
"contact": {
"contact_id": "CALL-20261007-140602-5531",
"channel": "Phone, inbound to the general customer service number",
"started": "2026-10-07T14:06:02-04:00",
"routing": "IVR intent: digital_banking_login (the caller said he can't log in) to the Digital Banking Support queue; waited 3 minutes 53 seconds; answered by agent 2217 (Dana)",
"authentication": "Caller ID not on file. IVR: debit card number and PIN, passed. Agent: name, date of birth and ZIP confirmed. No one-time code (the caller says the phone on file has no service).",
"triage_point": "The agent placed the caller on hold at 00:07:50 to look into the account; the transcript so far is sent",
"speech_analytics": {
"keywords_spotted": [
"password",
"email changed",
"log in"
],
"customer_sentiment": "Neutral, turning negative from 00:06:20"
},
"transcript": {
"columns": [
"offset",
"speaker",
"text"
],
"rows": [
[
"00:00:01",
"IVR",
"Thank you for calling. This call may be monitored or recorded. In a few words, tell me what you're calling about."
],
[
"00:00:07",
"CUSTOMER",
"uh I can't log into my online banking"
],
[
"00:00:11",
"IVR",
"Got it. You need help signing in to online or mobile banking. Is that right?"
],
[
"00:00:14",
"CUSTOMER",
"yes"
],
[
"00:00:16",
"IVR",
"I don't recognize the number you're calling from. Please enter or say your debit card number."
],
"… 35 more in fraud.json"
]
}
}
},
"questions": {
"intent": {
"type": "choice",
"instructions": "What is this contact really about? Judge by what happened, as the contact and our records show it, not by the words the customer uses. If it covers more than one matter, choose the one that needs action first.",
"criteria": {
"unauthorized_activity": "Someone other than the customer made, or is making, transactions, sign-ins or account changes the customer didn't make or allow",
"scam": "The customer is being, or has been, deceived or pressured into sending money, sharing codes or passwords, or giving someone access, whether it is happening now or already happened",
"lost_or_stolen": "A lost or stolen card, checkbook or phone, with no unauthorized use",
"account_access": "The customer can't sign in or receive codes, or needs a password reset or a new phone set up, with no sign that anyone else is using the account",
"merchant_dispute": "A charge the customer made or agreed to is wrong: a billing error, a duplicate or held amount, goods or services not received, a cancelled subscription still billing, or a refund that hasn't arrived",
"complaint": "A complaint about our service, fees, a decision or a declined or blocked transaction",
"general_support": "Any other request or question, such as a limit change, a balance, a payment or account details"
}
},
"freeze_now": {
"type": "noul",
"instructions": "Should we act now, before the contact waits in any queue, to stop money leaving: block the affected cards and hold outgoing payments and digital banking on the affected accounts? Answer yes only when the contact and records show a real risk of further loss that a hold would prevent; answer no when nothing more is at risk or the customer is simply asking for something we can decline or delay."
},
"route": {
"type": "choice",
"instructions": "Where should this contact go next?",
"criteria": {
"fraud_now": "A fraud specialist now: warm-transfer the call or chat, or call the customer back within 15 minutes",
"fraud_queue": "The fraud team's queue, worked in normal order the same business day",
"support_queue": "The support team for its topic (disputes, card services, digital banking or general service), in normal order"
}
},
"vulnerable": {
"type": "noul",
"instructions": "Does the customer show signs of a vulnerability that should change how we handle them: a health condition or disability affecting how they manage money or communicate (including memory, hearing or confusion), a recent major life event such as bereavement, serious illness, job loss or a relationship ending, low ability to understand what is happening to their money or to use our services, or someone else pressuring or controlling them? Being upset or angry about the problem they are reporting is not on its own a sign of vulnerability, and neither is age."
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_2105046685fb4192a75c7e742ba74fe3",
"model": "grayson-1",
"answers": {
"intent": {
"type": "choice",
"choice": "unauthorized_activity",
"confidence": 0.9797,
"probabilities": {
"unauthorized_activity": 0.9826,
"scam": 0.0096,
"lost_or_stolen": 0.0009,
"account_access": 0.0058,
"merchant_dispute": 0.0003,
"complaint": 0.0004,
"general_support": 0.0004
}
},
"freeze_now": {
"type": "noul",
"noul": 0.9669
},
"route": {
"type": "choice",
"choice": "fraud_now",
"confidence": 0.9925,
"probabilities": {
"fraud_now": 0.995,
"fraud_queue": 0.0041,
"support_queue": 0.0009
}
},
"vulnerable": {
"type": "noul",
"noul": 0.018
}
},
"usage": {
"input_tokens": 16961,
"output_tokens": 0
}
}Open in Playground
A furious “FRAUD” message about a cycling studio still billing and a hotel hold. A keyword rule sent Jordan Whitfield's secure message to the fraud queue: it says fraud, stole, hacked and scammed. What he describes is a studio in Atlanta still billing the membership he has paid for since April 2025 and says he cancelled by email, and a hotel pre-authorization he reads as a double charge. The new-device email he mentions was his own new laptop on his home network, and nothing else on the account has changed.
| Question | Grayson's answer |
|---|---|
intent | merchant_dispute, confidence 88% |
freeze_now | 2% true |
route | support_queue, confidence 88% |
vulnerable | 2% true |
16,011 input tokens, $0.00056 per decision, answered in 224 ms.
The request, with long lists cut short. The full request is legitimate.json (57 KB).
{
"model": "grayson-1",
"state": {
"customer": {
"customer_id": "C-0561207",
"name": "Jordan T. Whitfield",
"age": 31,
"customer_since": "2019-05-22 (opened in an Atlanta branch)",
"occupation": "QA analyst at a software company (paid by direct deposit on the 15th and the last business day)",
"address": "Charlotte, NC 28205 since 2026-07-14; Atlanta, GA before",
"preferred_language": "English",
"trusted_contact_person": null,
"profile_flags": []
},
"contact_details": {
"mobile_phone": "404-555-0162, on file since 2019, last verified 2026-09-29",
"email": "jwhitfield.qa@example.com, on file since 2019",
"mailing_address": "Changed 2026-07-14 by phone, from Atlanta GA to Charlotte NC",
"alerts": "Texts for card fraud alerts (two-way), purchases over $500 and sign-ins on new devices; emails for password and contact changes",
"one_time_codes": "Sent by text to the mobile phone on file"
},
"accounts_and_limits": {
"columns": [
"account",
"type",
"opened",
"ledger_balance_usd",
"available_balance_usd",
"limits"
],
"rows": [
[
"checking x3358",
"checking",
"2019-05-22",
2781.97,
2369.61,
"P2P $2,500/day; external transfers $5,000/day"
],
[
"savings x5520",
"savings",
"2021-01-04",
8409.3,
8409.3,
"Transfers to checking only"
]
]
},
"cards": [
{
"card": "Debit x3358 on checking x3358",
"status": "Active",
"issued": "2025-09-10",
"digital_wallets": [
"Apple Pay on iPhone 15, added 2025-11-28"
],
"pending_authorizations": "HAMPTON INN SAVANNAH $412.36 from 2026-10-02 (pre-authorization; releases by 2026-10-09)"
}
],
"devices": {
"columns": [
"device",
"first_seen",
"last_seen",
"trusted",
"sessions_60_days"
],
"rows": [
[
"iPhone 15, app",
"2025-11-28",
"2026-10-08 12:40",
true,
null
],
[
"MacBook Air, Safari",
"2026-10-04 18:26",
"2026-10-08 22:47",
true,
3
]
]
},
"phone_number_check": {
"checked_at": "2026-10-08T22:47:15-04:00",
"source": "Your phone intelligence vendor, queried by the contact-center platform when the message arrived",
"mobile_on_file": {
"number": "404-555-0162",
"line_type": "Mobile, postpaid",
"carrier": "Unchanged since 2019",
"last_sim_change": "2025-11-28 (new handset)",
"device_change": "None since 2025-11-28",
"ported": "No",
"name_match": "Jordan Whitfield: match"
}
},
"payees_and_recipients": {
"columns": [
"payee",
"type",
"added",
"added_from",
"payments_12_months",
"notes"
],
"rows": [
[
"Maya Whitfield",
"P2P recipient",
"2020-03-02",
"earlier iPhone",
4,
"Same last name"
],
[
"Nikhil Rao",
"P2P recipient",
"2023-08-19",
"earlier iPhone",
3,
null
],
[
"Belmont Commons Apts",
"bill pay",
"2026-07-10",
"iPhone 15",
3,
"Rent since July"
]
]
},
"recurring_card_charges": {
"columns": [
"merchant",
"first_charge",
"charges_12_months",
"usual_amount_usd",
"last_charge"
],
"rows": [
[
"SUMMIT CYCLE STUDIO ATLANTA GA",
"2025-04-03",
12,
149,
"2026-10-03"
],
[
"NETFLIX.COM",
"2020-01-07",
12,
15.49,
"2026-10-07"
],
[
"SPOTIFY USA",
"2019-06-19",
12,
11.99,
"2026-09-19"
],
[
"APPLE.COM/BILL",
"2022-02-23",
12,
2.99,
"2026-09-23"
]
]
},
"transactions_60_days": {
"note": "Posted and pending items on both accounts from 2026-08-09 to the contact; amounts signed, debits negative; local time (UTC-4)",
"columns": [
"ts",
"account",
"type",
"description",
"amount_usd",
"status",
"detail"
],
"rows": [
[
"2026-08-09T09:07:00-04:00",
"checking x3358",
"card purchase",
"TST* NODA BREWING CHARLOTTE NC",
-12.92,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-09T12:21:19-04:00",
"checking x3358",
"card purchase",
"PUBLIX #1564 CHARLOTTE NC",
-33.36,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-09T17:07:10-04:00",
"checking x3358",
"card purchase",
"UBER *EATS HELP.UBER.COM CA",
-30.33,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-10T20:35:24-04:00",
"checking x3358",
"card purchase",
"TST* SOUTHBOUND CHARLOTTE NC",
-27.15,
"posted",
"contactless, Apple Pay"
],
[
"2026-08-10T20:42:15-04:00",
"checking x3358",
"card purchase",
"CVS/PHARMACY #07612 CHARLOTTE NC",
-92.06,
"posted",
"chip"
],
"… 142 more in legitimate.json"
]
},
"digital_banking_sessions_60_days": {
"note": "Every online and mobile banking session from 2026-08-09 to the contact; local time (UTC-4)",
"columns": [
"ts",
"device",
"network",
"sign_in",
"activity"
],
"rows": [
[
"2026-08-09T12:00:09-04:00",
"iPhone 15, app (trusted)",
"192.0.2.77, mobile carrier, Charlotte NC",
"Face ID",
"viewed checking activity"
],
[
"2026-08-10T07:40:50-04:00",
"iPhone 15, app (trusted)",
"192.0.2.77, mobile carrier, Charlotte NC",
"Face ID",
"viewed checking activity"
],
[
"2026-08-11T21:43:34-04:00",
"iPhone 15, app (trusted)",
"192.0.2.77, mobile carrier, Charlotte NC",
"Face ID",
"viewed balances"
],
[
"2026-08-12T08:33:53-04:00",
"iPhone 15, app (trusted)",
"192.0.2.77, mobile carrier, Charlotte NC",
"Face ID",
"viewed checking activity"
],
[
"2026-08-13T22:59:20-04:00",
"iPhone 15, app (trusted)",
"192.0.2.77, mobile carrier, Charlotte NC",
"Face ID",
"viewed balances"
],
"… 58 more in legitimate.json"
]
},
"fraud_rules_and_alerts_90_days": {
"columns": [
"ts",
"source",
"rule_or_alert",
"detail",
"outcome"
],
"rows": [
[
"2026-09-20T14:06:30-04:00",
"card fraud model",
"Electronics purchase over $1,000, card present",
"Score 688",
"Two-way text sent; cardholder replied YES 14:07; approved"
],
[
"2026-09-29T21:14:02-04:00",
"digital banking rules",
"DB-11 password reset",
"Known device, home network, score 90",
"Logged; no action"
],
[
"2026-10-04T18:26:30-04:00",
"digital banking rules",
"DB-04 sign-in from a new device",
"Home network seen 61 times since July, code entered, score 160",
"Logged; new-device email sent"
]
]
},
"open_cases": [],
"contact_history_12_months": {
"columns": [
"ts",
"channel",
"reason",
"summary"
],
"rows": [
[
"2025-12-04T12:31:00-05:00",
"chat",
"fees",
"Asked for an overdraft fee refund; one-time courtesy refund of $35 given"
],
[
"2026-07-14T17:55:00-04:00",
"phone",
"address change",
"Moving to Charlotte; updated mailing address; asked to close nothing else"
],
[
"2026-09-20T14:07:00-04:00",
"two-way text",
"card alert",
"Replied YES to a card alert for a $1,140.39 electronics purchase"
]
]
},
"contact": {
"contact_id": "SM-20261008-224712-0884",
"channel": "Secure message from online banking (signed-in session on the MacBook Air)",
"received": "2026-10-08T22:47:12-04:00",
"routing": "Keyword rule KW-07 (fraud, fraudulent, scam, hacked, stole) placed it in the Fraud: secure messages queue; service level 1 business day",
"authentication": "Signed in with password on a trusted device",
"triage_point": "On arrival in the queue",
"text_analytics": {
"keywords_spotted": [
"fraud",
"fraudulent",
"stole",
"hacked",
"compromised",
"scammed"
],
"customer_sentiment": "Very negative"
},
"message": {
"subject": "FRAUD on my account - need charges reversed ASAP",
"body": "Hi,\n\nI'm writing because there are fraudulent charges on my debit card and honestly I'm really frustrated. Summit Cycle Studio in Atlanta has charged me $149 every month since I moved, even though I CANCELLED in July. I emailed them on July 9 before I moved to Charlotte and they never stopped. Now I see August, September AND October. That's $447 they stole from me. This is straight up fraud and I want it reversed.\n\nThen on top of that the Hampton Inn in Savannah double charged me for my stay last weekend, I see $412.36 AND $386.12. I only stayed 2 nights.\n\nI'm starting to think my account got hacked or something. My Instagram got hacked a couple weeks ago and then I got an email from you guys on Saturday about a new device sign in. Is my card compromised?? Do I need a new card? I don't want to keep getting scammed.\n\nHere's what the gym sent back when I emailed them again last week:\n\n> Hi Jordan, thanks for reaching out. Per our membership agreement, cancellations must be submitted using the cancellation form at the front desk or by certified mail, with 30 days notice. We don't have a cancellation form on file for your account, so your membership remains active. You're welcome to freeze your membership for $15/month instead.\n> Summit Cycle Studio Member Services\n\nPlease fix this. I've been a customer for years and I expect better.\n\nJordan Whitfield",
"attachments": []
}
}
},
"questions": {
"intent": {
"type": "choice",
"instructions": "What is this contact really about? Judge by what happened, as the contact and our records show it, not by the words the customer uses. If it covers more than one matter, choose the one that needs action first.",
"criteria": {
"unauthorized_activity": "Someone other than the customer made, or is making, transactions, sign-ins or account changes the customer didn't make or allow",
"scam": "The customer is being, or has been, deceived or pressured into sending money, sharing codes or passwords, or giving someone access, whether it is happening now or already happened",
"lost_or_stolen": "A lost or stolen card, checkbook or phone, with no unauthorized use",
"account_access": "The customer can't sign in or receive codes, or needs a password reset or a new phone set up, with no sign that anyone else is using the account",
"merchant_dispute": "A charge the customer made or agreed to is wrong: a billing error, a duplicate or held amount, goods or services not received, a cancelled subscription still billing, or a refund that hasn't arrived",
"complaint": "A complaint about our service, fees, a decision or a declined or blocked transaction",
"general_support": "Any other request or question, such as a limit change, a balance, a payment or account details"
}
},
"freeze_now": {
"type": "noul",
"instructions": "Should we act now, before the contact waits in any queue, to stop money leaving: block the affected cards and hold outgoing payments and digital banking on the affected accounts? Answer yes only when the contact and records show a real risk of further loss that a hold would prevent; answer no when nothing more is at risk or the customer is simply asking for something we can decline or delay."
},
"route": {
"type": "choice",
"instructions": "Where should this contact go next?",
"criteria": {
"fraud_now": "A fraud specialist now: warm-transfer the call or chat, or call the customer back within 15 minutes",
"fraud_queue": "The fraud team's queue, worked in normal order the same business day",
"support_queue": "The support team for its topic (disputes, card services, digital banking or general service), in normal order"
}
},
"vulnerable": {
"type": "noul",
"instructions": "Does the customer show signs of a vulnerability that should change how we handle them: a health condition or disability affecting how they manage money or communicate (including memory, hearing or confusion), a recent major life event such as bereavement, serious illness, job loss or a relationship ending, low ability to understand what is happening to their money or to use our services, or someone else pressuring or controlling them? Being upset or angry about the problem they are reporting is not on its own a sign of vulnerability, and neither is age."
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_67c26f0e5de24dae84887ef894ec3398",
"model": "grayson-1",
"answers": {
"intent": {
"type": "choice",
"choice": "merchant_dispute",
"confidence": 0.8839,
"probabilities": {
"unauthorized_activity": 0.0349,
"scam": 0.0088,
"lost_or_stolen": 0.0078,
"account_access": 0.0128,
"merchant_dispute": 0.9004,
"complaint": 0.0165,
"general_support": 0.0187
}
},
"freeze_now": {
"type": "noul",
"noul": 0.018
},
"route": {
"type": "choice",
"choice": "support_queue",
"confidence": 0.8754,
"probabilities": {
"fraud_now": 0.0244,
"fraud_queue": 0.0586,
"support_queue": 0.9169
}
},
"vulnerable": {
"type": "noul",
"noul": 0.0203
}
},
"usage": {
"input_tokens": 16011,
"output_tokens": 0
}
}Open in Playground
A recently widowed customer asks to raise her P2P limit for a roofer's $6,800 deposit. Patricia Hollis, widowed in May and new to online banking, wants a one-day limit increase to send a $6,800 deposit to a roofer who knocked on her door after a storm, tarped her roof and was paid $350 by P2P two weeks ago. Her insurer paid the claim and the recipient's P2P token is 19 months old with no fraud reports, but the crew is from out of state, the deposit is half the job, it goes to a person's name, and he wants it today.
| Question | Grayson's answer |
|---|---|
intent | general_support, confidence 74% |
freeze_now | 5% true |
route | support_queue, confidence 10% |
vulnerable | 97% true |
11,711 input tokens, $0.00041 per decision, answered in 197 ms.
The request, with long lists cut short. The full request is ambiguous.json (42 KB).
{
"model": "grayson-1",
"state": {
"customer": {
"customer_id": "C-0039916",
"name": "Patricia A. Hollis",
"age": 67,
"customer_since": "1998-04-06",
"occupation": "Retired school librarian (state pension on the 1st, Social Security survivor benefit since July)",
"address": "Wichita, KS 67212; unchanged since 1998",
"household": "Lives alone. Joint owner Gerald Hollis (husband) died 2026-05-14; removed from both accounts 2026-06-10",
"preferred_language": "English",
"trusted_contact_person": "Emily Hollis-Park (granddaughter), 316-555-0186, added 2026-06-10",
"profile_flags": [
"Bereavement noted 2026-05-20 (branch)"
]
},
"contact_details": {
"mobile_phone": "316-555-0114, on file since 2011, last verified 2026-06-10",
"email": "pat.hollis.ks@example.net, on file since 2015",
"mailing_address": "Unchanged since 1998",
"alerts": "Texts for P2P payments and sign-ins on new devices, set up 2026-06-10",
"one_time_codes": "Sent by text to the mobile phone on file"
},
"accounts_and_limits": {
"columns": [
"account",
"type",
"opened",
"ledger_balance_usd",
"available_balance_usd",
"limits"
],
"rows": [
[
"checking x2290",
"checking",
"1998-04-06",
19938.43,
19938.43,
"P2P $2,500/day; external transfers $5,000/day; no online wires; limit increases by an agent, up to $10,000 for one day"
],
[
"savings x6614",
"savings",
"1998-04-06",
60690.72,
60690.72,
"Transfers to checking only; includes $50,000 life insurance proceeds deposited 2026-06-18"
]
]
},
"cards": [
{
"card": "Debit x8840 on checking x2290",
"status": "Active",
"issued": "2024-11-02",
"digital_wallets": []
}
],
"devices": {
"columns": [
"device",
"first_seen",
"last_seen",
"trusted",
"sessions_60_days"
],
"rows": [
[
"iPhone 12, app",
"2026-06-10 (enrolled in the branch)",
"2026-10-09 13:02",
true,
null
],
[
"iPad (9th generation), Safari",
"2026-06-24",
"2026-10-03 19:12",
true,
null
]
]
},
"phone_number_check": {
"checked_at": "2026-10-09T13:03:01-05:00",
"source": "Your phone intelligence vendor, queried by the contact-center platform when the chat reached an agent",
"mobile_on_file": {
"number": "316-555-0114",
"line_type": "Mobile, postpaid",
"carrier": "Unchanged since 2011",
"last_sim_change": "2022-03-15 (new handset)",
"device_change": "None since 2022-03-15",
"ported": "No",
"name_match": "Patricia Hollis: match"
}
},
"payees_and_recipients": {
"columns": [
"payee",
"type",
"added",
"added_from",
"payments_12_months",
"notes"
],
"rows": [
[
"Emily Hollis-Park",
"P2P recipient",
"2026-06-10",
"iPhone 12 (with branch staff)",
3,
"Granddaughter; trusted contact person"
],
[
"Evergy",
"bill pay",
"2026-07-08",
"iPhone 12",
3,
null
],
[
"Marcus Dale",
"P2P recipient",
"2026-09-23 16:37",
"iPhone 12",
1,
"Phone token x0129 (316 area code); network: registered name MARCUS DALE, enrolled 2025-03-04 at a large national bank; 2 of our customers paid this token in the last 30 days ($350.00 and $4,200.00), no fraud reports against it on the network"
]
]
},
"transactions_60_days": {
"note": "Posted, pending and declined items on both accounts from 2026-08-10 to the contact; amounts signed, debits negative; local time (UTC-5)",
"columns": [
"ts",
"account",
"type",
"description",
"amount_usd",
"status",
"detail"
],
"rows": [
[
"2026-08-10T06:14:02-05:00",
"checking x2290",
"card purchase",
"NETFLIX.COM LOS GATOS CA",
-7.99,
"posted",
"recurring, card on file"
],
[
"2026-08-11T11:30:40-05:00",
"checking x2290",
"card purchase",
"DILLARD'S #0402 WICHITA KS",
-82.88,
"posted",
"chip"
],
[
"2026-08-11T14:01:53-05:00",
"checking x2290",
"card purchase",
"AMAZON MKTPL*FYA38MEWJ AMZN.COM/BILL WA",
-17.27,
"posted",
"chip"
],
[
"2026-08-12T05:01:49-05:00",
"checking x2290",
"ACH credit",
"SSA TREAS 310 XXSOC SEC PPD",
2391,
"posted",
"survivor benefit since 2026-07"
],
[
"2026-08-12T06:58:47-05:00",
"checking x2290",
"ACH debit",
"PRAIRIE MUTUAL INS PREM PPD",
-211.66,
"posted",
null
],
"… 66 more in ambiguous.json"
]
},
"digital_banking_sessions_60_days": {
"note": "Every online and mobile banking session from 2026-08-10 to the contact; local time (UTC-5)",
"columns": [
"ts",
"device",
"network",
"sign_in",
"activity"
],
"rows": [
[
"2026-08-10T20:16:47-05:00",
"iPhone 12, app (trusted)",
"203.0.113.201, residential cable, Wichita KS",
"Face ID",
"viewed balances"
],
[
"2026-08-12T20:03:58-05:00",
"iPhone 12, app (trusted)",
"203.0.113.201, residential cable, Wichita KS",
"Face ID",
"viewed checking activity"
],
[
"2026-08-13T07:19:38-05:00",
"iPhone 12, app (trusted)",
"203.0.113.201, residential cable, Wichita KS",
"Face ID",
"viewed checking activity"
],
[
"2026-08-13T21:26:11-05:00",
"iPhone 12, app (trusted)",
"203.0.113.201, residential cable, Wichita KS",
"Face ID",
"viewed balances"
],
[
"2026-08-14T08:25:32-05:00",
"iPhone 12, app (trusted)",
"203.0.113.201, residential cable, Wichita KS",
"Face ID",
"viewed checking activity"
],
"… 54 more in ambiguous.json"
]
},
"fraud_rules_and_alerts_90_days": {
"columns": [
"ts",
"source",
"rule_or_alert",
"detail",
"outcome"
],
"rows": [
[
"2026-09-23T16:41:20-05:00",
"P2P rules",
"SC-02 first payment to a new recipient, customer 65 or older",
"$350.00, score 210",
"Logged; no action"
],
[
"2026-10-09T12:58:41-05:00",
"P2P rules",
"Daily limit",
"$6,800.00 over the $2,500 limit",
"Declined; in-app message offered chat for a limit increase"
],
[
"2026-10-09T12:58:41-05:00",
"scam model",
"SC-09 large payment to a recent recipient within 10 days of a large deposit",
"Score 540 (review at 600)",
"Logged; no action"
]
]
},
"open_cases": [],
"contact_history_12_months": {
"columns": [
"ts",
"channel",
"reason",
"summary"
],
"rows": [
[
"2026-05-20T10:15:00-05:00",
"branch",
"bereavement",
"Reported husband's death; death certificate scanned; condolences; appointment set for account changes"
],
[
"2026-06-10T14:00:00-05:00",
"branch",
"account changes",
"Removed Gerald Hollis as joint owner; added granddaughter as trusted contact; enrolled in the app on her iPhone. Notes: 'Gerald handled all bills, customer learning online banking; walked her through bill pay and P2P'"
],
[
"2026-07-08T11:22:00-05:00",
"phone",
"bill pay",
"Help adding Evergy to bill pay; completed"
],
[
"2026-09-23T16:20:00-05:00",
"phone",
"P2P help",
"Asked how to send money to someone new; agent explained adding a recipient; customer said it was for a roofer who tarped her roof"
]
]
},
"contact": {
"contact_id": "CHAT-20261009-130214-2207",
"channel": "Chat in the mobile app (signed in on her iPhone 12)",
"started": "2026-10-09T13:02:14-05:00",
"routing": "Virtual assistant intent: limit_increase to the Digital Banking Support chat queue; waited 3 minutes 8 seconds; answered by agent 3108 (Chris)",
"authentication": "Signed in with Face ID on her trusted iPhone",
"triage_point": "The agent submitted a one-day P2P limit increase to $7,000 at 13:18:10; increases are triaged before approval",
"text_analytics": {
"keywords_spotted": [
"limit",
"deposit",
"insurance"
],
"customer_sentiment": "Positive"
},
"transcript": {
"columns": [
"offset",
"speaker",
"text"
],
"rows": [
[
"13:02:14",
"BOT",
"Hi Patricia! I'm the virtual assistant. What can I help you with today?"
],
[
"13:02:41",
"CUSTOMER",
"I need to raise my limit on sending money. It wont let me send 6800"
],
[
"13:02:44",
"BOT",
"I can help with that. Your daily limit for person-to-person payments is $2,500. Limit increases need a specialist. Would you like me to connect you?"
],
[
"13:02:58",
"CUSTOMER",
"yes please"
],
[
"13:03:01",
"BOT",
"Connecting you now. The wait is about 3 minutes."
],
"… 18 more in ambiguous.json"
]
}
}
},
"questions": {
"intent": {
"type": "choice",
"instructions": "What is this contact really about? Judge by what happened, as the contact and our records show it, not by the words the customer uses. If it covers more than one matter, choose the one that needs action first.",
"criteria": {
"unauthorized_activity": "Someone other than the customer made, or is making, transactions, sign-ins or account changes the customer didn't make or allow",
"scam": "The customer is being, or has been, deceived or pressured into sending money, sharing codes or passwords, or giving someone access, whether it is happening now or already happened",
"lost_or_stolen": "A lost or stolen card, checkbook or phone, with no unauthorized use",
"account_access": "The customer can't sign in or receive codes, or needs a password reset or a new phone set up, with no sign that anyone else is using the account",
"merchant_dispute": "A charge the customer made or agreed to is wrong: a billing error, a duplicate or held amount, goods or services not received, a cancelled subscription still billing, or a refund that hasn't arrived",
"complaint": "A complaint about our service, fees, a decision or a declined or blocked transaction",
"general_support": "Any other request or question, such as a limit change, a balance, a payment or account details"
}
},
"freeze_now": {
"type": "noul",
"instructions": "Should we act now, before the contact waits in any queue, to stop money leaving: block the affected cards and hold outgoing payments and digital banking on the affected accounts? Answer yes only when the contact and records show a real risk of further loss that a hold would prevent; answer no when nothing more is at risk or the customer is simply asking for something we can decline or delay."
},
"route": {
"type": "choice",
"instructions": "Where should this contact go next?",
"criteria": {
"fraud_now": "A fraud specialist now: warm-transfer the call or chat, or call the customer back within 15 minutes",
"fraud_queue": "The fraud team's queue, worked in normal order the same business day",
"support_queue": "The support team for its topic (disputes, card services, digital banking or general service), in normal order"
}
},
"vulnerable": {
"type": "noul",
"instructions": "Does the customer show signs of a vulnerability that should change how we handle them: a health condition or disability affecting how they manage money or communicate (including memory, hearing or confusion), a recent major life event such as bereavement, serious illness, job loss or a relationship ending, low ability to understand what is happening to their money or to use our services, or someone else pressuring or controlling them? Being upset or angry about the problem they are reporting is not on its own a sign of vulnerability, and neither is age."
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_8c44da7c80a841599d470b6f794a698c",
"model": "grayson-1",
"answers": {
"intent": {
"type": "choice",
"choice": "general_support",
"confidence": 0.738,
"probabilities": {
"unauthorized_activity": 0.0301,
"scam": 0.1189,
"lost_or_stolen": 0.0052,
"account_access": 0.0111,
"merchant_dispute": 0.0098,
"complaint": 0.0496,
"general_support": 0.7754
}
},
"freeze_now": {
"type": "noul",
"noul": 0.0474
},
"route": {
"type": "choice",
"choice": "support_queue",
"confidence": 0.1026,
"probabilities": {
"fraud_now": 0.3546,
"fraud_queue": 0.2437,
"support_queue": 0.4018
}
},
"vulnerable": {
"type": "noul",
"noul": 0.9669
}
},
"usage": {
"input_tokens": 11711,
"output_tokens": 0
}
}A yes/no answer is Grayson's probability that it's true. A choice answer is the top option and Grayson's confidence: 0% when every option is equally likely, 100% when one option has all the probability. A score answer is the expected level, numbering the levels in its criteria from 0, with its confidence measured the same way and, when no level reaches 70%, each level's probability. A multiple-choice answer lists the options at 50% or more.
routeis the routing decision: sendfraud_nowabove a threshold straight to a specialist (warm transfer or a callback within minutes), and usefraud_queueandsupport_queueto set the queue when your keyword or IVR routing disagrees.freeze_nowis the probability that it's true: above a high threshold, block cards and hold outgoing payments automatically; between that and a lower one, prompt the agent to do it on the call.intentsets the queue's reason code, andvulnerableturns on your vulnerable-customer handling (more time, a specialist, the trusted contact person), whatever the route.
Call it from your code
Save an example as request.json, such as legitimate.json, and send it with your API key in GRAYSON_API_KEY:
curl https://api.finic.ai/v1/decide \
-H "Authorization: Bearer $GRAYSON_API_KEY" \
-H "Content-Type: application/json" \
--data @request.jsonThe problem
Contact centers route on words: an IVR hears "can't log in", a keyword rule sees "fraud". Customers in the middle of an account takeover often describe a login problem, scam victims ask for a higher limit, and angry customers call a gym's billing "fraud". The difference is in the records next to the contact: a SIM change an hour ago, a new device, a payee added today, or a recurring charge paid for 18 months.
What to send
Send the contact as your platform exports it, with what an agent's screens would show. The examples are about 12,000 to 17,000 input tokens each.
- The contact, verbatim. Speaker turns and timestamps for calls and chats, subject and body for messages, with your IVR intent, routing and authentication.
- Sign-ins, devices and security events. A password reset, new device or email change minutes before money moves is the core of an account takeover.
- A phone-number check on the number on file. A recent SIM change explains a customer whose phone "just lost service" and whose codes went to someone else.
- Recent payments, payees and what is still pending. A same-day ACH or a wire waiting for a callback is what a freeze can still stop.
- Fraud rule hits and their status. An alert sitting unassigned in a queue is evidence that the contact is about it.
- Earlier contacts and the customer profile. Bereavement notes, a trusted contact person and earlier calls about the same payee show who you are talking to.
Add your own policy
Whether every customer who says "fraud" goes to the fraud team is a policy choice, often made for complaint and Regulation E reasons, so put your routing standard in the state. This one sends any contact that calls a charge fraudulent or a scam to the fraud queue, and leaves the fraud team to pass merchant disputes on.
Your fraud-claim routing standard adds this to the state of the legitimate example:
{
"routing_standard": "Contact routing standard, section 2 (rev. 2026-05). Any call, chat or message in which the customer says a charge or payment on their account is fraudulent, unauthorized, stolen or a scam goes to the fraud team's queue, to be worked the same business day, even when it looks like a merchant dispute or a billing error. The fraud team decides whether to handle it as an unauthorized-transaction claim or pass it to disputes. Freezes and holds are decided separately, on the evidence."
}| Question | Without | With your fraud-claim routing standard |
|---|---|---|
intent | merchant_dispute, confidence 88% | merchant_dispute, confidence 84% |
freeze_now | 2% true | 2% true |
route | support_queue, confidence 88% | fraud_queue, confidence 87% |
vulnerable | 2% true | 2% true |
Applied to the routine support example: Jordan calls the studio's charges fraud and says they "stole" from him, so the route moves from the support queue to the fraud queue, while the intent stays a merchant dispute and there is still no freeze.
Where to call it
- When a contact arrives: on each secure message and email, and when the IVR or virtual assistant hands a call or chat to a queue.
- During a call or chat, each time the agent places the customer on hold or submits a request such as a limit increase, with the transcript so far.
- On contacts already in a support queue, to pull out the fraud reports that keyword routing missed.
Cost and latency
| Example | Input tokens | Per decision | Per 1,000 decisions | Latency |
|---|---|---|---|---|
| Obvious | 16,961 | $0.00059 | $0.59 | 272 ms |
| Legitimate | 16,011 | $0.00056 | $0.56 | 224 ms |
| Ambiguous | 11,711 | $0.00041 | $0.41 | 197 ms |
You pay only for input tokens, at $0.035 per million, and each request is rounded up to the next millionth of a dollar, so a request with a larger state costs proportionally more; every response reports its size in usage.input_tokens. Latency is the median of 5 calls each through api.finic.ai from US-West, and grows with the number of input tokens. Add your own network time to api.finic.ai.
Evaluate on your own data
Score Grayson on your own past cases before you use it: a CSV with one row per case and a column with the right answer to each question. Every other column is sent as the case.
pipx install https://docs.finic.ai/downloads/grayson_cli-0.4.0-py3-none-any.whl
grayson eval my-cases.csv --questions https://docs.finic.ai/recipes/customer-contact-triage/questions.json --label intent=<column> --label freeze_now=<column> --label route=<column> --label vulnerable=<column>Each --label names the column with that question's right answer:
intent:unauthorized_activity,scam,lost_or_stolen,account_access,merchant_dispute,complaint,general_supportfreeze_now:trueorfalseroute:fraud_now,fraud_queue,support_queuevulnerable:trueorfalse
Or run grayson on its own to set up your questions step by step. You get each question's accuracy and a CSV with Grayson's answer next to yours for every case.
FAQ
Can it run while the customer is still on the line?
Yes. Send the transcript so far from your speech-to-text or agent-assist feed at natural pauses, such as a hold or a request the agent submits, and act on the latest answer. A call usually needs only a few requests, and each is priced and timed like the examples above.
What if a customer reports fraud in the wrong channel?
Under Regulation E, a consumer can notify you of an unauthorized electronic transfer in person, by phone or in writing, and notice counts as given when they take reasonable steps to tell you, whether or not the right employee receives it. A fraud report that waits in a general support queue can still start your clock, which is a reason to triage every contact, not only those your keyword rules catch.
Does vulnerable mean the customer lacks capacity?
No. It flags signs your team should act on, such as a recent bereavement, confusion or someone pressuring the customer, and leaves the judgment to trained staff. Upset or anger about the problem being reported doesn't count on its own, and neither does age, so an angry customer reporting fraud isn't flagged for that reason alone.
Related recipes
Fraud typology classification
Label a fraud claim with a FraudClassifier class, scam type and contributing factors; decide reimbursement.
Classify card disputes and detect friendly fraud
Classify unauthorized-transaction claims and choose provisional credit, approval or denial.
Recipes
Every use case, with its questions and cost per decision.
Claims and customer contacts
Fraud and scam claims, and the customer calls, chats and emails that report them. Ready-to-run Grayson recipes with real responses, cost and latency.
Fraud typology classification
Grayson labels a fraud claim with a FraudClassifier class, a ScamClassifier type and contributing factors, and decides reimbursement, from the claim file: statements, payments, account history and session logs.