Reading a verdict
The number and the word always agree, and the body tells you which of them was decided by a lookup and which by a model. This page is how to read that.
The three words
Nothing connects this address to a sanctioned or illicit source, and the model found nothing in its behaviour worth a person's time. It is the only verdict that means what it sounds like.
A person should look. Either the model put this wallet high enough to be worth an hour, or the trail reached somewhere the API refuses to clear on its own, such as a custodian's wallet holding thousands of customers at once.
Exposure to a sanctioned or illicit source, either directly or through an address that has one. When this comes from a list or a contact rule it is a database match, not a prediction, and ofac_hard_match tells you which.
What sets the score
Exactly one thing sets risk_score, and decided_by.rule names it. The checks run in this order and stop at the first one that fires.
- Lists and contacts. On the OFAC list, on our candidate list, or having sent to or received from any listed address or any known mixer, at any amount. Score 100, verdict FLAGGED,
sourceisrule. No model runs. - The model. Nothing above fired, so the score is the model's own 0 to 100 number and the verdict is a pure function of it. Below the review line it is CLEAR, at or above it REVIEW, at or above the flag line FLAGGED.
- The floors. The model said CLEAR but the address is a contract, or the trail ends in exchange custody, or a check could not run. The score is raised to the review line and the verdict becomes REVIEW.
A wallet that shows most of the named behaviours also gets a floor under its score, so a reader is never shown CLEAR next to a list of ticked behaviours. The floor moves the number the verdict is read from; it does not overrule the verdict separately.
The lines are configuration
The review line is 85 and the flag line is 99.1 by default. Both are deployment settings, so derive the verdict from the verdict field rather than recomputing it from the score at your end.
The two kinds of reason
why looks like one list and is really two. Every entry carries a kind, and the difference between them is the difference between a cause and an observation.
"decided_by": {
"rule": "mixer_contact",
"source": "rule",
"reason": "This wallet received funds from a known mixer."
},
"why": [
{
"kind": "decided",
"reason": "This wallet received funds from a known mixer.",
"pushed": null
},
{
"kind": "model",
"reason": "Funds were passed along in a chain of one-to-one transfers.",
"pushed": "up"
},
{
"kind": "model",
"reason": "A long history with no flagged counterparty anywhere in it.",
"pushed": "down"
}
]kind: "decided" is the first entry, always. It repeats decided_by.reason and it is the only line that explains the score. Its pushed is null, because it did not move the number: it set it.
kind: "model" is everything the model noticed about the wallet, each with pushed saying which way it leaned. In the example above a mixer contact set the verdict, and the two model lines are context: one raising, one lowering. Neither of them caused the FLAGGED.
Do not render them as one list
Flattening the two kinds into a single bulleted list of reasons puts a lowering observation directly under a sanctions match, as though they were weighed against each other. Show the decided line on its own, above the rest.
Addresses that are never cleared
Three cases come back REVIEW no matter what the model thought, and two of them carry a null score.
- Contracts. A contract is not a wallet with a history, so scoring it as one would be a category error.
- Exchange custody. The trail arrived at a wallet a custodian holds for many customers at once. Beyond that point one customer is not separable from the rest, and the boundary is named in the caveats.
- A check that could not run. Missing input is missing information, and the API will not spend it as evidence in either direction.
What is not a verdict
Several responses look like answers and are not. Each one carries a null verdict, or no verdict field at all, and a sentence saying so.
202, the wallet has never been screened and is being fetched now.402, your allowance is spent, so no screening was performed.503, the store is briefly unreachable and the request never ran.- A job in state
failed, which is a failure to gather data.
The one mistake that matters
An address that has not been assessed is not a low-risk address. If your integration defaults to allowing anything that did not come back FLAGGED, an outage becomes an approval. Branch on the presence of a verdict first, and on its value second.
Building on this
- Read
verdict. If it is absent or null, you do not have an answer. - Show
summaryto a person anddecided_by.reasonbeside it. They agree by construction. - Keep
screening_id. It is how a decision made today is explained six months from now. - Treat
caveatsas limits on the answer, never as evidence against the wallet.
The full field list is on The response.