GuidesStart here

How scoring works

Every call gets one number between 0 and 1, where we would draw the line on it, and a list of reasons. Those three things are the whole interface.

The score

A score is a number from 0 to 1. Zero is a call we have nothing against. One is as bad as it gets. It is a judgement about this call to this number right now, not a permanent property of the caller. The same number can score differently an hour later, and a number that behaves goes back down on its own.

What is fixed, and what is not
The scale is fixed and public: 0.5 is where we start to doubt a call and 0.8 is where we would refuse it, and those two numbers come back with every score. A line you draw on the score today means the same thing next year. What goes into the score, the weights and the windows, is not published and moves as we see more traffic.

The recommended action

action is where we would draw the line on the score, at the thresholds that come back with it. Take it as it is and you are making the decision we would make. Draw your own line on the score, a stricter one on a sales line or a looser one on support, and action becomes a second opinion.

allow"allow"
Connect it. Nothing here worries us.
review"review"
Something is off, but not enough to refuse a caller who might be real. Connect it and watch it; this is the band where a short verification question earns its keep.
reject"reject"
Do not connect it. On Guard, if we are connected to your platform, we end it for you; at the gate, the caller is challenged.
With every scoreJSON
"score": 0.92,
"action": "reject",
"thresholds": { "review": 0.5, "reject": 0.8 }

If you are drawing your own line, the shape that works is one number for refusing and, if you want it, a lower one for a verification step. Anything under the lower one connects as usual.

The reasons

Every score carries a reasons array of short stable strings. They are there so a human reading an alert at 3am knows what happened, and so your logs say something useful. Treat them as labels to display and group by, not as an interface to branch on, because the set grows.

CodeIn a sentence
blocked_manualYou blocked this number yourself, from the dashboard or the API.
blocked_exactWe placed a temporary block on this exact number after earlier behaviour.
blocked_stemA block on a run of consecutive numbers this one belongs to.
blocked_volumeYour protected number is over its hourly volume and is refusing new callers for a while.
exact_rateThis number has called you more than a number should in the time it had.
stem_rateCalls arriving from a run of numbers that differ only in the last digits: one caller with a block of lines.
prefix_clusterAn unusual amount of your traffic suddenly sharing a prefix.
country_burstA burst from a single country, measured against your own normal.
number_volumeThe protected number itself is taking far more calls than it usually does.
geo_clusterMany different numbers with no history that the carrier places in the same small area.
attestation_failedThe carrier's own attestation says the calling number is not verified.
seen_on_networkOther protected numbers, at other companies, are hearing from this same number right now.
stem_on_networkAs above, for the run of numbers this one sits in.
bad_historyThis caller has a record with you specifically.
trustedOn your trusted list. Scores zero and stops there.
daily_capYour plan's daily scoring allowance is spent. The call is allowed and recorded, not scored.
live_*Added during the call by the live monitor: live_recording_likely, live_barge_storm and the rest of the live flags.

The two scores

There are two numbers on every finished call, and they answer different questions.

scorenumber, 0–1
The ring-time score. Decided before your agent speaks, from who is calling and what the numbers around it are doing. It can rise during a call as the live monitor trips flags, never fall. This is what action follows.
spam_scoreinteger, 0–100
The call's own score, settled once it has ended: how it behaved (interruptions, the length of the caller's turns, how long it ran) plus what the number was doing when it rang and its record before. Under your spam_threshold reads as a normal call. It is what the dashboard colours, and what feeds the number's history for next time.

Why other people's traffic matters

The two *_on_network reasons are the ones you cannot build yourself. A number that has just started working through a list hits fifty companies before it hits you twice. On its second call to you it looks like nothing; across everyone we protect it is already unmistakable.

What crosses between accounts is a count and a fading score per calling number. Never who was called, never by whom, never anything about the conversation. When an account leaves, its contribution stays anonymous and its link to it is dropped.

What it looks like

200OKA call we would refuseJSON
{
  "caller": "+15125550142",
  "number": "+14155550100",
  "direction": "inbound",
  "score": 0.92,
  "action": "reject",
  "reasons": ["stem_rate", "seen_on_network"],
  "block": null,
  "level": "standard"
}

A run of consecutive numbers is working your line, and the same caller is on other people's numbers at the same time. See the score endpoint for how to ask this question, and reputation for the longer story behind one number.