Detect account takeover before money moves
Grayson decides whether someone else is controlling an account that just changed its sign-in, contact or payout details, who owns the destination, and whether to release, step up, hold or block the money.
Grayson decides whether the person who just changed a password, phone, email, 2-step method or payout account, or who signed in from a new device, is really the account holder, before a payout, transfer or withdrawal leaves. It returns how likely a takeover is, how the account was reached (a stolen password, the email or phone number on file, a support agent, a shared code or remote access), who owns the account the money would go to, and whether to release it, confirm it with a 2-step method that predates the changes, hold it for a call or block it and lock the account. It costs about $0.53 to $0.67 per 1,000 decisions.
- Decides: Whether someone else controls an account that just changed its sign-in, contact or payout details, and whether the money should go.
- Call it: When money is about to leave an account after a new device or a sign-in, contact or payout change
- Questions: 1 score, 1 multiple choice, 2 choice
- Cost: $0.00053 to $0.00067 per decision ($0.53 to $0.67 per 1,000) for these examples' 15,041 to 19,029 input tokens
- Latency: 227 to 253 ms for these examples, the median of 5 calls each through api.finic.ai from US-West
Examples
Three payouts waiting in a small-business payments platform's review queue, each sent with 90 days of sign-ins (about 70 to 90 by the owner and unknown devices, plus a summary of staff point-of-sale sign-ins), device-intelligence results for recent sessions, every credential, contact and payout change, carrier checks on the phone on file, 90 days of daily sales and payouts, and support history. They are a bakery's week of sales sent by instant payout to a stranger after a SIM swap and a password reset, a bike shop owner moving payouts to his new credit union account from a trade show in Las Vegas, and a yoga studio's $9,850 instant payout to a week-old account in the owner's name from a laptop she has never used with us.
Open in Playground
A password reset after a SIM swap, then the bakery's whole week sent to a stranger. At 7:52 p.m. on a Sunday, an hour after the SIM on the bakery owner's phone number was moved to a new handset, a Windows computer behind a residential proxy failed four passwords, reset hers through her email and passed the text code. In 14 minutes it added an authenticator, changed the email, silenced notices and requested an instant payout of the week's $14,191.06 to a two-month-old account held by someone named Trevon A Mills.
| Question | Grayson's answer |
|---|---|
takeover_likelihood | 3.94 of 4, confidence 97% |
access_route | email_taken_over, phone_taken_over |
destination_owner | unrelated, confidence 99% |
action | block_and_lock, confidence 97% |
15,904 input tokens, $0.00056 per decision, answered in 243 ms.
The request, with long lists cut short. The full request is fraud.json (51 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "ATO-26-10-0381",
"queue": "Payout review: account security",
"opened": "2026-10-05T00:21:48Z",
"records_as_of": "2026-10-05T00:34:10Z",
"local_time": "Sunday 2026-10-04, 8:34 p.m. EDT in Portland, ME"
},
"platform_controls": "Sign-in is email and password. A device not trusted in the last 30 days must also pass 2-step verification: an SMS code to the phone on file, or an authenticator app if the user has added one. The mobile app then signs in with Face ID or a fingerprint. 'Forgot password' emails a reset link to the email on file, and 2-step verification is still required after a reset. Changing the email or phone on file, adding or removing a 2-step method, and adding a payout destination each need a fresh 2-step code; we email the previous address and text the phone on file after each change. Payout destinations are business or owner checking accounts, verified by signing in to the bank through our account-verification provider (which returns the holder name and the account's open date) or by micro-deposits, and debit cards for instant payouts, checked with the card network's account name inquiry. Standard payouts go by ACH on the schedule the business picks and arrive the next business day. Instant payouts send up to $25,000 a day in minutes, to a debit card or a bank account on the real-time payments network, for a 1.5% fee, and cannot be recalled. Any payout to a destination added in the last 7 days, and any instant payout over $5,000 within 24 hours of a sign-in, contact or 2-step change, waits in this review queue. Staff with the point-of-sale role take payments on the shop's devices with a PIN and cannot see payouts or change settings.",
"business": {
"merchant_id": "mer_20417",
"legal_name": "Harbor Lane Bakery LLC",
"doing_business_as": "Harbor Lane Bakery",
"business_type": "Single-member LLC; bakery and cafe, MCC 5462 (bakeries)",
"location": "Portland, ME; open Tuesday to Sunday, 6:30 a.m. to 3 p.m.; closed Mondays",
"on_platform_since": "2021-05-14",
"owner": {
"name": "Denise Kowalczyk",
"role": "Owner and only admin",
"phone_on_file": "(207) 555-0163, since 2021-05-14",
"email_on_file": "harborlane.payouts@example.com since 2026-10-05T00:11:52Z; harborlane.bakery@example.net from 2021-05-14 until then",
"two_step_methods": "SMS to (207) 555-0163 since 2021; authenticator app added 2026-10-05T00:09:26Z"
},
"products": "In-person card payments at the counter, online invoices for wholesale cafe customers, weekly standard payouts",
"monthly_card_volume_usd_last_12_months": "52,000 to 78,000 (summer high)",
"payout_schedule": "Weekly standard payout every Monday for the previous Monday to Sunday",
"disputes_12_months": 1,
"account_status": "Active; no holds before tonight"
},
"users": {
"columns": [
"user",
"role",
"added",
"sign_in"
],
"rows": [
[
"Denise Kowalczyk",
"Owner (admin)",
"2021-05-14",
"email and password, 2-step"
],
[
"Marco Bellini",
"Point of sale",
"2023-03-11",
"PIN on the shop iPad only"
],
[
"Aisha Grant",
"Point of sale",
"2023-03-11",
"PIN on the shop iPad only"
]
]
},
"devices": {
"columns": [
"device_id",
"device",
"user",
"first_seen",
"trusted",
"last_seen"
],
"rows": [
[
"dv_b2",
"MacBook Air, Safari (macOS 14)",
"Denise Kowalczyk",
"2021-05-14",
"yes, renewed 2026-08-17",
"2026-09-28T15:02:28Z"
],
[
"dv_a1",
"iPhone 13, our app (iOS 18)",
"Denise Kowalczyk",
"2022-09-30",
"yes (Face ID)",
"2026-10-04T23:43:02Z"
],
[
"dv_c3",
"iPad 9th gen at the counter, point-of-sale app",
"shop device (staff PINs)",
"2023-03-11",
"yes (shop device)",
"2026-10-04T10:20:01Z"
],
[
"dv_x9",
"Windows 10, Chrome 129",
"signed in as Denise Kowalczyk",
"2026-10-04T23:52:08Z",
"no",
"2026-10-05T00:21:47Z"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2021-05-14T15:12:40Z",
"Account opened; owner Denise Kowalczyk; email harborlane.bakery@example.net; phone (207) 555-0163",
"dv_b2",
"203.0.113.84",
"identity check passed"
],
[
"2021-05-17T13:30:02Z",
"Payout destination added: checking x2290 (the bakery's bank since 2015)",
"dv_b2",
"203.0.113.84",
"bank login through verification provider; holder HARBOR LANE BAKERY LLC"
],
[
"2022-09-30T23:41:18Z",
"App trusted on new phone dv_a1 (iPhone 13)",
"dv_a1",
"203.0.113.84",
"SMS code"
],
[
"2023-03-11T11:08:55Z",
"Staff users added: Marco Bellini, Aisha Grant (point-of-sale role)",
"dv_b2",
"198.51.100.36",
"SMS code"
],
[
"2023-03-11T11:20:40Z",
"Shop iPad dv_c3 set up for point of sale",
"dv_c3",
"198.51.100.36",
"owner approval in app"
],
"… 9 more in fraud.json"
]
},
"payout_destinations": [
{
"destination": "checking x2290",
"added": "2021-05-17",
"status": "was default until 2026-10-05T00:18:40Z",
"ownership_check": "Bank login through verification provider, 2021-05-17: holder HARBOR LANE BAKERY LLC (matches the legal name)",
"account_opened": "2015-08-04",
"payouts_received": "All 271 payouts since 2021-05, none returned"
},
{
"destination": "checking x4471 at an online bank",
"added": "2026-10-05T00:16:05Z",
"status": "default since 00:18:40Z",
"ownership_check": "Bank login through verification provider, 2026-10-05T00:15:48Z: holder TREVON A MILLS (no match to the business, the owner or any user)",
"account_opened": "2026-08-21, per the verification provider",
"payouts_received": "None yet",
"seen_elsewhere_on_platform": "Not linked to any other business on our platform"
}
],
"sign_in_history": {
"period": "2026-07-07 to 2026-10-05T00:34:10Z",
"ip_addresses": {
"198.51.100.36": "Business cable ISP, Portland ME (the bakery's Wi-Fi)",
"203.0.113.84": "Residential cable ISP, Portland ME",
"198.51.100.77": "Residential proxy network, exit in Portland ME (not the owner's ISP)"
},
"staff_point_of_sale_sign_ins": "78 staff PIN sign-ins on dv_c3 from 198.51.100.36, one each open day between 6:00 and 6:25 a.m. local time, all successful (Aisha Grant 28, Marco Bellini 26, Denise Kowalczyk 24); last 2026-10-04T10:20:01Z",
"columns": [
"ts",
"device_id",
"ip",
"method",
"result",
"activity"
],
"rows": [
[
"2026-07-09T23:45:55Z",
"dv_a1",
"203.0.113.84",
"Face ID (app)",
"success",
"items and prices"
],
[
"2026-07-12T00:51:20Z",
"dv_a1",
"203.0.113.84",
"Face ID (app)",
"success",
"deposits report"
],
[
"2026-07-14T01:13:11Z",
"dv_a1",
"203.0.113.84",
"Face ID (app)",
"success",
"payouts viewed"
],
[
"2026-07-14T19:05:50Z",
"dv_a1",
"198.51.100.36",
"Face ID (app)",
"success",
"sales summary"
],
[
"2026-07-16T23:56:38Z",
"dv_a1",
"203.0.113.84",
"Face ID (app)",
"success",
"deposits report"
],
"… 73 more in fraud.json"
]
},
"device_intelligence": {
"vendor": "Your device intelligence vendor, scored on every sign-in and sensitive change",
"reason_code_meanings": {
"NEW_DEVICE": "Device not seen on this account before",
"NEW_LOCATION": "IP location not seen on this account in 90 days",
"PROXY_RESIDENTIAL": "IP belongs to a residential proxy network",
"VPN": "IP belongs to a commercial VPN service",
"TZ_MISMATCH": "Device timezone doesn't fit the IP location",
"FP_INCONSISTENT": "Browser fingerprint attributes contradict each other (anti-detect browser suspected)",
"FRESH_PROFILE": "Browser has no stored cookies or history",
"DIRECT_NAV": "Went straight to payout settings after sign-in",
"RESET_THEN_CHANGE": "Password reset followed by contact or payout changes in the same session",
"BEHAVIOR_MISMATCH": "Typing and pointer behavior differ from this user's profile",
"SIM_RECENT": "SIM change or port on the phone on file in the last 7 days"
},
"recent_sessions": {
"columns": [
"ts",
"device_id",
"vendor_score",
"reason_codes",
"proxy_or_vpn",
"… 4 more in fraud.json"
],
"rows": [
[
"2026-09-28T13:12:40Z",
"dv_b2",
38,
[],
"no",
"… 4 more in fraud.json"
],
[
"2026-10-01T23:44:05Z",
"dv_a1",
22,
[],
"no",
"… 4 more in fraud.json"
],
[
"2026-10-03T00:05:51Z",
"dv_a1",
25,
[],
"no",
"… 4 more in fraud.json"
],
[
"2026-10-04T21:58:12Z",
"dv_a1",
19,
[],
"no",
"… 4 more in fraud.json"
],
[
"2026-10-04T23:52:08Z",
"dv_x9",
871,
[
"NEW_DEVICE",
"PROXY_RESIDENTIAL",
"TZ_MISMATCH",
"FP_INCONSISTENT"
],
"residential proxy",
"… 4 more in fraud.json"
],
[
"2026-10-05T00:07:19Z",
"dv_x9",
947,
[
"NEW_DEVICE",
"PROXY_RESIDENTIAL",
"TZ_MISMATCH",
"FP_INCONSISTENT",
"RESET_THEN_CHANGE",
"DIRECT_NAV",
"BEHAVIOR_MISMATCH"
],
"residential proxy",
"… 4 more in fraud.json"
]
]
}
},
"phone_checks": [
{
"checked": "2026-10-05T00:07:02Z",
"number": "(207) 555-0163 (on file since 2021-05-14)",
"trigger": "2-step SMS at sign-in",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match (Kowalczyk)",
"sim_change": "SIM changed 2026-10-04T22:41Z (1 hour 26 minutes before this code; first SIM change since 2022-09-30)",
"port_out": "none",
"device_change": "the number is now in a different handset (new IMEI)"
},
{
"checked": "2026-09-28T13:12:31Z",
"number": "(207) 555-0163",
"trigger": "30-day trust renewal check",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match",
"sim_change": "none in 90 days",
"port_out": "none",
"device_change": "none"
}
],
"security_notices": {
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-07-13T13:00:00Z",
"email",
"harborlane.bakery@example.net",
"Your weekly payout is on its way",
"delivered"
],
[
"2026-07-20T13:00:00Z",
"email",
"harborlane.bakery@example.net",
"Your weekly payout is on its way",
"delivered"
],
[
"2026-07-27T13:00:00Z",
"email",
"harborlane.bakery@example.net",
"Your weekly payout is on its way",
"delivered"
],
[
"2026-08-01T12:00:00Z",
"email",
"harborlane.bakery@example.net",
"Your July statement is ready",
"delivered"
],
[
"2026-08-03T13:00:00Z",
"email",
"harborlane.bakery@example.net",
"Your weekly payout is on its way",
"delivered"
],
"… 19 more in fraud.json"
]
},
"daily_sales": {
"period": "2026-07-07 to 2026-10-04",
"note": "Card and invoice payments by business day, local time",
"columns": [
"date",
"payments",
"gross_usd",
"refunds_usd",
"fees_usd",
"net_usd",
"disputes"
],
"rows": [
[
"2026-07-07",
142,
1701.66,
0,
59.8,
1641.86,
0
],
[
"2026-07-08",
185,
1996.23,
0,
72,
1924.23,
0
],
[
"2026-07-09",
192,
2647.13,
0,
90.14,
2556.99,
0
],
[
"2026-07-10",
248,
2636.95,
172.81,
95.47,
2368.67,
0
],
[
"2026-07-11",
283,
3437,
0,
120.41,
3316.59,
0
],
"… 73 more in fraud.json"
]
},
"payout_history": {
"columns": [
"initiated",
"type",
"destination",
"amount_usd",
"covers",
"status",
"arrived"
],
"rows": [
[
"2026-07-13T13:00:00Z",
"standard (ACH)",
"checking x2290",
14836.17,
"2026-07-06 to 2026-07-12",
"paid",
"2026-07-14"
],
[
"2026-07-20T13:00:00Z",
"standard (ACH)",
"checking x2290",
16125.96,
"2026-07-13 to 2026-07-19",
"paid",
"2026-07-21"
],
[
"2026-07-27T13:00:00Z",
"standard (ACH)",
"checking x2290",
15098.32,
"2026-07-20 to 2026-07-26",
"paid",
"2026-07-28"
],
[
"2026-08-03T13:00:00Z",
"standard (ACH)",
"checking x2290",
15069.64,
"2026-07-27 to 2026-08-02",
"paid",
"2026-08-04"
],
[
"2026-08-10T13:00:00Z",
"standard (ACH)",
"checking x2290",
15754.45,
"2026-08-03 to 2026-08-09",
"paid",
"2026-08-11"
],
"… 7 more in fraud.json"
]
},
"support_history": {
"columns": [
"ts",
"channel",
"contact",
"verification",
"summary"
],
"rows": [
[
"2025-12-02T15:20:00Z",
"phone",
"(207) 555-0163 (on file)",
"SMS code",
"Owner asked why a wholesale invoice payment showed as pending; explained ACH timing"
],
[
"2026-03-19T14:05:00Z",
"chat (app)",
"dv_a1",
"signed-in app",
"Owner ordered a second card reader; shipped"
],
[
"2026-07-28T19:40:00Z",
"chat (app)",
"dv_a1",
"signed-in app",
"Owner asked to add a tip screen to the counter iPad; walked through settings"
]
]
},
"rules_and_scores": {
"rules_fired": [
"ATO-03 Payout destination added within 1 hour of a password reset",
"ATO-07 Email on file changed and notification emails turned off in the same session",
"ATO-11 SIM change on the phone on file within 24 hours of a 2-step code",
"PAY-02 Instant payout to a destination added today",
"PAY-05 Destination holder name doesn't match the business or the owner"
],
"platform_risk_model": "0.97 (0 to 1; our queue prioritizes above 0.80)",
"device_intelligence_vendor_score": "947 (0 to 1,000, higher is riskier)"
},
"payout_under_review": {
"requested": "2026-10-05T00:21:47Z",
"session": "dv_x9 at 198.51.100.77, signed in 00:07:19Z after the password reset",
"type": "Instant payout (real-time payments network)",
"amount_usd": 14191.06,
"fee_usd": 212.87,
"available_balance_usd": 14191.06,
"covers": "all card and invoice sales from 2026-09-28 to 2026-10-04, which the weekly standard payout to x2290 would have sent on 2026-10-05",
"destination": "checking x4471 at an online bank (added 2026-10-05T00:16:05Z)",
"owner_usual": "Weekly standard payouts to x2290; no instant payout in 5 years on our platform",
"status": "Waiting in review since 00:21:48Z"
}
},
"questions": {
"takeover_likelihood": {
"type": "score",
"instructions": "How likely is it that someone other than the account holder or a user they authorized controls the session that requested the money movement under review, or the session that made the recent sign-in, contact, 2-step or payout change before it?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"access_route": {
"type": "multi_choice",
"instructions": "Which of these does the record show happened on this account in the last 30 days? Choose every one that applies, or only none_of_these.",
"criteria": {
"password_stolen": "Someone else signed in with the account holder's current password, without resetting it",
"email_taken_over": "Someone else used the email account on file, for example to open a password reset link or receive change notices",
"phone_taken_over": "Someone else took over the phone number on file (SIM swap or port-out) or replaced it with their own number",
"support_tricked": "Our support team changed a sign-in detail, contact detail or 2-step method for someone posing as the account holder",
"code_handed_over": "The account holder was tricked into reading out a one-time code or approving a sign-in for someone else",
"remote_access": "Someone operated the account holder's own device through a remote-access or screen-sharing tool",
"none_of_these": "None of these: the account holder or their authorized users made every recent change themselves"
}
},
"destination_owner": {
"type": "choice",
"instructions": "Who owns and controls the bank account or card the money movement under review would pay into?",
"criteria": {
"holder": "The account holder: the business itself or its owner, in an account they control",
"known_party": "A person or business with a real, earlier relationship to the account holder, such as a family member, employee or regular supplier",
"unrelated": "Someone with no evident relationship to the account holder, including an account opened in the holder's name by someone else",
"cannot_tell": "The records can't establish it: ownership checks are missing or inconclusive and nothing else ties the account to anyone"
}
},
"action": {
"type": "choice",
"instructions": "What should happen to the money movement under review?",
"criteria": {
"allow": "Release it as requested",
"step_up": "Release it only after the account holder confirms it with a 2-step method that existed before the recent changes and that the session under review did not use",
"hold_and_call": "Hold it and call the account holder at a phone number that was on file before the recent changes; release it only if they confirm",
"block_and_lock": "Cancel it, lock the account, end all sessions, undo the recent changes and contact the account holder through details on file before the changes"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_e8ac636151ed43df95e68bd24dd12dfc",
"model": "grayson-1",
"answers": {
"takeover_likelihood": {
"type": "score",
"score": 3.94,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.9701,
"probabilities": {
"0": 0.0084,
"1": 0.0035,
"2": 0.0035,
"3": 0.0084,
"4": 0.9761
}
},
"access_route": {
"type": "multi_choice",
"multi_choice": [
"email_taken_over",
"phone_taken_over"
],
"probabilities": {
"password_stolen": 0.0474,
"email_taken_over": 0.6792,
"phone_taken_over": 0.9579,
"support_tricked": 0.0004,
"code_handed_over": 0.0203,
"remote_access": 0.0028,
"none_of_these": 0.0159
}
},
"destination_owner": {
"type": "choice",
"choice": "unrelated",
"confidence": 0.9931,
"probabilities": {
"holder": 0.0015,
"known_party": 0.0006,
"unrelated": 0.9948,
"cannot_tell": 0.0032
}
},
"action": {
"type": "choice",
"choice": "block_and_lock",
"confidence": 0.9738,
"probabilities": {
"allow": 0.0015,
"step_up": 0.0058,
"hold_and_call": 0.0123,
"block_and_lock": 0.9804
}
}
},
"usage": {
"input_tokens": 15904,
"output_tokens": 0
}
}Open in Playground
A bike shop owner moves payouts to his new credit union account from a Las Vegas hotel. Five days after porting his number to a new carrier and moving to a new iPhone, the owner of a Madison bike shop added a new business checking account as his payout destination from a hotel in Las Vegas. The change came from his laptop, trusted since 2023, while his new phone was signed in from the same hotel; the account is in the LLC's name, and a week earlier he told support he was switching banks and going to the show in Vegas.
| Question | Grayson's answer |
|---|---|
takeover_likelihood | 0.03 of 4, confidence 98% |
access_route | none_of_these |
destination_owner | holder, confidence 99% |
action | allow, confidence 93% |
19,029 input tokens, $0.00067 per decision, answered in 253 ms.
The request, with long lists cut short. The full request is legitimate.json (59 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "ATO-26-10-0402",
"queue": "Payout review: account security",
"opened": "2026-10-08T15:21:31Z",
"records_as_of": "2026-10-08T16:05:00Z",
"local_time": "Thursday 2026-10-08, 11:05 a.m. CDT in Madison, WI"
},
"platform_controls": "Sign-in is email and password. A device not trusted in the last 30 days must also pass 2-step verification: an SMS code to the phone on file, or an authenticator app if the user has added one. The mobile app then signs in with Face ID or a fingerprint. 'Forgot password' emails a reset link to the email on file, and 2-step verification is still required after a reset. Changing the email or phone on file, adding or removing a 2-step method, and adding a payout destination each need a fresh 2-step code; we email the previous address and text the phone on file after each change. Payout destinations are business or owner checking accounts, verified by signing in to the bank through our account-verification provider (which returns the holder name and the account's open date) or by micro-deposits, and debit cards for instant payouts, checked with the card network's account name inquiry. Standard payouts go by ACH on the schedule the business picks and arrive the next business day. Instant payouts send up to $25,000 a day in minutes, to a debit card or a bank account on the real-time payments network, for a 1.5% fee, and cannot be recalled. Any payout to a destination added in the last 7 days, and any instant payout over $5,000 within 24 hours of a sign-in, contact or 2-step change, waits in this review queue. Staff with the point-of-sale role take payments on the shop's devices with a PIN and cannot see payouts or change settings.",
"business": {
"merchant_id": "mer_08826",
"legal_name": "Calder Street Cycles LLC",
"doing_business_as": "Calder Street Cycles",
"business_type": "Two-member LLC; bicycle sales and repair, MCC 5940 (bicycle shops)",
"location": "Madison, WI; open Monday to Saturday, 10 a.m. to 7 p.m.",
"on_platform_since": "2019-03-02",
"owner": {
"name": "Mateo Ferraro",
"role": "Owner and only admin",
"phone_on_file": "(608) 555-0127, since 2019-03-02",
"email_on_file": "mateo@calderstreetcycles.example.com, since 2019-03-02",
"two_step_methods": "SMS to (608) 555-0127 since 2019"
},
"products": "In-person card payments, online repair deposits, daily standard payouts",
"monthly_card_volume_usd_last_12_months": "38,000 (January) to 112,000 (June)",
"payout_schedule": "Daily standard payout each business day for the previous day's sales (Monday covers Saturday)",
"disputes_12_months": 2,
"account_status": "Active; no holds"
},
"users": {
"columns": [
"user",
"role",
"added",
"sign_in"
],
"rows": [
[
"Mateo Ferraro",
"Owner (admin)",
"2019-03-02",
"email and password, 2-step"
],
[
"Jess Okonkwo-Hale",
"Manager (no payouts or settings)",
"2024-03-15",
"email and password, 2-step"
],
[
"Liam Sorensen",
"Point of sale",
"2024-05-01",
"PIN on the shop iPad only"
]
]
},
"devices": {
"columns": [
"device_id",
"device",
"user",
"first_seen",
"trusted",
"last_seen"
],
"rows": [
[
"dv_m2",
"MacBook Pro, Chrome (macOS 15)",
"Mateo Ferraro",
"2023-06-19",
"yes, renewed 2026-09-20",
"2026-10-08T15:12:37Z"
],
[
"dv_m1",
"Pixel 7, our app (Android 15)",
"Mateo Ferraro",
"2023-02-11",
"removed by the owner 2026-10-03T17:46Z",
"2026-10-03"
],
[
"dv_m4",
"iPhone 16, our app (iOS 18)",
"Mateo Ferraro",
"2026-10-03T17:40:26Z",
"yes (Face ID)",
"2026-10-08T15:31:50Z"
],
[
"dv_m3",
"iPad Air at the counter, point-of-sale app",
"shop device (staff PINs)",
"2022-04-02",
"yes (shop device)",
"2026-10-08T14:47:50Z"
],
[
"dv_j1",
"iPhone 14, our app",
"Jess Okonkwo-Hale",
"2024-03-15",
"yes (Face ID)",
"2026-10-06"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2019-03-02T16:40:11Z",
"Account opened; owner Mateo Ferraro; email mateo@calderstreetcycles.example.com; phone (608) 555-0127",
"",
"",
"identity check passed"
],
[
"2019-03-04T14:02:50Z",
"Payout destination added: checking x5508",
"",
"",
"micro-deposits; holder name not returned"
],
[
"2022-04-02T15:15:30Z",
"Shop iPad dv_m3 set up for point of sale",
"dv_m3",
"198.51.100.120",
"owner approval in app"
],
[
"2023-02-11T15:30:44Z",
"App trusted on new phone dv_m1 (Pixel 7)",
"dv_m1",
"198.51.100.120",
"SMS code"
],
[
"2023-06-19T02:12:09Z",
"Computer trusted: dv_m2 (MacBook Pro)",
"dv_m2",
"203.0.113.19",
"SMS code"
],
"… 7 more in legitimate.json"
]
},
"payout_destinations": [
{
"destination": "checking x5508",
"added": "2019-03-04",
"status": "was default until 2026-10-08T15:21:30Z",
"ownership_check": "Micro-deposits in 2019 (no holder name returned); account name inquiry 2024-06: CALDER STREET CYCLES LLC",
"account_opened": "unknown",
"payouts_received": "About 1,500 payouts since 2019, none returned"
},
{
"destination": "business checking x0931 at a credit union in Madison, WI",
"added": "2026-10-08T15:20:13Z",
"status": "default since 15:21:30Z",
"ownership_check": "Bank login through verification provider, 2026-10-08T15:19:31Z: holder CALDER STREET CYCLES LLC (matches the legal name); authorized signer MATEO R FERRARO",
"account_opened": "2026-09-24, per the verification provider",
"payouts_received": "None yet",
"seen_elsewhere_on_platform": "Not linked to any other business on our platform"
}
],
"sign_in_history": {
"period": "2026-07-10 to 2026-10-08T16:05:00Z",
"ip_addresses": {
"198.51.100.120": "Business cable ISP, Madison WI (the shop's Wi-Fi)",
"203.0.113.19": "Residential fiber ISP, Madison WI",
"192.0.2.57": "Mobile carrier, Las Vegas NV",
"203.0.113.140": "Hotel Wi-Fi, Las Vegas NV"
},
"staff_point_of_sale_sign_ins": "78 staff PIN sign-ins on dv_m3 from 198.51.100.120, one each open day between 9:30 and 9:55 a.m. local time, all successful (Jess Okonkwo-Hale 57, Liam Sorensen 21); last 2026-10-08T14:47:50Z",
"columns": [
"ts",
"device_id",
"ip",
"method",
"result",
"activity"
],
"rows": [
[
"2026-07-10T13:02:02Z",
"dv_m1",
"198.51.100.120",
"fingerprint (app)",
"success",
"items and stock"
],
[
"2026-07-10T21:46:07Z",
"dv_j1",
"198.51.100.120",
"Face ID (app) (Jess Okonkwo-Hale)",
"success",
"refund issued"
],
[
"2026-07-14T20:36:42Z",
"dv_j1",
"198.51.100.120",
"Face ID (app) (Jess Okonkwo-Hale)",
"success",
"sales report"
],
[
"2026-07-15T02:28:08Z",
"dv_m1",
"203.0.113.19",
"fingerprint (app)",
"success",
"payouts viewed"
],
[
"2026-07-15T13:53:13Z",
"dv_m1",
"198.51.100.120",
"fingerprint (app)",
"success",
"refund issued"
],
"… 82 more in legitimate.json"
]
},
"device_intelligence": {
"vendor": "Your device intelligence vendor, scored on every sign-in and sensitive change",
"reason_code_meanings": {
"NEW_DEVICE": "Device not seen on this account before",
"NEW_LOCATION": "IP location not seen on this account in 90 days",
"PROXY_RESIDENTIAL": "IP belongs to a residential proxy network",
"VPN": "IP belongs to a commercial VPN service",
"TZ_MISMATCH": "Device timezone doesn't fit the IP location",
"FP_INCONSISTENT": "Browser fingerprint attributes contradict each other (anti-detect browser suspected)",
"FRESH_PROFILE": "Browser has no stored cookies or history",
"DIRECT_NAV": "Went straight to payout settings after sign-in",
"RESET_THEN_CHANGE": "Password reset followed by contact or payout changes in the same session",
"BEHAVIOR_MISMATCH": "Typing and pointer behavior differ from this user's profile",
"SIM_RECENT": "SIM change or port on the phone on file in the last 7 days"
},
"recent_sessions": {
"columns": [
"ts",
"device_id",
"vendor_score",
"reason_codes",
"proxy_or_vpn",
"… 4 more in legitimate.json"
],
"rows": [
[
"2026-10-03T17:40:26Z",
"dv_m4",
488,
[
"NEW_DEVICE",
"SIM_RECENT"
],
"no",
"… 4 more in legitimate.json"
],
[
"2026-10-04T16:12:55Z",
"dv_m2",
31,
[],
"no",
"… 4 more in legitimate.json"
],
[
"2026-10-06T23:48:31Z",
"dv_m4",
214,
[
"NEW_LOCATION"
],
"no",
"… 4 more in legitimate.json"
],
[
"2026-10-07T04:06:47Z",
"dv_m2",
236,
[
"NEW_LOCATION"
],
"no",
"… 4 more in legitimate.json"
],
[
"2026-10-08T15:12:37Z",
"dv_m2",
412,
[
"NEW_LOCATION",
"SIM_RECENT"
],
"no",
"… 4 more in legitimate.json"
]
]
}
},
"phone_checks": [
{
"checked": "2026-10-08T15:19:44Z",
"number": "(608) 555-0127 (on file since 2019-03-02)",
"trigger": "2-step SMS for the payout destination",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match (Ferraro)",
"sim_change": "new SIM 2026-10-03T15:52Z with the port",
"port_out": "ported to a new carrier 2026-10-03T15:52Z (first port since 2019)",
"device_change": "new handset since 2026-10-03; same handset at every check since"
},
{
"checked": "2026-10-03T17:40:12Z",
"number": "(608) 555-0127",
"trigger": "2-step SMS for the new phone",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match (Ferraro)",
"sim_change": "new SIM 2026-10-03T15:52Z",
"port_out": "ported to a new carrier 2026-10-03T15:52Z",
"device_change": "new handset"
}
],
"security_notices": {
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-08-01T12:00:00Z",
"email",
"mateo@calderstreetcycles.example.com",
"Your July statement is ready",
"delivered"
],
[
"2026-09-01T12:00:00Z",
"email",
"mateo@calderstreetcycles.example.com",
"Your August statement is ready",
"delivered"
],
[
"2026-09-20T15:02:11Z",
"SMS",
"(608) 555-0127",
"Your verification code (renew trust on this computer)",
"entered"
],
[
"2026-10-01T12:00:00Z",
"email",
"mateo@calderstreetcycles.example.com",
"Your September statement is ready",
"delivered"
],
[
"2026-10-03T17:40:14Z",
"SMS",
"(608) 555-0127",
"Your verification code. We'll never call to ask for it.",
"entered 17:40:24Z on dv_m4"
],
"… 5 more in legitimate.json"
]
},
"daily_sales": {
"period": "2026-07-10 to 2026-10-07",
"note": "Card payments by business day, local time",
"columns": [
"date",
"payments",
"gross_usd",
"refunds_usd",
"fees_usd",
"net_usd",
"disputes"
],
"rows": [
[
"2026-07-10",
48,
4453.16,
0,
121.47,
4331.69,
0
],
[
"2026-07-11",
53,
4630.26,
0,
126.61,
4503.65,
0
],
[
"2026-07-13",
36,
3496.24,
38.68,
95.2,
3362.36,
0
],
[
"2026-07-14",
46,
4027.92,
92.93,
110.13,
3824.86,
0
],
[
"2026-07-15",
44,
4383.71,
0,
119.25,
4264.46,
0
],
"… 72 more in legitimate.json"
]
},
"payout_history": {
"columns": [
"initiated",
"type",
"destination",
"amount_usd",
"covers",
"status",
"arrived"
],
"rows": [
[
"2026-07-10T21:00:00Z",
"standard (ACH)",
"checking x5508",
4163.43,
"2026-07-09",
"paid",
"2026-07-13"
],
[
"2026-07-13T21:00:00Z",
"standard (ACH)",
"checking x5508",
8835.34,
"2026-07-10 to 2026-07-11",
"paid",
"2026-07-14"
],
[
"2026-07-14T21:00:00Z",
"standard (ACH)",
"checking x5508",
3362.36,
"2026-07-13",
"paid",
"2026-07-15"
],
[
"2026-07-15T21:00:00Z",
"standard (ACH)",
"checking x5508",
3824.86,
"2026-07-14",
"paid",
"2026-07-16"
],
[
"2026-07-16T21:00:00Z",
"standard (ACH)",
"checking x5508",
4264.46,
"2026-07-15",
"paid",
"2026-07-17"
],
"… 58 more in legitimate.json"
]
},
"support_history": {
"columns": [
"ts",
"channel",
"contact",
"verification",
"summary"
],
"rows": [
[
"2025-10-08T18:20:00Z",
"chat (app)",
"dv_m1, from Las Vegas NV",
"signed-in app",
"Owner at a bicycle industry trade show in Las Vegas asked how to see the shop's sales live on his phone; showed him the live sales view"
],
[
"2026-02-14T16:05:00Z",
"phone",
"(608) 555-0127 (on file)",
"SMS code",
"Owner asked about a chargeback on a repair; helped him submit receipts (won)"
],
[
"2026-10-02T19:12:00Z",
"chat (web)",
"dv_m2 at 198.51.100.120",
"signed-in web",
"Owner: 'We're moving our business checking to the credit union, account opens next week. How do I switch payouts so nothing gets lost? I'll be at the show in Vegas next week.' Agent explained adding a destination by bank login and that the first payout to it goes through review"
]
]
},
"rules_and_scores": {
"rules_fired": [
"PAY-01 Payout to a destination added today",
"ATO-09 Payout destination added within 7 days of a port or SIM change on the phone on file",
"ATO-12 Sensitive change from an IP location not seen in 90 days"
],
"platform_risk_model": "0.31 (0 to 1; our queue prioritizes above 0.80)",
"device_intelligence_vendor_score": "412 (0 to 1,000, higher is riskier)"
},
"payout_under_review": {
"scheduled": "2026-10-08T21:00:00Z",
"session": "Scheduled daily payout; destination set from dv_m2 at 203.0.113.140 at 15:21:30Z",
"type": "Standard payout (ACH), arrives next business day",
"amount_usd": 2123.03,
"available_balance_usd": 2123.03,
"covers": "card sales on 2026-10-07",
"destination": "business checking x0931 at a credit union (added 2026-10-08T15:20:13Z)",
"owner_usual": "Daily standard payouts to x5508; no instant payouts",
"status": "Waiting in review since 15:21:31Z"
}
},
"questions": {
"takeover_likelihood": {
"type": "score",
"instructions": "How likely is it that someone other than the account holder or a user they authorized controls the session that requested the money movement under review, or the session that made the recent sign-in, contact, 2-step or payout change before it?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"access_route": {
"type": "multi_choice",
"instructions": "Which of these does the record show happened on this account in the last 30 days? Choose every one that applies, or only none_of_these.",
"criteria": {
"password_stolen": "Someone else signed in with the account holder's current password, without resetting it",
"email_taken_over": "Someone else used the email account on file, for example to open a password reset link or receive change notices",
"phone_taken_over": "Someone else took over the phone number on file (SIM swap or port-out) or replaced it with their own number",
"support_tricked": "Our support team changed a sign-in detail, contact detail or 2-step method for someone posing as the account holder",
"code_handed_over": "The account holder was tricked into reading out a one-time code or approving a sign-in for someone else",
"remote_access": "Someone operated the account holder's own device through a remote-access or screen-sharing tool",
"none_of_these": "None of these: the account holder or their authorized users made every recent change themselves"
}
},
"destination_owner": {
"type": "choice",
"instructions": "Who owns and controls the bank account or card the money movement under review would pay into?",
"criteria": {
"holder": "The account holder: the business itself or its owner, in an account they control",
"known_party": "A person or business with a real, earlier relationship to the account holder, such as a family member, employee or regular supplier",
"unrelated": "Someone with no evident relationship to the account holder, including an account opened in the holder's name by someone else",
"cannot_tell": "The records can't establish it: ownership checks are missing or inconclusive and nothing else ties the account to anyone"
}
},
"action": {
"type": "choice",
"instructions": "What should happen to the money movement under review?",
"criteria": {
"allow": "Release it as requested",
"step_up": "Release it only after the account holder confirms it with a 2-step method that existed before the recent changes and that the session under review did not use",
"hold_and_call": "Hold it and call the account holder at a phone number that was on file before the recent changes; release it only if they confirm",
"block_and_lock": "Cancel it, lock the account, end all sessions, undo the recent changes and contact the account holder through details on file before the changes"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_0d1f266f5a664f3a9f1660d5f3e042b8",
"model": "grayson-1",
"answers": {
"takeover_likelihood": {
"type": "score",
"score": 0.031,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.9755,
"probabilities": {
"0": 0.9804,
"1": 0.014,
"2": 0.0019,
"3": 0.0013,
"4": 0.0024
}
},
"access_route": {
"type": "multi_choice",
"multi_choice": [
"none_of_these"
],
"probabilities": {
"password_stolen": 0.0124,
"email_taken_over": 0.018,
"phone_taken_over": 0.0421,
"support_tricked": 0.0002,
"code_handed_over": 0.0013,
"remote_access": 0.0006,
"none_of_these": 0.9627
}
},
"destination_owner": {
"type": "choice",
"choice": "holder",
"confidence": 0.9921,
"probabilities": {
"holder": 0.9941,
"known_party": 0.001,
"unrelated": 0.0008,
"cannot_tell": 0.0041
}
},
"action": {
"type": "choice",
"choice": "allow",
"confidence": 0.9302,
"probabilities": {
"allow": 0.9477,
"step_up": 0.0197,
"hold_and_call": 0.0153,
"block_and_lock": 0.0174
}
}
},
"usage": {
"input_tokens": 19029,
"output_tokens": 0
}
}Open in Playground
A yoga studio's first web sign-in in two months sends $9,850 to a week-old account in the owner's name. Two days after membership renewals, a new Windows laptop at a Denver coworking space signed in as the studio's owner with her current password and an SMS code to her unchanged phone, added a personal checking account opened on September 29 in her name at an address we don't know, asked for a $9,850 instant payout and then pressed support to release it, saying she couldn't take calls. She has taken two smaller instant payouts after renewals before, always from her iPhone to her debit card, and her iPhone was last seen at home that morning.
| Question | Grayson's answer |
|---|---|
takeover_likelihood | 0.64 of 4, confidence 61% (Very unlikely 69%, Unlikely 15%, Uncertain 6%, Likely 5%, Very likely 6%) |
access_route | none_of_these |
destination_owner | holder, confidence 84% |
action | block_and_lock, confidence 22% |
15,041 input tokens, $0.00053 per decision, answered in 227 ms.
The request, with long lists cut short. The full request is ambiguous.json (48 KB).
{
"model": "grayson-1",
"state": {
"case": {
"case_id": "ATO-26-10-0395",
"queue": "Payout review: account security",
"opened": "2026-10-07T17:38:41Z",
"records_as_of": "2026-10-07T17:52:00Z",
"local_time": "Wednesday 2026-10-07, 11:52 a.m. MDT in Denver, CO"
},
"platform_controls": "Sign-in is email and password. A device not trusted in the last 30 days must also pass 2-step verification: an SMS code to the phone on file, or an authenticator app if the user has added one. The mobile app then signs in with Face ID or a fingerprint. 'Forgot password' emails a reset link to the email on file, and 2-step verification is still required after a reset. Changing the email or phone on file, adding or removing a 2-step method, and adding a payout destination each need a fresh 2-step code; we email the previous address and text the phone on file after each change. Payout destinations are business or owner checking accounts, verified by signing in to the bank through our account-verification provider (which returns the holder name and the account's open date) or by micro-deposits, and debit cards for instant payouts, checked with the card network's account name inquiry. Standard payouts go by ACH on the schedule the business picks and arrive the next business day. Instant payouts send up to $25,000 a day in minutes, to a debit card or a bank account on the real-time payments network, for a 1.5% fee, and cannot be recalled. Any payout to a destination added in the last 7 days, and any instant payout over $5,000 within 24 hours of a sign-in, contact or 2-step change, waits in this review queue. Staff with the point-of-sale role take payments on the shop's devices with a PIN and cannot see payouts or change settings.",
"business": {
"merchant_id": "mer_15532",
"legal_name": "Fern and Ash Yoga LLC",
"doing_business_as": "Fern & Ash Yoga",
"business_type": "Single-member LLC; yoga studio, MCC 7997 (membership clubs)",
"location": "Denver, CO; classes daily from 6 a.m.",
"on_platform_since": "2022-01-10",
"owner": {
"name": "Hannah Lindqvist",
"role": "Owner and only admin",
"phone_on_file": "(720) 555-0144, since 2022-01-10",
"email_on_file": "hello.fernandash@example.net, since 2022-01-10",
"two_step_methods": "SMS to (720) 555-0144 since 2022"
},
"products": "Monthly memberships billed on the 5th to cards on file, class packs and drop-ins at the front desk, workshops sold online; weekly standard payouts; instant payouts since 2026-07",
"monthly_card_volume_usd_last_12_months": "21,000 to 27,500",
"payout_schedule": "Weekly standard payout every Friday for the previous Friday to Thursday",
"disputes_12_months": 3,
"account_status": "Active; no holds",
"external_data": "The owner's email address appears in a 2025 breach of a fitness booking site (email and name only; no password in the breach data)"
},
"users": {
"columns": [
"user",
"role",
"added",
"sign_in"
],
"rows": [
[
"Hannah Lindqvist",
"Owner (admin)",
"2022-01-10",
"email and password, 2-step"
],
[
"Rosa Delgado-Finch",
"Point of sale",
"2023-05-20",
"PIN on the front-desk iPad only"
]
]
},
"devices": {
"columns": [
"device_id",
"device",
"user",
"first_seen",
"trusted",
"last_seen"
],
"rows": [
[
"dv_h1",
"iPhone 15, our app (iOS 18)",
"Hannah Lindqvist",
"2023-11-04",
"yes (Face ID)",
"2026-10-07T14:10:02Z"
],
[
"dv_h2",
"MacBook Air, Safari (macOS 13)",
"Hannah Lindqvist",
"2022-01-10",
"trust expired 2025-09 (renewed 2026-08-11 with SMS code)",
"2026-08-11T02:30:19Z"
],
[
"dv_h3",
"iPad at the front desk, point-of-sale app",
"shop device (staff PINs)",
"2022-02-01",
"yes (shop device)",
"2026-10-07T11:34:43Z"
],
[
"dv_h8",
"Windows 11, Edge",
"attempted as Hannah Lindqvist",
"2026-10-04T08:12:37Z",
"no",
"2026-10-04T08:12:37Z"
],
[
"dv_h9",
"Windows 11, Chrome 129",
"signed in as Hannah Lindqvist",
"2026-10-07T17:31:12Z",
"no (2-step passed; 'trust this device' not ticked)",
"2026-10-07T17:38:40Z"
]
]
},
"credential_and_contact_changes": {
"columns": [
"ts",
"change",
"device_id",
"ip",
"verification"
],
"rows": [
[
"2022-01-10T18:22:40Z",
"Account opened; owner Hannah Lindqvist; email hello.fernandash@example.net; phone (720) 555-0144",
"dv_h2",
"203.0.113.150",
"identity check passed"
],
[
"2022-01-12T16:05:31Z",
"Payout destination added: checking x3346",
"dv_h2",
"203.0.113.150",
"bank login through verification provider; holder FERN AND ASH YOGA LLC"
],
[
"2022-02-01T15:40:02Z",
"Front-desk iPad dv_h3 set up for point of sale",
"dv_h3",
"198.51.100.205",
"owner approval in app"
],
[
"2023-05-20T17:12:48Z",
"User added: Rosa Delgado-Finch, point-of-sale role",
"dv_h2",
"198.51.100.205",
"SMS code"
],
[
"2023-11-04T03:01:19Z",
"App trusted on new phone dv_h1 (iPhone 15)",
"dv_h1",
"203.0.113.150",
"SMS code"
],
[
"2025-03-08T16:44:00Z",
"Password changed",
"dv_h1",
"203.0.113.150",
"current password"
],
[
"2026-07-06T13:58:21Z",
"Debit card x8812 added for instant payouts",
"dv_h1",
"203.0.113.150",
"SMS code; card network name inquiry: HANNAH M LINDQVIST (matches the owner)"
],
[
"2026-10-07T17:35:26Z",
"Payout destination added: personal checking x6075 at an online bank, enabled for instant payouts",
"dv_h9",
"203.0.113.201",
"SMS code to (720) 555-0144, entered 17:35:09Z; bank login through verification provider"
]
]
},
"payout_destinations": [
{
"destination": "checking x3346",
"added": "2022-01-12",
"status": "default; weekly payouts",
"ownership_check": "Bank login through verification provider, 2022-01-12: holder FERN AND ASH YOGA LLC (matches the legal name)",
"account_opened": "2021-11-30",
"payouts_received": "All 247 payouts since 2022-01, none returned"
},
{
"destination": "Visa debit x8812",
"added": "2026-07-06",
"status": "instant payouts only",
"ownership_check": "Card network account name inquiry: HANNAH M LINDQVIST (matches the owner)",
"issuer": "A large national bank",
"payouts_received": "2 instant payouts (2026-07-06, 2026-09-07)"
},
{
"destination": "personal checking x6075 at an online bank",
"added": "2026-10-07T17:35:26Z",
"status": "not default; chosen for the instant payout under review",
"ownership_check": "Bank login through verification provider, 2026-10-07T17:34:52Z: holder HANNAH M LINDQVIST (matches the owner's name; a personal account, not the LLC's)",
"holder_address_at_bank": "An apartment in Aurora, CO; not the home or studio address we hold for her, and not in her identity check at onboarding",
"holder_phone_and_email_at_bank": "Not returned by the provider",
"account_opened": "2026-09-29, per the verification provider",
"balance_at_verification_usd": 0,
"seen_elsewhere_on_platform": "Not linked to any other business on our platform"
}
],
"sign_in_history": {
"period": "2026-07-09 to 2026-10-07T17:52:00Z",
"ip_addresses": {
"198.51.100.205": "Business cable ISP, Denver CO (the studio's Wi-Fi)",
"192.0.2.88": "Mobile carrier, Denver CO",
"203.0.113.150": "Residential cable ISP, Denver CO",
"198.51.100.244": "Commercial VPN service, exit in Denver CO",
"203.0.113.201": "Business fiber ISP, Denver CO (a coworking space network; 11 other businesses on our platform sign in from it)"
},
"staff_point_of_sale_sign_ins": "91 staff PIN sign-ins on dv_h3 from 198.51.100.205, one each open day between 5:30 and 5:55 a.m. local time, all successful (Rosa Delgado-Finch 59, Hannah Lindqvist 32); last 2026-10-07T11:34:43Z",
"columns": [
"ts",
"device_id",
"ip",
"method",
"result",
"activity"
],
"rows": [
[
"2026-07-09T19:23:51Z",
"dv_h1",
"192.0.2.88",
"Face ID (app)",
"success",
"payouts viewed"
],
[
"2026-07-10T13:09:11Z",
"dv_h1",
"203.0.113.150",
"Face ID (app)",
"success",
"class bookings"
],
[
"2026-07-10T23:01:48Z",
"dv_h1",
"198.51.100.205",
"Face ID (app)",
"success",
"sales summary"
],
[
"2026-07-11T13:20:09Z",
"dv_h1",
"203.0.113.150",
"Face ID (app)",
"success",
"memberships"
],
[
"2026-07-12T13:57:24Z",
"dv_h1",
"203.0.113.150",
"Face ID (app)",
"success",
"sales summary"
],
"… 63 more in ambiguous.json"
]
},
"device_intelligence": {
"vendor": "Your device intelligence vendor, scored on every sign-in and sensitive change",
"reason_code_meanings": {
"NEW_DEVICE": "Device not seen on this account before",
"NEW_LOCATION": "IP location not seen on this account in 90 days",
"PROXY_RESIDENTIAL": "IP belongs to a residential proxy network",
"VPN": "IP belongs to a commercial VPN service",
"TZ_MISMATCH": "Device timezone doesn't fit the IP location",
"FP_INCONSISTENT": "Browser fingerprint attributes contradict each other (anti-detect browser suspected)",
"FRESH_PROFILE": "Browser has no stored cookies or history",
"DIRECT_NAV": "Went straight to payout settings after sign-in",
"RESET_THEN_CHANGE": "Password reset followed by contact or payout changes in the same session",
"BEHAVIOR_MISMATCH": "Typing and pointer behavior differ from this user's profile",
"SIM_RECENT": "SIM change or port on the phone on file in the last 7 days"
},
"recent_sessions": {
"columns": [
"ts",
"device_id",
"vendor_score",
"reason_codes",
"proxy_or_vpn",
"… 4 more in ambiguous.json"
],
"rows": [
[
"2026-09-07T13:48:05Z",
"dv_h1",
64,
[],
"no",
"… 4 more in ambiguous.json"
],
[
"2026-10-04T08:12:37Z",
"dv_h8",
702,
[
"NEW_DEVICE",
"VPN"
],
"commercial VPN",
"… 4 more in ambiguous.json"
],
[
"2026-10-06T13:55:30Z",
"dv_h1",
41,
[],
"no",
"… 4 more in ambiguous.json"
],
[
"2026-10-07T14:10:02Z",
"dv_h1",
38,
[],
"no",
"… 4 more in ambiguous.json"
],
[
"2026-10-07T17:31:12Z",
"dv_h9",
655,
[
"NEW_DEVICE",
"FRESH_PROFILE",
"DIRECT_NAV"
],
"no",
"… 4 more in ambiguous.json"
]
]
}
},
"phone_checks": [
{
"checked": "2026-10-07T17:31:00Z",
"number": "(720) 555-0144 (on file since 2022-01-10)",
"trigger": "2-step SMS at sign-in",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match (Lindqvist)",
"sim_change": "none in 90 days",
"port_out": "none",
"device_change": "same handset as at every check since 2023-11",
"call_forwarding": "not active"
},
{
"checked": "2026-10-07T17:35:00Z",
"number": "(720) 555-0144",
"trigger": "2-step SMS for the payout destination",
"line_type": "mobile, postpaid",
"subscriber_name_match": "match",
"sim_change": "none in 90 days",
"port_out": "none",
"device_change": "none",
"call_forwarding": "not active"
}
],
"security_notices": {
"columns": [
"ts",
"channel",
"to",
"message",
"outcome"
],
"rows": [
[
"2026-07-06T13:58:22Z",
"email",
"hello.fernandash@example.net",
"A debit card ending 8812 was added for instant payouts",
"delivered"
],
[
"2026-08-01T12:00:00Z",
"email",
"hello.fernandash@example.net",
"Your July statement is ready",
"delivered"
],
[
"2026-08-11T02:29:40Z",
"SMS",
"(720) 555-0144",
"Your verification code (renew trust on this computer)",
"entered"
],
[
"2026-09-01T12:00:00Z",
"email",
"hello.fernandash@example.net",
"Your August statement is ready",
"delivered"
],
[
"2026-10-01T12:00:00Z",
"email",
"hello.fernandash@example.net",
"Your September statement is ready",
"delivered"
],
"… 5 more in ambiguous.json"
]
},
"daily_sales": {
"period": "2026-07-09 to 2026-10-06",
"note": "Card payments by day, local time; memberships renew on the 5th",
"columns": [
"date",
"payments",
"gross_usd",
"refunds_usd",
"fees_usd",
"net_usd",
"disputes"
],
"rows": [
[
"2026-07-09",
15,
388.12,
0,
12.17,
375.95,
0
],
[
"2026-07-10",
8,
221.3,
0,
6.89,
214.41,
0
],
[
"2026-07-11",
22,
532.7,
0,
16.85,
515.85,
0
],
[
"2026-07-12",
23,
606.93,
55.43,
18.99,
532.51,
0
],
[
"2026-07-13",
14,
373.74,
0,
11.68,
362.06,
0
],
"… 85 more in ambiguous.json"
]
},
"payout_history": {
"columns": [
"initiated",
"type",
"destination",
"amount_usd",
"covers",
"status",
"arrived"
],
"rows": [
[
"2026-07-10T15:00:00Z",
"standard (ACH)",
"checking x3346",
12210.6,
"2026-07-03 to 2026-07-09",
"paid",
"2026-07-13"
],
[
"2026-07-17T15:00:00Z",
"standard (ACH)",
"checking x3346",
2526.79,
"2026-07-10 to 2026-07-16",
"paid",
"2026-07-20"
],
[
"2026-07-24T15:00:00Z",
"standard (ACH)",
"checking x3346",
2624.96,
"2026-07-17 to 2026-07-23",
"paid",
"2026-07-27"
],
[
"2026-07-31T15:00:00Z",
"standard (ACH)",
"checking x3346",
3496.91,
"2026-07-24 to 2026-07-30",
"paid",
"2026-08-03"
],
[
"2026-08-07T15:00:00Z",
"standard (ACH)",
"checking x3346",
14744.07,
"2026-07-31 to 2026-08-06",
"paid",
"2026-08-10"
],
"… 9 more in ambiguous.json"
]
},
"support_history": {
"columns": [
"ts",
"channel",
"contact",
"verification",
"summary"
],
"rows": [
[
"2025-11-21T16:30:00Z",
"phone",
"(720) 555-0144 (on file)",
"SMS code",
"Owner asked how to pause a member's recurring membership; explained"
],
[
"2026-04-02T21:15:00Z",
"chat (app)",
"dv_h1",
"signed-in app",
"Owner asked whether we offer business loans; told her she isn't eligible for an offer yet"
],
[
"2026-09-18T19:03:00Z",
"chat (app)",
"dv_h1",
"signed-in app",
"Owner asked whether instant payouts can go to a bank account instead of a card and whether the $25,000 daily limit can be raised. Agent: bank accounts on the real-time network can be added for instant payouts; limit stays $25,000"
],
[
"2026-10-07T17:44:10Z",
"chat (web)",
"dv_h9 at 203.0.113.201",
"signed-in web session under review",
"'Hi, my instant payout says it is in review. I need it today to pay my landlord, can you release it?' Agent: reviews usually finish within the hour. 'Ok please hurry, I can't take calls right now, I'm teaching all afternoon.' No reply since 17:46Z"
]
]
},
"rules_and_scores": {
"rules_fired": [
"PAY-02 Instant payout to a destination added today",
"PAY-07 Instant payout over $5,000 within 24 hours of a new-device sign-in",
"PAY-09 Instant payout more than twice the account's largest earlier instant payout"
],
"platform_risk_model": "0.58 (0 to 1; our queue prioritizes above 0.80)",
"device_intelligence_vendor_score": "655 (0 to 1,000, higher is riskier)"
},
"payout_under_review": {
"requested": "2026-10-07T17:38:40Z",
"session": "dv_h9 at 203.0.113.201, signed in 17:31:12Z with the current password and an SMS code",
"type": "Instant payout (real-time payments network)",
"amount_usd": 9850,
"fee_usd": 147.75,
"available_balance_usd": 14977.74,
"covers": "part of the balance from 2026-10-02 onward, including the October 5 membership renewals",
"destination": "personal checking x6075 at an online bank (added 2026-10-07T17:35:26Z)",
"owner_usual": "Weekly standard payouts to x3346 on Fridays; instant payouts of $2,400 and $3,100 to debit card x8812, each from her iPhone at home within two days of the monthly renewals",
"status": "Waiting in review since 17:38:41Z"
}
},
"questions": {
"takeover_likelihood": {
"type": "score",
"instructions": "How likely is it that someone other than the account holder or a user they authorized controls the session that requested the money movement under review, or the session that made the recent sign-in, contact, 2-step or payout change before it?",
"criteria": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"access_route": {
"type": "multi_choice",
"instructions": "Which of these does the record show happened on this account in the last 30 days? Choose every one that applies, or only none_of_these.",
"criteria": {
"password_stolen": "Someone else signed in with the account holder's current password, without resetting it",
"email_taken_over": "Someone else used the email account on file, for example to open a password reset link or receive change notices",
"phone_taken_over": "Someone else took over the phone number on file (SIM swap or port-out) or replaced it with their own number",
"support_tricked": "Our support team changed a sign-in detail, contact detail or 2-step method for someone posing as the account holder",
"code_handed_over": "The account holder was tricked into reading out a one-time code or approving a sign-in for someone else",
"remote_access": "Someone operated the account holder's own device through a remote-access or screen-sharing tool",
"none_of_these": "None of these: the account holder or their authorized users made every recent change themselves"
}
},
"destination_owner": {
"type": "choice",
"instructions": "Who owns and controls the bank account or card the money movement under review would pay into?",
"criteria": {
"holder": "The account holder: the business itself or its owner, in an account they control",
"known_party": "A person or business with a real, earlier relationship to the account holder, such as a family member, employee or regular supplier",
"unrelated": "Someone with no evident relationship to the account holder, including an account opened in the holder's name by someone else",
"cannot_tell": "The records can't establish it: ownership checks are missing or inconclusive and nothing else ties the account to anyone"
}
},
"action": {
"type": "choice",
"instructions": "What should happen to the money movement under review?",
"criteria": {
"allow": "Release it as requested",
"step_up": "Release it only after the account holder confirms it with a 2-step method that existed before the recent changes and that the session under review did not use",
"hold_and_call": "Hold it and call the account holder at a phone number that was on file before the recent changes; release it only if they confirm",
"block_and_lock": "Cancel it, lock the account, end all sessions, undo the recent changes and contact the account holder through details on file before the changes"
}
}
}
}The response. Probabilities and confidence are shortened to four decimals here, and the score to three; responses carry full precision.
{
"id": "dec_2e4b938a708c4d68bf04f68b6a6de557",
"model": "grayson-1",
"answers": {
"takeover_likelihood": {
"type": "score",
"score": 0.639,
"legend": {
"0": "Very unlikely (under 10%)",
"1": "Unlikely (10-40%)",
"2": "Uncertain (40-60%)",
"3": "Likely (60-90%)",
"4": "Very likely (over 90%)"
},
"confidence": 0.6063,
"probabilities": {
"0": 0.6851,
"1": 0.1529,
"2": 0.0562,
"3": 0.0496,
"4": 0.0562
}
},
"access_route": {
"type": "multi_choice",
"multi_choice": [
"none_of_these"
],
"probabilities": {
"password_stolen": 0.0953,
"email_taken_over": 0.0203,
"phone_taken_over": 0.0006,
"support_tricked": 0.0004,
"code_handed_over": 0.023,
"remote_access": 0.0032,
"none_of_these": 0.5927
}
},
"destination_owner": {
"type": "choice",
"choice": "holder",
"confidence": 0.8385,
"probabilities": {
"holder": 0.8789,
"known_party": 0.0052,
"unrelated": 0.0438,
"cannot_tell": 0.0721
}
},
"action": {
"type": "choice",
"choice": "block_and_lock",
"confidence": 0.2237,
"probabilities": {
"allow": 0.4177,
"step_up": 0.0823,
"hold_and_call": 0.0823,
"block_and_lock": 0.4177
}
}
},
"usage": {
"input_tokens": 15041,
"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.
takeover_likelihoodandaction: cancel and lock automatically when the sum of "Likely" and "Very likely" passes a high cutoff, and act onactionwhen its top option is well ahead. When probability is split between releasing and blocking, as in the ambiguous example, neither is safe: hold the money and call the owner at the number on file.access_routetells your team what to repair along with the money: rebind the phone number with the carrier after a SIM swap, tell the owner to secure their email before resetting the password again, or review the support contact that changed a login detail.destination_ownersets the stakes. A payout to an account the holder controls loses nothing even if the session is odd, while an account in the holder's name opened last week can belong to whoever opened it, so act onactionrather than on a name match alone.
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
Takeover rules fire on every new device, password reset, new payout account and unfamiliar location, and most of those are owners who bought a phone, switched banks or went on a trip. The few real takeovers pass the same checks a real owner does: an attacker with the owner's email and phone number gets every code. What separates them is the sequence and its context, such as a SIM change an hour before a reset, the owner's own phone active at home while another computer fails passwords, or an owner who told support last week that he was switching banks.
What to send
Send the money movement with the records an analyst would pull to decide who was at the keyboard. The examples use about 15,000 to 19,000 input tokens.
- Every credential, contact and payout change, with the device, IP address and the factor that approved it. Changes made right after a reset, especially to the email, 2-step methods and notifications, are the core of a takeover.
- Months of sign-ins, including failures and staff logins. The owner's usual devices, places and hours are what make a new session stand out, and a trusted device active elsewhere at the same time is strong evidence.
- Your device intelligence vendor's results, per session: score, reason codes, proxy or VPN, remote-access tools, emulators, timezone against IP location, and behavioral similarity to the user's profile.
- Carrier checks on the phone on file: recent SIM changes, port-outs and new handsets, with their times. A code to a phone that changed hands an hour earlier proves nothing.
- The destination's ownership checks: the holder name your account-verification provider or the card network returned, and how long ago the account was opened.
- Payout and sales history, so the amount, speed and destination can be compared with what the business usually does.
- Support contacts and security notices, including what the owner told you before the change and whether anyone answered the "Not you?" messages.
Add your own policy
How much proof a payout needs after a phone change is a policy choice, so put your rule in the request and Grayson applies it. This one never releases the first payout to a new destination within 14 days of a port, SIM change or new handset without a call to the owner.
Your rule after a phone port adds this to the state of the legitimate example:
{
"payout_review_policy": "Payout review policy, section 3 (rev. 2026-07): The first payout to a payout destination added within 14 days of a port, SIM change or new handset on the phone on file is never released on device, location, support-chat or ownership-check evidence alone, and an SMS code to that phone doesn't count as confirmation. Hold the payout and call the owner at the phone number on file; release it only after the owner confirms the new destination on that call and answers our account questions. Cancel the payout and lock the account only when the evidence shows someone other than the owner made the change."
}| Question | Without | With your rule after a phone port |
|---|---|---|
takeover_likelihood | 0.03 of 4, confidence 98% | 0.06 of 4, confidence 95% |
access_route | none_of_these | none_of_these |
destination_owner | holder, confidence 99% | holder, confidence 99% |
action | allow, confidence 93% | hold_and_call, confidence 90% |
Applied to the likely legitimate example: the bike shop owner ported his number to a new carrier five days before adding the credit union account, so the action moves from releasing the payout to holding it for a call, while the takeover likelihood and the destination stay the same.
Where to call it
- When a payout, transfer or withdrawal is requested within days of a new device or a sign-in, contact, 2-step or payout-destination change, before it leaves, and again for the first payout to a new destination.
- On instant and real-time payments, where the money can't be recalled, even when the payout follows the owner's usual schedule.
- When the answer is uncertain, hold the money and route the case to an analyst who calls the owner at a number that was on file before the changes.
Cost and latency
| Example | Input tokens | Per decision | Per 1,000 decisions | Latency |
|---|---|---|---|---|
| Obvious | 15,904 | $0.00056 | $0.56 | 243 ms |
| Legitimate | 19,029 | $0.00067 | $0.67 | 253 ms |
| Ambiguous | 15,041 | $0.00053 | $0.53 | 227 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/account-takeover-detection/questions.json --label takeover_likelihood=<column> --label access_route=<column> --label destination_owner=<column> --label action=<column>Each --label names the column with that question's right answer:
takeover_likelihood: a level, such as "Very likely (over 90%)"access_route: option keys separated by|(password_stolen,email_taken_over,phone_taken_over,support_tricked,code_handed_over,remote_access,none_of_these)destination_owner:holder,known_party,unrelated,cannot_tellaction:allow,step_up,hold_and_call,block_and_lock
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
Doesn't a correct 2-step code mean the account holder was there?
No. A code proves someone had the phone number or the email at that moment. SIM swaps, port-outs, a phone number changed earlier in the same session and a code read out to a caller posing as your support team all pass it. That is why step_up uses a method that existed before the changes and that the session under review did not use, and why carrier checks belong in the state.
Does this work for consumer accounts, not just businesses?
Yes. The examples are small-business payouts, but the decision is the same for a transfer out of a personal account, a withdrawal from a brokerage or wallet, a loan disbursement or a payroll run: send the sign-ins, devices, changes, payees and the money movement, and describe your controls in plain words as the examples do.
What about customers who are tricked into sending the money themselves?
That is a scam, not a takeover: the account holder is in control and authorizes the payment. access_route flags the overlap, a code handed over or a remote-access session, and the scam payment recipe asks the questions for payments the customer makes under someone else's direction.
Related recipes
Triage dark web credential and card alerts
Match a dark web alert to the customer, judge whether the exposure still works, and choose the response.
Detect business email compromise in vendor payments
Catch payments to a vendor's new bank account after a fake or compromised change request.
Stop scam payments before they're sent
Catch authorised push payment scams in the payment flow, and choose release, warn, hold and call, or block.
Recipes
Every use case, with its questions and cost per decision.
Account security
Who is really in control of an account: takeovers, exposed credentials and employee access to customer accounts. Ready-to-run Grayson recipes with real responses, cost and latency.
Dark web alerts
Grayson triages dark web alerts: whether a leaked password, bank log or card listing matches a customer, whether it still works, and what to do about it.