Detect fraudulent incoming ACH credits and transfers
Decide whether an incoming ACH credit is the proceeds of fraud at the sender, and whether to release, hold or return it, from account, login and transfer data.
Grayson tells a receiving bank or fintech whether an incoming ACH credit or transfer is likely the proceeds of fraud at the sender, how likely its own customer is acting as a money mule, and whether to release the funds, hold them while it contacts the sending bank, or return the credit. It reads the account profile, recent logins and profile changes, the credit itself and what happened after it posted, and costs about $0.05 per 1,000 decisions.
- Decides: Release, hold or return an incoming credit that may be proceeds of BEC, account takeover or payroll diversion.
- Call it: When a large or out-of-pattern incoming ACH credit or transfer posts
- Questions: 1 yes/no, 1 score, 1 choice
- Cost: $0.000050 per decision, $0.05 per 1,000, for this example's 1,414 input tokens
- Latency: 173 ms for this example, the median of 5 calls through api.finic.ai from US-West
Example
A rideshare driver's six-month-old checking account receives a $38,400 corporate vendor payment addressed to a supply company, three days after a new device linked a crypto exchange account, and money starts leaving within minutes.
| Question | Grayson's answer |
|---|---|
proceeds_of_fraud | Yes, P(yes) 82% |
mule_likelihood | Very likely (over 90%), 68% |
action | hold_and_contact, 91% |
Each percentage is Grayson's probability for the answer shown; for a yes/no question it's the probability of yes. A multiple-choice answer lists the options at 50% or more.
{
"model": "grayson-1",
"context": {
"review": {
"as_of": "2026-10-07T15:10:00Z",
"trigger": "Incoming ACH credit over $10,000 to a consumer account, more than 10 times the account's largest prior credit"
},
"account": {
"account": "Personal checking x7302",
"institution": "Harbor Federal Credit Union",
"owners": [
"Dana R. Whitfield"
],
"opened": "2026-04-18",
"opening_channel": "Online application",
"identity_verification": "Passed (government ID and selfie match), 2026-04-18",
"stated_occupation": "Rideshare and delivery driver",
"stated_expected_monthly_deposits_usd": 3000,
"average_balance_90d_usd": 412.37,
"largest_prior_credit_usd": 1184.2,
"usual_credits": "Weekly rideshare platform payouts of $550 to $1,200; occasional P2P payments from 2 recurring senders",
"business_relationships_on_file": "None",
"prior_alerts": "None",
"daily_p2p_limit_usd": 2500
},
"events_before_credit": [
{
"ts": "2026-10-01T23:13:44Z",
"type": "login",
"device": "iPhone, known since 2026-04-18",
"ip": "198.51.100.23",
"ip_location": "Columbus, OH"
},
{
"ts": "2026-10-04T18:02:10Z",
"type": "login",
"device": "Windows PC, Chrome, first seen",
"ip": "203.0.113.77",
"ip_location": "Dallas, TX",
"ip_type": "Hosting provider",
"mfa": "One-time code sent to the phone on file, entered correctly"
},
{
"ts": "2026-10-04T18:06:51Z",
"type": "external_account_linked",
"device": "Windows PC, first seen 2026-10-04",
"detail": "Account at a cryptocurrency exchange, verified by instant account verification"
},
{
"ts": "2026-10-05T16:40:22Z",
"type": "secure_message_from_member",
"device": "iPhone, known",
"text": "Hi, I'm expecting a big payment this week from a client for my consulting side job, around $38k. How fast will it be available? I need to pay their supplier right away. Can you also raise my P2P limit?"
},
{
"ts": "2026-10-05T19:15:03Z",
"type": "staff_action",
"detail": "Daily P2P limit raised from $1,000 to $2,500 at the member's request. Member told that large ACH credits may be reviewed before funds are available."
}
],
"credit_under_review": {
"posted": "2026-10-07T14:02:00Z",
"rail": "Same-day ACH",
"sec_code": "CCD (corporate credit)",
"amount_usd": 38400,
"originator_company_name": "TARROW CREEK HVAC SVCS",
"company_entry_description": "VENDOR PAY",
"receiver_name_in_entry": "SALTMARSH SUPPLY PARTNERS",
"addenda": "INV 20417 20431",
"sending_bank": "Prairie Gate Commerce Bank",
"funds_status": "Available, no hold placed at posting"
},
"events_after_credit": [
{
"ts": "2026-10-07T14:09:31Z",
"type": "login",
"device": "iPhone, known",
"ip": "198.51.100.23",
"ip_location": "Columbus, OH"
},
{
"ts": "2026-10-07T14:11:40Z",
"type": "p2p_payee_added",
"device": "iPhone, known",
"payee": "Individual, never paid before"
},
{
"ts": "2026-10-07T14:12:05Z",
"type": "p2p_out",
"device": "iPhone, known",
"amount_usd": 2500,
"payee": "Payee added 2026-10-07T14:11:40Z",
"status": "Sent"
},
{
"ts": "2026-10-07T14:47:18Z",
"type": "login",
"device": "Windows PC, first seen 2026-10-04",
"ip": "203.0.113.77",
"ip_location": "Dallas, TX"
},
{
"ts": "2026-10-07T14:49:02Z",
"type": "transfer_to_external_account",
"device": "Windows PC, first seen 2026-10-04",
"amount_usd": 9500,
"destination": "Cryptocurrency exchange account linked 2026-10-04",
"status": "Pending"
},
{
"ts": "2026-10-07T15:03:55Z",
"type": "wire_request",
"device": "Windows PC, first seen 2026-10-04",
"amount_usd": 24000,
"beneficiary": "Business account at another US bank, never paid before",
"status": "Pending review"
}
],
"balances": {
"available_before_credit_usd": 286.14,
"available_now_usd": 26686.14
}
},
"questions": {
"proceeds_of_fraud": {
"type": "noul",
"instructions": "Is the credit under review the proceeds of fraud against the sender or someone else, such as business email compromise, account takeover, payroll diversion or a scam?"
},
"mule_likelihood": {
"type": "score",
"instructions": "How likely is it that the account holder is acting as a money mule, knowingly or unknowingly, by receiving the credit under review and moving it on for someone else?",
"levels": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"action": {
"type": "choice",
"instructions": "What should the receiving institution do with the credit under review?",
"options": {
"release": "Release the funds and allow normal account activity",
"hold_and_contact": "Hold the funds, restrict outbound transfers and contact the sending bank to confirm the payment",
"return": "Return the credit to the sending bank as suspected fraud and restrict outbound transfers"
}
}
}
}Probabilities are shortened to four decimals here; responses carry full precision.
{
"id": "dec_2dc351dde5024a1d8725ff765133c3ae",
"model": "grayson-1",
"answers": {
"proceeds_of_fraud": {
"type": "noul",
"value": true,
"probability": 0.8176
},
"mule_likelihood": {
"type": "score",
"value": 3.396,
"level": "Very likely (over 90%)",
"probabilities": [
0.0385,
0.0634,
0.0436,
0.1724,
0.682
]
},
"action": {
"type": "choice",
"value": "hold_and_contact",
"probabilities": {
"release": 0.0033,
"hold_and_contact": 0.9119,
"return": 0.0848
}
}
},
"usage": {
"input_tokens": 1414
}
}proceeds_of_fraud: above your threshold, delay availability of the funds; Nacha's funds-availability exception requires you to notify the sending bank promptly when you use it.mule_likelihood: route a high sum of "Likely" and "Very likely" to your mule-account team, separately from the decision about this credit.action: whenreturnandhold_and_contactare close, hold and restrict outbound transfers; a hold can be released, but a return can't be taken back.
Call it from your code
Save request.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
The receiving institution sees only an ACH credit with a company name, an entry description and a receiver name, not the compromise that produced it. Once the funds move on, they are rarely recovered. Simple rules separate the cases poorly: name mismatches are common on legitimate credits, and a large-credit threshold flags every insurance settlement and tax refund.
What to send
Send what your operations team would see on the account and the credit, cut at the moment you decide:
- The name on the entry and the account's owners. A company or another person's name on a consumer account suggests the sender was misled.
- What kind of credit it is. A corporate SEC code or vendor-payment description on a personal account that never received one.
- The account's normal. A credit far above the average balance, or to a dormant account, is out of pattern.
- Access and profile changes before the credit. New devices, contact changes and linked accounts show an account being prepared or taken over.
- What happened after it posted. Money leaving within hours is the strongest sign of a mule account.
- What the customer said. A customer forwarding a "client's" payment to "their supplier" is describing a mule arrangement.
Add your own criteria
When to return rather than hold is a business decision the data alone can't settle: some institutions always hold and call the sending bank first, while others return on the spot when the evidence is strong. This one returns, the same day, a large corporate credit to a consumer account with an unexplained name mismatch while money is already moving to new payees.
Your return policy for name mismatches adds this to the context:
{
"institution_policy": "ACH-14, name mismatches on incoming credits. We post ACH credits by account number, but we do not hold a CCD or CTX credit over $10,000 to a consumer account for a call to the sending bank when all three of these are true: (1) the receiver name in the entry matches no owner of the account; (2) we have no business relationship on file between the member and the originator or the named receiver; (3) money has started leaving the account, or a transfer is pending, to a payee or external account added in the last 14 days. In that case, return the full credit the same banking day with return reason R17 and QUESTIONABLE in the addenda, block outbound transfers, and refer the member to BSA. Holding the funds and contacting the sending bank is for mismatches that do not meet all three conditions."
}| Question | Without | With your return policy for name mismatches |
|---|---|---|
proceeds_of_fraud | Yes, P(yes) 82% | Yes, P(yes) 93% |
mule_likelihood | Very likely (over 90%), 68% | Very likely (over 90%), 84% |
action | hold_and_contact, 91% | return, 98% |
All three conditions hold here (the receiver name matches no owner, nothing on file ties the member to the originator or the named receiver, and money is going to a payee and an exchange account added this week), so the action should move from holding the funds to returning the credit.
Where to call it
- When the credit posts, for credits your screening routes for review, before the funds become available.
- Again when money starts to leave an account holding a recent large credit, with the outbound activity added.
- When the answer is uncertain, hold the funds and call the sending bank, which can ask its own customer whether the payment was intended.
Cost and latency
This example is 1,414 input tokens, so a decision costs $0.000050: $0.05 per 1,000 decisions, or $50.00 per million. You pay only for input tokens, at $0.035 per million, and each request is rounded up to the next millionth of a dollar. A larger context costs proportionally more; every response reports its size in usage.input_tokens.
Grayson answered this example in 173 ms, the median of 5 calls through api.finic.ai from US-West. Latency 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.2.2-py3-none-any.whl
grayson eval my-cases.csv --questions https://docs.finic.ai/recipes/incoming-payment-fraud/questions.json --label proceeds_of_fraud=<column> --label mule_likelihood=<column> --label action=<column>Each --label names the column with that question's right answer:
proceeds_of_fraud:trueorfalsemule_likelihood: a level, such as "Very likely (over 90%)"action:release,hold_and_contact,return
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
Should I hold or return a credit I think is fraudulent?
Nacha rules allow either: since October 2024, a receiving bank that reasonably suspects a credit is unauthorized or induced by false pretenses may delay its availability (notifying the sending bank promptly) and may return it with R17 and QUESTIONABLE in the addenda. Many teams hold and contact the sending bank first, because a return can't be undone. Whichever you choose, restrict outbound transfers at once: a return is for the full amount, so you fund whatever has already left.
Can Grayson tell an unwitting mule from a complicit one?
The mule_likelihood question covers both on purpose, because the decision about the credit is the same either way. To separate them, add a question such as "Does the account holder appear to be the victim of a job, romance or investment scam that is using their account?" and include the customer's messages and call notes. Intent often becomes clear only after someone talks to the customer, so ask again with the call notes added.
What if the name on the credit matches my customer?
Then the most common giveaway is missing, and the other signals carry the decision: a new or recently reactivated account, a type of credit the account has never received, new devices or profile changes beforehand, and money leaving soon after. Fraudsters also open accounts, including business accounts, in names that match what the sender expects to see.
Related recipes
Detect money mule accounts
Whether an account is passing other people's money through, whether the holder knows, and what to do
Detect business email compromise in vendor payments
Catch payments to a vendor's new bank account after a fake or compromised change request.
Recipes
Every use case, with its questions and cost per decision.
Fraud typology classification
Grayson labels a fraud claim with a FraudClassifier class, a ScamClassifier type and contributing factors, and decides reimbursement, from notes and payments.
Insider threats
Grayson triages insider risk alerts: whether an employee opened customer accounts without a business reason, why, and whether to close, refer or suspend.