Developer API
Free, no auth, CORS-enabled. Just GET the endpoints — JSON in, JSON out.
Endpoints
/api/ip?ip={ip}Full IP check: geo, ASN, IP-layer risk evidence, native label, scenario reference, and AI region snapshots
/api/bgp?asn={asn}&ip={ip}BGP routing: announced prefix, upstream/downstream ASNs (via RIPEstat)
/api/reverse-ip?ip={ip}Reverse IP: domains hosted on the same IP
/api/batch?q={ips|cidr}Fast batch estimate using ip-api + IPOK's offline DB; not the same as the multi-source single-IP score
/api/cidr?q={cidr}Block reputation: scan IPv4 CIDRs against the offline DB (each block ≤/16; total expansion ≤65,536 addresses/request) for VPN/Tor/abuse ratios and a verdict, with no extra upstream requests
/api/badge?ip={ip}Band-colored SVG risk badge for READMEs / forums. To protect upstream capacity, badges skip Scamalytics, so the same target may score slightly differently from a user-initiated /api/ip lookup. A result using stale fallback older than 72 hours (up to 7 days) is labeled stale and colored amber. Quota exhaustion or lookup failure returns a gray n/a SVG with HTTP 200; success is cached 5 minutes and n/a 1 minute
Example
# Full IP check: geo, ASN, IP-layer risk evidence, native label, scenario reference, and AI region snapshots
curl "https://ipok.io/api/ip?ip=1.1.1.1"
# BGP routing: announced prefix, upstream/downstream ASNs (via RIPEstat)
curl "https://ipok.io/api/bgp?asn=AS13335&ip=1.1.1.1"
# Reverse IP: domains hosted on the same IP
curl "https://ipok.io/api/reverse-ip?ip=1.1.1.1"
# Fast batch estimate using ip-api + IPOK's offline DB; not the same as the multi-source single-IP score
curl "https://ipok.io/api/batch?q=1.1.1.1,8.8.8.8"
# Block reputation: scan IPv4 CIDRs against the offline DB (each block ≤/16; total expansion ≤65,536 addresses/request) for VPN/Tor/abuse ratios and a verdict, with no extra upstream requests
curl "https://ipok.io/api/cidr?q=146.70.50.0/24"
# Band-colored SVG risk badge for READMEs / forums. To protect upstream capacity, badges skip Scamalytics, so the same target may score slightly differently from a user-initiated /api/ip lookup. A result using stale fallback older than 72 hours (up to 7 days) is labeled stale and colored amber. Quota exhaustion or lookup failure returns a gray n/a SVG with HTTP 200; success is cached 5 minutes and n/a 1 minute
Key response fields
{
"geo": { "ip", "version", "country", "city", "asn", "asName", "isp", "lat", "lon" },
"ipType": "residential | hosting | mobile | business | unknown",
"usageType": "isp | dual_isp | business | hosting | mobile | education | government | unknown",
"risk": 0,
"riskBreakdown": { // how the score was computed (see /methodology)
"contributors": [{ "source", "risk", "weight" }],
"weightedAvg": 0,
"floors": [{ "key": "tor", "floor": 90 }],
"final": 0
},
"signals": ["proxy", "hosting", ...],
"blocklist": { "listed": ["SpamCop"], "checked": 5, "total": 5 }, // valid DNSBL results / planned lists, IPv4 only
"anonAsn?": { "asn", "name", "type" }, // known VPN/proxy provider ASN
"nativeType": "native | broadcast | unknown",
"sharedUsers": { "range": "1-5", "quality": "good | ok | poor | unknown" },
"scenarios": [{ "key": "tiktok", "stars": 3, "verdict": "try" }],
"services": [{ "key": "chatgpt", "status": "available" }],
"media": [{ "key": "netflix", "status": "unknown" }], // known-region restriction reference, not a live unlock test
"sources": [{ "source": "ip-api", "risk": 10, "flags": {} }],
"intel?": { "asn", "company", "datacenter", "abuse" }, // ipapi.is enrichment
"asnHistory?": [{ "asn", "firstSeen", "lastSeen" }],
"rdap?": { "registry", "country", "registered", "org" } // "?" = optional, omitted when unavailable
}Status / errors
| 200 | OK |
| 400 | Bad request: invalid/private IP, missing ip/asn, etc. |
| 429 | Minute or daily quota exhausted; retry after the supplied interval |
| 503 | Quota service or batch upstream temporarily unavailable |
| 502 | Upstream data source unavailable or timed out |
Rate limits & caching
Limits are keyed by requester IP (IPv6 grouped to /64). Only /api/ip has an additional 30/minute burst gate within each Worker instance; MCP, /api/ip, and /api/badge share daily buckets of 20 self checks per UTC day and 15 target-IP lookups/day. Badge exhaustion returns a gray n/a instead of 429. Batch allows 25 upstream chunks/day (up to 100 targets per chunk); reverse-ip, whois, and BGP each allow 25 requests/UTC day, CIDR allows 10/day, and the DNS-leak proxy allows 40 HTTP requests/day (about 20 complete tests). One CIDR request may expand at most 65,536 addresses. Scamalytics is attempted only for explicit cache misses under three caps: five tries/requester/UTC day, six site-wide tries/UTC hour, and the upstream monthly allowance. Exhausted capacity uses a visibly marked fallback cache when available; otherwise that source is omitted and the full lookup continues. Commercial-source fetches (AbuseIPDB / proxycheck / ipapi.is / Scamalytics) are pooled per client class and UTC hour, with separate pools for self checks and target-IP lookups: requests issued by this site's own pages that pass Cloudflare Turnstile's silent verification are not pooled (a failed or unloaded verification falls back to 120 / 30, never a rejection); the official app gets 120 / 60, browser extensions 120 / 30, honest programmatic clients (curl, scripts, MCP) 100 / 30, cross-site calls from other web apps 60 / 30, direct browser navigations to the endpoint 30 / 10, and requests that claim to be a browser but lack headers every real browser sends 20 / 5. A spent pool never rejects: the commercial sources are served only from cache or clearly marked stale values with no upstream fetch, the free sources still participate, and the response carries upstream:"cached-only" plus x-ipok-upstream and x-ipok-client headers. Requests carrying header combinations no real browser produces (a navigation with XHR-only headers, a page fetch with navigation-only headers, a User-Agent OS that contradicts the client hints) are rejected with 403; an honest HTTP client is all you need. Matching cache hits do not consume auxiliary quotas. A real limit returns 429; a production quota-service failure returns 503. Add your own cache and contact us for higher-volume use.
Attribution Policy
Our API is free and does not require registration. However, if you display, quote, or reference our IP risk intelligence data (such as IP type, threat scores, or VPN flags) in your public products, web pages, or research, you must prominently credit IPOK as the data source and include an active, followable HTML backlink to https://ipok.io.
Please use responsibly; add your own cache for high-volume or commercial use.