Live: Tor + abuse feeds refreshed every 6 hours

LayerCall

Move from IPQualityScore without rewriting your integration

One base URL. Same field names, same key position.

The reason people stay on a fraud API they have outgrown is almost never the argument. It is that moving means touching parsing code, alert thresholds, dashboards and tests — a week of engineering against a saving that does not cover it. So LayerCall speaks the shape you already parse.

The change

Before

https://ipqualityscore.com/api/json/ip/YOUR_KEY/1.2.3.4

After

https://www.layercall.com/compat/ipqs/ip/YOUR_LAYERCALL_KEY/1.2.3.4

That is the whole migration for the IP endpoint, and /email/ and /phone/ work the same way. If you would rather not put a key in a URL — and you are right not to want that — send it as X-Api-Key instead and leave anything in the key position; the header wins. We never record the path you called, only the value you looked up.

What maps to what

IP — /compat/ipqs/ip/KEY/1.2.3.4

Their fieldWhat we put in it
fraud_scorerisk_score — both 0–100, both riskier as they rise
country_code / citygeo.country / geo.city
ISP / organizationgeo.isp — we hold one name for the network
ASNgeo.asn, as a number (AS15169 → 15169)
proxyproxy OR VPN OR Tor, matching their wider meaning
vpn / torsignals.is_vpn / signals.is_tor
recent_abusesignals.recent_abuse
connection_type"Data Center" when the network is one; null otherwise

Email — /compat/ipqs/email/KEY/you@example.com

Their fieldWhat we put in it
validsyntax and MX both good, and the mailbox not known to be absent
disposablesignals.is_disposable
fraud_scorerisk_score
deliverabilityour 0–100 deliverability score, bucketed high / medium / low
catch_all / dns_validsignals.is_catch_all / signals.mx_found
generic / commonrole address / large consumer provider
leakedseen in a known breach
sanitized_email / suggested_domainnormalized_email / did_you_mean
domain_agedomain age in days, in their object shape

Phone — /compat/ipqs/phone/KEY/+14155552671

Their fieldWhat we put in it
validsignals.syntax_valid
formatted / local_formatinternational / national notation
fraud_scorerisk_score
VOIPsignals.is_voip — their capitalisation, kept
riskyanything our verdict would not wave through
line_type / countrynumber.line_type / number.country
dialing_codederived from the parsed number

Every response also carries a layercall object with the signals that have no counterpart on their side — the verdict, hijacked-netblock detection, our own abuse-report counts, whether the answer was cached. Ignore it and nothing changes; read it when you are ready to use what you moved for.

What we return null for, and why

A compatibility layer that fills every field so the response looks complete is a compatibility layer that lies. Anything we do not actually measure comes back null — not false, which would assert we checked and found nothing. This is the complete list.

ip

active_vpnactive_torbot_statusis_crawlermobilelatitudelongitudezip_coderegiontimezonehostabuse_velocity

Live-probe and per-client fields (is this exit node up right now, is this a bot, where exactly is it) need measurements we do not take on an address alone. Bot scoring lives on /v1/score/device, which takes signals an IP cannot carry.

email

first_namehoneypotspam_trap_scorefrequent_complainersmtp_scoreoverall_score

Their smtp_score and overall_score are scales of their own with no published definition, so there is nothing to convert honestly. The rest are signals we do not collect.

phone

activeactive_statusprepaidnamecarriercityregionzip_codesms_domaindo_not_callleakedspammer

Whether a handset is switched on, who it belongs to and which carrier holds it are HLR and CNAM queries — a different and far more expensive product. We would rather say so than guess.

Two things that will differ

The scores themselves

fraud_score is 0–100 on both sides and means the same direction, so your threshold keeps compiling. It will not keep meaning the same thing — different engines disagree, which is the entire reason anyone compares them. Run a real list through both before you move a threshold you rely on. The bulk checker does that with no account.

HTTP status on failure

A rejected key gets a real 4xx here, not a 200 with success: false. The body still carries success, so code branching on it is unaffected — but a proxy, a retry policy or an uptime check between you and us will now see a refusal as a refusal.

The free tier is 1,000 lookups a month with no card and no daily cap, which is enough to point a copy of your real traffic at both and compare the answers rather than the marketing.

IPQualityScore is a trademark of its owner. LayerCall is not affiliated with or endorsed by them. This page documents a response format we implement so their customers can leave without rewriting; every field above is produced by LayerCall’s own engine.