Risk scores and signals

Every email, phone and IP module returns a 0-100 risk score, higher is riskier. Ask for signals and you also get the named reasons behind each score.

Scores

Risk is one shape everywhere: { score, signals? }. Each module that runs carries its own risk. The overall risk.score at the top of the response is the total of every signal that fired - in every module, plus the rules that look across modules - capped at 100. A module’s own score is the total of its own signals, also capped at 100. So the numbers always add up: signals worth 3 and 2 give a score of 5. A module that ran and found nothing adds nothing, and modules you did not run cannot change the score.

A score is null when nothing it depends on was known, for example an IP only the geolocation source could answer. An unknown is never scored as clean, and never as risky. The root risk is null when no email, phone or IP module ran - a footprint alone is not scored.

Signals (opt in)

Add "riskSignals": true to checks. Each module’s risk.signals then lists the rules that fired, and the top-level risk.signals lists all of them plus the cross-module ones. Match on id, which is stable; the label is for people and may be reworded. Signals are included on paid plans.

Request
POST /v2/lookup?wait=true
{
  "email": "someone@example.com",
  "phone": "+14155552671",
  "ip": "185.220.101.1",
  "checks": { "email": true, "phone": true, "ip": true, "riskSignals": true }
}
Response (abridged)
{
  "risk": {
    "score": 58,
    "signals": [
      { "id": "ip.tor", "module": "ip", "label": "Traffic is leaving the Tor network", "points": 30, "severity": "high" },
      { "id": "cross.phone_ip_country", "module": "cross", "label": "Phone country and IP country differ", "points": 10, "severity": "medium" }
    ]
  },
  "email": { "…": "…", "risk": { "score": 5,  "signals": [ … ] } },
  "phone": { "…": "…", "risk": { "score": 48, "signals": [ … ] } },
  "ip":    { "…": "…", "risk": { "score": 90, "signals": [ … ] } }
}

Your rules

On the dashboard’s Risk rules page an account can tune every default rule for its own traffic - switch it off, change its points, or change the values in its condition (e.g. a domain registered in the last 60 days instead of 30). Reset brings back ours. Changes apply to that account only.

It can also build its own rules from the same facts - up to five conditions each, e.g. “IP country is one of RU, KP” or “company domain and domain age under 90 days”. Their signals carry the id custom.<id>. The free plan includes 3 custom rules; paid plans more.

Our rules keep improving, and never undo yours. Only what an account changed is stored, so a new rule or a better default reaches everyone who has not changed that exact setting. A rule we retire is marked deprecated: it keeps working exactly as before until the account switches it off - rule ids are never removed.

Three rules react to a module’s own score: an email, phone or IP address rated 80 or more adds 10 points to the overall score.

What the rules look at

Email: disposable providers, undeliverable mailboxes, domains with no mail server or registered in the last 30 days, unusual extensions, digit-heavy handles, catch-all and webmail domains, company domains without DMARC, breach history, and addresses with no online presence at all. Phone: invalid numbers, disposable numbers, recent SIM swaps, VOIP (and app-minted VOIP in particular), porting, and numbers with no linked accounts. IP: Tor, VPN, proxies, residential proxies, datacenter ranges, automated traffic and compromised hosts.