A fraud score of 87 tells you almost nothing. Is it 87 because the device has been seen behind forty IP addresses tonight, or because the user is traveling and their new phone looks unfamiliar? The number is identical; the correct action is opposite. A risk model that emits only a score forces every human downstream, the analyst reviewing a queue, the support agent handling a dispute, the compliance officer facing an audit, to guess at the reasoning. Reason codes remove the guessing.
A reason code is a compact, stable label that names the specific signal behind a decision. Attached to the suspect score, it turns an opaque verdict into an explanation you can verify, dispute, and improve. This is not a nicety; in regulated contexts it is increasingly a requirement, and in every context it is what makes a fraud program tunable rather than superstitious.
Why a bare score fails everyone
The score-only model quietly imposes costs on every stakeholder.
- Analysts cannot triage efficiently because two identical scores can mean unrelated things, so they re-investigate from scratch each time.
- Users who are wrongly blocked get “your transaction was declined for security reasons” and no path to resolution, which drives churn and support load.
- Compliance teams cannot answer a regulator’s “why was this customer declined” when the only answer is a number from a model no one can narrate.
- Engineers cannot improve the model because they cannot see which signals over-fire without a controlled experiment.
The common thread is that a score compresses away exactly the information people need to act. Reason codes preserve it. Our work on reducing false positives depends on this: you cannot fix what you cannot see.
What a good reason code looks like
Not every explanation is a good reason code. The useful ones share a few properties.
| Property | Why it matters |
|---|---|
| Specific | Names one signal, not a vague category |
| Stable | The same code means the same thing over time, so you can trend it |
| Machine-readable | A short slug your rules and dashboards can key on |
| Human-readable | A phrase an analyst or agent understands without a decoder ring |
| Actionable | Implies what to check or what step-up to apply |
A well-formed decision therefore carries both a score and an ordered list of the codes that drove it:
{
"suspectScore": 0.87,
"decision": "challenge",
"reasonCodes": [
{ "code": "DEVICE_MANY_IPS", "detail": "device seen behind 40 IPs in 1h", "weight": 0.34 },
{ "code": "JA4_TOOL_MISMATCH", "detail": "TLS fingerprint matches automation library", "weight": 0.28 },
{ "code": "DATACENTER_IP", "detail": "exit ASN is hosting", "weight": 0.15 }
]
}
The ordering by contribution is what makes it actionable: the analyst reads the top code first and knows immediately this is proxy-rotated automation, not a traveling customer.
Mapping signals to codes
Reason codes are the human-facing projection of your signal stack. Each detection capability should map to one or more stable codes, so the vocabulary grows with your coverage rather than being invented ad hoc.
- Device signals —
NEW_DEVICE,LOW_CONFIDENCE_MATCH,DEVICE_MANY_ACCOUNTS, drawn from device fingerprinting and its confidence score. - Network signals —
DATACENTER_IP,RESIDENTIAL_PROXY,TOR_EXIT,IMPOSSIBLE_TRAVEL, from proxy detection and impossible-travel detection. - Bot signals —
HEADLESS_BROWSER,AUTOMATION_FRAMEWORK,JA4_TOOL_MISMATCH, from bot detection and automation-framework detection. - Behavioral signals —
NO_INPUT_DYNAMICS,SCRIPTED_CADENCE, from behavioral biometrics.
The discipline is a controlled vocabulary. If three different code paths can emit three different strings for “this is a headless browser,” your dashboards fracture and trending breaks. Define the code set once, document it, and make every signal map into it.
Reason codes in the decision loop
Codes are not just output; they close the loop back into tuning and operations.
- Triage — analysts sort queues by top reason code, batching similar cases and resolving them faster.
- User messaging — some codes justify a specific, honest message (“we do not recognize this device”) and a self-service step-up, while others should stay internal.
- Threshold tuning — track how often each code appears on confirmed fraud versus confirmed-legitimate cases. A code that fires constantly on good users is over-weighted, and now you can see it and dial it down.
- Audit trail — every decision stores its codes, so a later “why did we decline this” has a precise, timestamped answer.
This feeds directly into your bot detection metrics. Instead of a single precision number, you get per-code precision, which tells you exactly which signal is manufacturing false positives and by how much.
Explainability and compliance
Regulations around automated decisioning increasingly expect that a consequential decision can be explained to the person it affects. A model that emits only a score struggles here; reason codes provide the substantive basis a decision needs. This connects to privacy-preserving fraud detection and the broader legal picture: you can justify a decision without exposing your entire model or hoarding excess personal data, because the codes reference behavior and signals rather than raw sensitive attributes.
- Keep codes descriptive of signals, not of protected characteristics.
- Store the code set and weights so a decision is reproducible after the fact.
- Give users a path to dispute that references the code, turning a dead-end decline into a resolvable step-up.
Frequently asked questions
What is a reason code in fraud detection?
A reason code is a short, machine- and human-readable label attached to a risk decision that names the specific signal that drove it, such as device seen behind many IPs or impossible travel from last login.
Why isn’t a numeric risk score enough on its own?
A bare score tells you how risky but not why, so analysts cannot verify it, users cannot dispute it, and regulators cannot audit it; reason codes supply the missing justification.
Do reason codes help reduce false positives?
Yes. When each decision names its drivers, you can see which signals over-fire on legitimate users and tune their weights precisely instead of guessing at an opaque model.
Reason codes are what turn a fraud score from a verdict into an argument. They let analysts triage, users dispute, compliance audit, and engineers tune, all from the same stable vocabulary attached to every decision. If your risk system emits a number and nothing else, adding explainable reason codes is one of the highest-leverage changes you can make. See the suspect score explainer, the glossary, and the docs to put them to work.
Run it yourself
Prynt is open-source, self-hostable device intelligence — visitor IDs, bot & fraud Smart Signals, and behavioral biometrics you own end to end.