Risk Scoring
Every signal behind the score, what it is worth, and why it lands where it does.
The score is a sum. Shield runs a fixed set of checks against a payment, each one that matches adds its own number of points, and the total is capped at 100. There is no model, no training data and no drift: the same payment scores the same today and next year.
Which means a score is explainable. Every payment records the exact list of signals that fired, and this page is what each one of them costs.
The bands, and what they are not
| Score | Band |
|---|---|
| 0 to 20 | Low |
| 21 to 50 | Medium |
| 51 to 80 | High |
| 81 to 100 | Critical |
These are labels for reading a list at a glance. The decision comes from
your thresholds, not from the band, so a payment at 62 is high whether your
block threshold is 70 or 60, and only one of those refuses it.
Where the payer is coming from
| Signal | Fires when | Points |
|---|---|---|
| Proxy or VPN | The IP is a known proxy or VPN exit | 40 |
| IP and timezone disagree | The browser timezone maps to a different country than the IP | 35 |
| IP and phone disagree | The payer's phone country is not the IP country | 30 |
| Datacenter IP | The IP belongs to a hosting provider | 20 |
| Three or more countries | IP, phone, currency, browser language and timezone point at three or more countries | 15 |
| IP and language disagree | The browser language region is not the IP country | 10 |
| Unknown operator | A mobile money prefix that matches no operator for the resolved country | 5 |
These are the signals that need browser data, which is why a payment made through your own server-to-server integration triggers fewer of them than one through a hosted page.
Whether the request came from a browser at all
| Signal | Fires when | Points |
|---|---|---|
| Headless screen | The reported screen resolution starts at 0x0 | 20 |
| Bot user agent | The user agent matches HeadlessChrome, PhantomJS, SlimerJS, Selenium or WebDriver | 5 |
| No device signals | No browser data was sent with the charge | 3 |
Three points, deliberately
A charge with no browser data is also exactly what a legitimate server-to-server integration looks like. It nudges the score and never carries it. Ordinary HTTP clients like curl, Postman, axios or requests are not in the bot list for the same reason.
How fast the same identifier is moving
Every attempt is counted in a ten minute sliding window, per identifier. Only the higher of the two levels fires on each dimension.
| Dimension | Elevated at | Points | Critical at | Points |
|---|---|---|---|---|
| IP address | 5 attempts | 25 | 10 attempts | 50 |
| Card BIN | 3 attempts | 25 | 5 attempts | 45 |
| Device fingerprint | 5 attempts | 20 | 8 attempts | 45 |
| 3 attempts | 20 | 5 attempts | 40 | |
| Phone | 3 attempts | 20 | 5 attempts | 40 |
Two more patterns come out of the same window. Card amount probing is worth 45 and fires when one card BIN is tried at three or more different amounts, which is what a carding script looks like from the outside. Multi merchant is worth 25 and fires when one IP has hit three or more different Wajub merchants.
These counters are not scoped to you
A phone number, an email, an IP or a card BIN carries one counter across the whole platform. A script working through a list of cards against five different merchants exhausts its budget everywhere at once, and the sixth merchant it tries sees a payment that is already critical before anything else is looked at.
What the platform remembers about this payer
Reputation is a score from -100 to 100, held per email, per phone and per device, and shared across every merchant on the platform. It moves on real outcomes.
| Event | Reputation |
|---|---|
| A dispute lost | -30 |
| A dispute won | +10 |
| A payment that went through | +2, capped at +20 |
Keys expire after 90 days without activity, which is the decay: nobody is on a permanent list because of one bad month. Below -5 an identifier is suspect, below -20 it is bad, and the flag is worth points accordingly.
| Signal | Points |
|---|---|
| Device with bad reputation | 35 |
| Phone with bad reputation | 30 |
| Email with bad reputation | 25 |
| Device or phone suspect | 15 |
| Email suspect | 10 |
Alongside them sits SIM swap, worth 40. Shield keeps the devices each phone number has been seen on over the last 30 days, and flags a payment when the number arrives on a device that is not among them. It is the most useful signal there is on mobile money, and it only exists when a fingerprint was sent.
Reputation is the one thing that gets you blocklisted automatically
On Shield Advanced, an identifier whose reputation falls to -50 or below is added to your own blocklist without being asked. That takes more than one lost dispute by design, so it is a track record rather than an incident.
What the identifiers themselves look like
| Signal | Fires when | Points |
|---|---|---|
| Disposable email | The domain is a known throwaway provider | 30 |
| Email seen 10 times in 24 hours | Counted across the platform | 30 |
| Suspicious top level domain | The domain ends in one of the cheap bulk registered TLDs | 15 |
| Email first seen under an hour ago | The platform met this address this hour | 15 |
| Name does not match the email | The customer's name shares nothing with the local part, and the local part looks random | 15 |
| Email seen 5 times in 24 hours | Counted across the platform | 15 |
| Email never seen before | The platform has no record of this address | 10 |
| Phone never seen before | The platform has no record of this number | 10 |
The two first-seen signals are why an ordinary new customer does not start at zero. Both are platform wide, so a customer new to you but not to Wajub triggers neither.
What the card is
| Signal | Fires when | Points |
|---|---|---|
| Three declines in 24 hours | On the same phone, card or BIN | 35 |
| Issuer country is not the IP country | The card was issued elsewhere than the payer is sitting | 35 |
| Issuer country is not the phone country | The card was issued elsewhere than the phone belongs | 20 |
| Prepaid or virtual card | No issuer KYC behind it | 15 |
| Elevated risk brand | Amex, Diners, JCB or Discover | 15 |
| Issuing bank looks prepaid | The issuer name contains prepaid, virtual, gift or reloadable | 15 |
Only the first eight digits of a card number ever reach the risk engine, and nothing longer is stored.
What you and your history say
| Signal | Fires when | Points |
|---|---|---|
| Customer tagged high risk | You marked them | 30 |
| Three or more disputes | Open, under review or lost, on this customer | 25 |
| Amount is 10 times your average | Over your last 30 days, from 5 payments up | 35 |
| Amount is 5 times your average | Same basis | 20 |
| Customer tagged medium risk | You marked them | 15 |
| One or two disputes | On this customer | 10 |
The tagging is the one place your own system feeds the score directly. Set risk_flag to high
or medium in the payment's metadata, and Shield reads it on that payment. The same key on the
customer's own metadata applies to every payment they make, and there only high is honoured.
The two scores that are not computed
Two things bypass the arithmetic entirely and force the score to 100, which refuses the payment on any threshold that can be set.
A blocklist match, on your own list, while the list is switched on.
A sanctions match, against the platform watchlist, on every plan and whether or not you have configured Shield. Sanctions screening is not a feature you buy.
What the Rules page shows you
The Shield, Rules page lists the signals with a name, a description and a severity label. That list is a description of what protects you, not a set of switches: you cannot turn a signal off, change what it is worth, or add one. Weights are platform wide and tuned by Wajub.
The severity words on that page, and in the flag detail on a payment, are labels for reading. The score is built from the points on this page and nothing else.