Detect check fraud in mobile and branch deposits
Grayson decides whether a deposited check is counterfeit, altered, stolen or a duplicate, and whether to release funds, place an exception hold or reject it.
Grayson decides whether a check deposited through a mobile app or at a branch is counterfeit, altered, stolen or a duplicate, and whether to make the funds available on your normal schedule, place an exception hold or reject the deposit. It reads the account's deposit history, your image-analysis, duplicate-detection and check-verification results, and what happened on the account around the deposit, and costs about $0.04 per 1,000 decisions.
- Decides: Release, hold or reject a check deposit that may be counterfeit, altered, stolen or a duplicate.
- Call it: When a mobile or branch check deposit is submitted
- Questions: 1 score, 2 choice
- Cost: $0.000045 per decision, $0.04 per 1,000, for this example's 1,274 input tokens
- Latency: 172 ms for this example, the median of 5 calls through api.finic.ai from US-West
Example
A member whose four-month-old account is paid by payroll ACH deposits a $3,950 business check in the app from a company that has never paid them before, then tries to send $3,600 to a new P2P recipient five minutes later.
| Question | Grayson's answer |
|---|---|
return_likelihood | Likely (60-90%), 30% |
check_problem | counterfeit, 69% |
funds_action | exception_hold, 84% |
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": {
"institution": "Cobalt Ridge Credit Union",
"member": {
"name": "Dana R. Whitlock",
"account": "Checking x3307",
"account_opened": "2026-05-18",
"direct_deposit": "Payroll ACH from Fernbrook Distribution LLC, $1,372 to $1,394 every other Friday since 2026-05-29",
"average_daily_balance_90d_usd": 905.4,
"largest_prior_deposit_usd": 1394.11,
"check_deposit_history": [
{
"date": "2026-07-06",
"channel": "Mobile",
"amount_usd": 150,
"maker": "Personal check from an individual",
"result": "Paid"
},
{
"date": "2026-08-21",
"channel": "Mobile",
"amount_usd": 220,
"maker": "Personal check from the same individual",
"result": "Paid"
}
],
"returned_deposited_items": 0,
"overdrafts_last_90_days": 1,
"known_devices": [
{
"device": "iPhone 13",
"first_seen": "2026-05-18"
}
],
"usual_login_location": "Columbus, OH"
},
"activity": [
{
"ts": "2026-09-18T13:01:00Z",
"type": "ach_credit",
"description": "Fernbrook Distribution payroll",
"amount_usd": 1381.27
},
{
"ts": "2026-09-22T21:40:13Z",
"type": "debit_card",
"description": "Grocery store",
"amount_usd": -86.12
},
{
"ts": "2026-09-27T16:05:51Z",
"type": "debit_card",
"description": "Gas station",
"amount_usd": -41.3
},
{
"ts": "2026-09-30T18:21:44Z",
"type": "login",
"channel": "Mobile app",
"device": "iPhone 16, first seen",
"ip_address": "203.0.113.58",
"ip_location": "Columbus, OH",
"verification": "One-time code sent by SMS to the phone on file, entered correctly"
},
{
"ts": "2026-09-30T18:29:10Z",
"type": "p2p_recipient_added",
"recipient": "T. Hale",
"recipient_account": "Individual, at another institution"
},
{
"ts": "2026-09-30T18:42:10Z",
"type": "mobile_check_deposit",
"deposit_id": "dep_2Q8812",
"amount_usd": 3950,
"note": "Item under review"
},
{
"ts": "2026-09-30T18:47:35Z",
"type": "p2p_send_attempt",
"recipient": "T. Hale",
"amount_usd": 3600,
"result": "Declined: insufficient available funds"
},
{
"ts": "2026-09-30T18:52:02Z",
"type": "secure_message_from_member",
"text": "Hi, I just deposited a check in the app. Can you make it available today? I need to pay for my work equipment tonight."
}
],
"item_under_review": {
"deposit_id": "dep_2Q8812",
"channel": "Mobile app",
"amount_usd": 3950,
"check_type": "Business check",
"maker": "Quillmore Medical Supply Inc.",
"paying_bank": "A commercial bank in Texas",
"check_date": "2026-09-25",
"check_number_printed": "4417",
"check_number_in_micr_line": "4417",
"payee": "Dana R. Whitlock",
"memo": "Equipment reimbursement",
"endorsement": "Signature plus 'For mobile deposit only at Cobalt Ridge CU'",
"earlier_checks_from_this_maker": 0,
"image_analysis": {
"image_quality": "Pass",
"courtesy_and_legal_amounts_agree": true,
"signs_of_alteration": "None detected",
"security_features": "No padlock icon, microprint signature line or void pantograph visible on the front image"
},
"duplicate_detection": {
"this_credit_union": "No match",
"shared_image_network": "No match"
},
"check_verification_service": {
"maker_account_status": "Open",
"check_number_vs_recent_items": "Outside range: recent paid checks from this account are numbered 20114 to 20390",
"positive_pay_data": "Not available for this account"
}
},
"available_balance_before_deposit_usd": 412.55,
"funds_availability_if_accepted": "Per the mobile deposit agreement: $275 on the next business day, the rest on the second business day"
},
"questions": {
"return_likelihood": {
"type": "score",
"instructions": "How likely is it that the check under review will be returned unpaid?",
"levels": [
"Very unlikely (under 10%)",
"Unlikely (10-40%)",
"Uncertain (40-60%)",
"Likely (60-90%)",
"Very likely (over 90%)"
]
},
"check_problem": {
"type": "choice",
"instructions": "What is most likely wrong with the check under review?",
"options": {
"none": "Nothing: it appears to be a legitimate check payable to the account holder",
"counterfeit": "Counterfeit: a fake check, possibly printed with a real account's routing and account numbers",
"altered": "Altered: a genuine check whose payee or amount was changed",
"stolen": "Stolen: a genuine, unaltered check deposited by someone not entitled to it",
"duplicate": "Duplicate: a check that has already been deposited or cashed elsewhere"
}
},
"funds_action": {
"type": "choice",
"instructions": "What should happen to the funds from the check under review?",
"options": {
"normal_availability": "Accept the deposit and make the funds available on the normal schedule",
"exception_hold": "Accept the deposit and place an exception hold until the check clears, with a notice giving the reason",
"reject": "Reject the deposit and don't credit the account"
}
}
}
}Probabilities are shortened to four decimals here; responses carry full precision.
{
"id": "dec_1aac17c125f645709fab3f727d303370",
"model": "grayson-1",
"answers": {
"return_likelihood": {
"type": "score",
"value": 2.066,
"level": "Likely (60-90%)",
"probabilities": [
0.1418,
0.2339,
0.1821,
0.3003,
0.1418
]
},
"check_problem": {
"type": "choice",
"value": "counterfeit",
"probabilities": {
"none": 0.1975,
"counterfeit": 0.6893,
"altered": 0.0441,
"stolen": 0.0566,
"duplicate": 0.0126
}
},
"funds_action": {
"type": "choice",
"value": "exception_hold",
"probabilities": {
"normal_availability": 0.1455,
"exception_hold": 0.8372,
"reject": 0.0174
}
}
},
"usage": {
"input_tokens": 1274
}
}funds_actionroutes the deposit. Anexception_holdon a check covered by Regulation CC means sending a notice that gives the reason.check_problemsets the follow-up: call a likely scam victim the same day, contact the paying bank for altered or stolen checks, find a duplicate's first deposit.return_likelihood: set hold thresholds on the sum of "Likely" and "Very likely", choosing the cut-off from your own return history.
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
Customers expect deposited funds within a day or two, but a bad check can come back days later, after the money has left by P2P, ATM or debit card. Many people who deposit counterfeit checks are scam victims, and holding every unusual check frustrates good customers.
What to send
Send the account's history, the item with your vendors' results on it, and what happened around the deposit:
- Account age and deposit history. A young account whose first large credit is a check fits scam victims and mules alike.
- The maker and the customer's history with it. A first check from a business that has never paid them raises the question why.
- Check number against the maker's range. A number far outside the maker's recent range is a strong counterfeit signal.
- Image analysis. Mismatched amounts, or different ink on the payee or amount line, point to alteration.
- Duplicate detection. Whether the same item was already deposited, at your institution or through a shared image network.
- Activity around the deposit. Money that leaves straight away suggests someone expects the check to bounce, or a scammer is pressing.
Add your own criteria
Grayson follows your mobile deposit procedure when it's in the request, even where it's stricter than a general reviewer would be. This one rejects a mobile deposit instead of holding it when the member has never deposited a check from the maker and the check-verification service reports the number out of range or the maker's account closed, because members treat a held deposit as money they have.
Your mobile deposit procedure adds this to the context:
{
"institution_policy": "Cobalt Ridge Credit Union mobile deposit procedure MD-4. Reject a mobile check deposit, rather than accepting it with a hold, when both of these are true: (1) the member has never deposited a check from this maker before; (2) the check-verification service reports the check number outside the maker's recent range, or the maker's account as closed. Do not credit the account. Call the member the same day, explain that the check appears to be counterfeit, and tell them not to send money to whoever gave them the check. We reject instead of holding because members see a held deposit in their balance, treat it as money they have, and send their own funds on before the check comes back. Branch deposits, and checks from makers the member has deposited before, follow the standard hold rules."
}| Question | Without | With your mobile deposit procedure |
|---|---|---|
return_likelihood | Likely (60-90%), 30% | Very likely (over 90%), 48% |
check_problem | counterfeit, 69% | counterfeit, 94% |
funds_action | exception_hold, 84% | reject, 99% |
Both conditions hold here (no earlier checks from this maker, and a check number far outside its recent range), so the funds decision should move from an exception hold to rejecting the deposit.
Where to call it
- Mobile deposits: after image analysis, duplicate detection and check verification return, and before the app confirms the deposit.
- Branch deposits: when the teller scans the item, so a rejection happens while the check is still at the window.
- When the answer is uncertain, hold rather than release and verify with the paying bank; call again if the customer tries to move the money.
Cost and latency
This example is 1,274 input tokens, so a decision costs $0.000045: $0.04 per 1,000 decisions, or $45.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 172 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/check-deposit-fraud/questions.json --label return_likelihood=<column> --label check_problem=<column> --label funds_action=<column>Each --label names the column with that question's right answer:
return_likelihood: a level, such as "Very likely (over 90%)"check_problem:none,counterfeit,altered,stolen,duplicatefunds_action:normal_availability,exception_hold,reject
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 an exception hold be based on Grayson's answer under Regulation CC?
For checks deposited at a branch or ATM, Regulation CC lets you extend a hold when you have reasonable cause to believe the check is uncollectible, based on facts that would cause a well-grounded belief in the mind of a reasonable person, not on the check or the depositor belonging to a particular class. The hold notice has to give the reason, so cite the facts Grayson weighed, such as a check number outside the maker's range, not a score. Regulators haven't settled whether Regulation CC's availability schedule covers mobile deposits, so many institutions set mobile availability in their mobile deposit agreement; confirm yours with your compliance team.
Can it tell a scam victim from someone depositing a bad check on purpose?
Add a question for it, such as a noul asking whether the account holder appears to be the victim of a fake-check scam rather than a participant. A message about a new job, an online sale or an overpayment and a long, ordinary account history point one way; a new account followed by ATM withdrawals at several locations points the other. The answer changes the conversation with the customer, not the hold.
What if I don't have check-verification or duplicate-detection data?
Send what you have. Without a check-verification service, Grayson can't compare the check number with the maker's range or confirm that the maker's account is open, so its answers will be less certain. Treat an uncertain answer as a reason to hold and verify with the paying bank, not to release.
Related recipes
Detect fraudulent incoming ACH credits and transfers
Release, hold or return an incoming credit that may be proceeds of BEC, account takeover or payroll diversion.
Detect money mule accounts
Whether an account is passing other people's money through, whether the holder knows, and what to do
Recipes
Every use case, with its questions and cost per decision.
Card disputes
Grayson classifies card disputes as friendly fraud, account takeover or stolen card from authentication, logins and past disputes, and recommends a resolution.
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.