IP Fraud Detection API — VPN, Proxy, Tor & Risk Score
A transparent IP fraud score API for risk and abuse teams: real Tor-exit and anonymous-proxy detection, a documented hosting/datacenter VPN heuristic, threat-intel matches from ten reputation feeds, and an OONI censorship signal — rolled into an explainable 0-100 risk score that names every input that fired, not a black box.
Building a VPN detection API integration, a proxy/Tor detection API check at signup, or an IP risk scoring API for checkout fraud? This service's security group is where those live: privacy.isTor and privacy.isProxy are real curated-list matches, threat.isMalicious is a threat intelligence IP lookup across ten feeds available on every tier including anonymous, and fraud.score/fraud.level roll all of it into one auditable number.
This page is the buying case for evaluating the API as a fraud signal — to check a single address right now, use IP Details instead, which reports the same fields for one IP at a time. For the full integration and code samples see the developer API page, or for the business/procurement view see the business overview page.
The signal inventory — what each field actually detects
Every signal below is checked against the current code and live deployment config. Where a signal is a heuristic rather than a confirmed fact, the limitation column says so plainly.
| Signal (API field) | What it means | Data source | Honest limitation |
|---|---|---|---|
| Tor exit detection — privacy.isTor | True when the address matches a maintained Tor exit-node list. | Curated Tor exit-node list, refreshed on a fixed schedule. | A brand-new exit relay can lag the refresh window, so a false result for a just-joined relay is possible for a while. |
| Anonymous proxy detection — privacy.isProxy | True when the address is flagged as an anonymous-proxy network. | IPFire libloc anonymous-proxy network flag — a real curated dataset, not a guess. | Coverage is limited to what libloc curates; an anonymizing proxy outside that dataset reports false rather than a confirmed negative. |
| VPN/hosting heuristic — privacy.isVpn | True only when the address's network classification comes from the curated hosting/datacenter rule list — a hosting-posture signal, not a list of VPN exit servers. | X4BNet-derived rule classification (network.classification.source is rule, type hosting or datacenter). | Deliberately excludes weaker cloud- and heuristic-sourced hosting matches, so it under-flags VPN providers outside a listed range — treat it as a coarse hosting-posture signal, never a confirmed VPN-exit match. |
| Threat-intel match — threat.isMalicious / threat.sources | True when the address appears on any configured reputation feed; sources[] names which ones matched. | Ten feeds — Feodo Tracker, Spamhaus DROP, ET Compromised, Blocklist.de, CINS Army, DShield, StopForumSpam, ipsum, and two MISP feeds (CIRCL OSINT, Botvrij OSINT); which tiers reach this signal is shown in the table below. | Reputation-list based: an address can rotate off every list, so a false result means no configured feed currently lists it, not a safety guarantee. |
| Aggregated threat level — threat.threatLevel | A 1-4 severity code (1=High, 2=Medium, 3=Low, 4=Undefined), aggregated as the most severe MISP threat_level_id across every matching entry that carries one. | MISP threat_level_id from the CIRCL OSINT and Botvrij OSINT feeds — the only two of the ten that carry a severity level. | Omitted entirely (not present, not zero) for a clean IP or when a match is backed only by the other 8 (non-MISP) feeds; gated the same as isMalicious/sources — no verbose needed, unlike threat.reports[]. |
| Threat evidence — threat.reports[] | The full MISP event backing a match — organization, description, date, and indicators — not just the yes/no verdict. | Persisted MISP events from the CIRCL OSINT and Botvrij OSINT feeds only. | The other 8 feeds contribute to isMalicious/sources but carry no event narrative, and this array is gated to an authenticated request on a verbose-enabled plan — plans without it still get isMalicious/sources, just not the evidence. |
| Censorship signal — censorship.isCensored | True when measurement data shows a blocking rate above the configured threshold for the caller's ASN and country. | OONI (ooni.org) network-measurement dataset. | A network/country-level signal, not a fact about the individual address, and only populated where OONI has aggregated enough measurements for that pair. |
| Fraud risk score — fraud.score / fraud.level / fraud.signals | A 0-100 score and low/medium/high level computed from the signals above plus reverse-DNS quality and a bulk-mail-sender match; signals[] lists exactly which weighted inputs fired. | A deterministic weighted rollup over this service's own signals — configured weights and thresholds, never a call to a paid third-party fraud API. | Only as complete as the signals feeding it: a low score means nothing configured fired, not an external guarantee. Always present as an object once enabled, even for a clean IP (score 0, level low, signals []). |
Which tier reaches which signal
privacy, threat.isMalicious and the fraud score are part of the security group; exactly which tiers reach them, and which tier's verbose entitlement unlocks the full threat.reports[] evidence array, is shown in the table below — fetched live from the same catalog the pricing page uses, so it never drifts out of date.
Loading current tier limits…
| Tier | Price | Security / day | Threat evidence (reports[]) |
|---|---|---|---|
* Per-minute and per-day limits are counted per unique IP address looked up. An overall request-rate ceiling also applies at the gateway, independent of the per-minute/per-day limits above, returning HTTP 429 once exceeded.
Worked example: scoring a signup or checkout
A typical integration calls the security group with the visitor's IP at signup or checkout, then branches on the returned level rather than inventing a custom threshold.
curl "https://ip.xakki.pro/api/v1/ip?include=security&ip=185.220.101.5"
A trimmed real response for a known Tor exit node (abbreviated for readability — the full field reference lives in the API docs).
{
"schemaVersion": 15,
"status": "ok",
"ip": "185.220.101.5",
"flags": { "isTor": true },
"network": {
"classification": { "type": "datacenter", "source": "rule", "confidence": "high" }
},
"privacy": {
"isProxy": true,
"isVpn": true,
"isTor": true,
"isAnonymous": true,
"isRelay": false,
"isResidentialProxy": false
},
"threat": {
"isMalicious": true,
"sources": ["ipsum"]
},
"fraud": {
"score": 100,
"level": "high",
"signals": ["hosting", "vpn", "tor", "malicious", "proxy"]
},
"tier": "anonymous"
}
fraud.level is already bucketed server-side against the configured thresholds, so a caller can branch on it directly instead of picking its own magic number.
import requests
resp = requests.get(
"https://ip.xakki.pro/api/v1/ip",
params={"include": "security", "ip": visitor_ip},
timeout=5,
)
resp.raise_for_status()
data = resp.json()
fraud = data.get("fraud") or {}
threat = data.get("threat") or {}
privacy = data.get("privacy") or {}
if threat.get("isMalicious") or fraud.get("level") == "high":
action = "block"
elif fraud.get("level") == "medium" or privacy.get("isTor") or privacy.get("isProxy"):
action = "step_up_verification"
else:
action = "allow"
Ready to score your traffic?
Frequently asked questions
- Is IP fraud and VPN/Tor detection free to use?
- Yes — baseline classification needs no signup. The security group (privacy, threat, censorship and fraud) is metered per unique IP per day like the geo and network groups; the anonymous tier already includes it, and a free registered account raises the ceiling further.
- What does privacy.isVpn actually detect?
- A hosting/datacenter posture heuristic: true only when the address's network classification comes from the curated X4BNet hosting/datacenter rule list. It is not a list of VPN exit servers, and it deliberately excludes weaker cloud- or heuristic-sourced hosting matches, so treat it as coarse hosting posture rather than a confirmed VPN-exit match.
- Is fraud.score a call to a paid third-party fraud API?
- No. fraud.score/fraud.level/fraud.signals are a deterministic weighted rollup over this service's own signals (hosting posture, VPN/Tor/proxy, threat-intel match, censorship, reverse-DNS quality, bulk-mail match) using configured weights and thresholds — every point is traceable to a named signal, unlike a black-box vendor score.
- Do you detect residential proxies or relays?
- No — privacy.isResidentialProxy and privacy.isRelay always report false; no adopted data source exists for either today, so this service doesn't claim it. What is real: Tor-exit matching (privacy.isTor) and the IPFire libloc anonymous-proxy flag (privacy.isProxy).
- What's the difference between threat.isMalicious and threat.reports?
- isMalicious and sources[] are available on every tier and draw on all ten configured reputation feeds. reports[] is the deeper evidence — the actual MISP event text, date and indicators — available only on an authenticated request on a verbose-enabled plan, and populated with real narrative for only 2 of the 10 feeds (CIRCL OSINT, Botvrij OSINT); the rest still count toward isMalicious/sources without contributing evidence text.