WorldIP API — Developer Documentation
A fast, JSON REST API over the same global IP intelligence that powers worldip.io — IP profiles, ASN & organization ownership, reverse/forward DNS, VPN/proxy classification, trust scoring and live BGP routing events. Built on a worldwide adaptive-scanning fleet processing over a billion record updates a day, with sub-second responses for cached profiles.
MCP server (for AI agents)
WorldIP speaks the Model Context Protocol, so an MCP-aware client can call it as a tool instead of scraping pages. No API key is required — the server exposes the same free keyless profile as the public endpoints.
| Endpoint | https://worldip.io/mcp |
|---|---|
| Transport | HTTP, JSON-RPC 2.0 over POST. A GET returns 405 by design — it is an API endpoint, not a page. |
| Protocol | 2025-06-18 |
| Auth | None. Rate-limited per source IP. |
| Server card | /.well-known/mcp/server-card.json |
Add it to Claude Code
claude mcp add --transport http worldip https://worldip.io/mcpOr by hand in .mcp.json
The type field selects the transport — the config will not work without it.
{ "mcpServers": { "worldip": { "type": "http", "url": "https://worldip.io/mcp" } } }Tools
lookup_ip | Look up a public IPv4 or IPv6 address: owner/organisation, ASN, country, region, city, CIDR, reverse DNS (PTR) and forward-confirmed DNS, plus a weekly count of the domains hosted on an IPv4 address (domains_hosted, from issued.live). Takes ip. |
|---|---|
whats_my_ip | Return the caller’s own public IP and its profile. Takes no arguments. |
Both tools are read-only, idempotent and open-world (they consult live data), and are annotated as such in tools/list.
The tools and the free keyless endpoint (https://worldip.io/{ip}) carry domains_hosted:
how many registrable domains have a name resolving to the address, counted once a week from issued.live's DNS
snapshot — a number, never the names. count is 0 when none were seen and
null when the count is unavailable; the whole object is null for reserved addresses
and, for now, for IPv6. The keyed lookup below is unchanged.
"domains_hosted": {"count":42650,"as_of":"2026-10-11","source":"issued.live","attribution":"Domain data provided by issued.live — for full details visit https://issued.live/pricing","details_url":"https://issued.live/pricing"}Getting started
Every endpoint lives under a single HTTPS base URL and returns application/json.
A successful response is 200 OK with the record at the top level; errors use
standard HTTP status codes with a JSON error body (see Errors).
| Base URL | https://worldip.io |
|---|---|
| Version | v1 (path-versioned) |
| Format | JSON, UTF-8. Slashes are unescaped. |
| Methods | GET (all data endpoints). OPTIONS is accepted for CORS preflight. |
| Auth | Authorization: Bearer YOUR_KEY, over HTTPS only. Never put a key in a URL (?key=). |
Quickstart — one full IP profile
curl -s https://worldip.io/api/v1/ext/lookup/8.8.8.8 \
-H "Authorization: Bearer YOUR_KEY"
https://worldip.io/{ip},
1,000 lookups a day) and the public Pulse feeds
(below) work today.
Beta keys for issued.live Plus and Pro customers
While the WorldIP API is in beta, our team issues API keys free of charge to customers with an active issued.live Plus or Pro subscription. issued.live and WorldIP are separate services run by the same company, Tuxxin LLC: your issued.live plan and billing do not change, and WorldIP charges nothing for a beta key.
| issued.live plan | WorldIP key | Enriched lookups / mo | Per minute | Concurrent | Data |
|---|---|---|---|---|---|
| Plus | Pro | 200,000 | 600 | 10 | The IP profile lookup with VPN / proxy / Tor / datacenter classification, residential & mobile proxy detection, access type, trust score, BGP prefix and origin ASN, /24 neighbours, region and city. |
| Pro | Business | 1,000,000 | 1,200 | 20 | Everything in Pro, plus MOAS and routing anomalies on the lookup, Web3 node roles and the Pulse API. |
Basic lookups on https://worldip.io/{ip} with
your key have no daily cap. Responses carry X-RateLimit-* (per minute) and
X-Concurrency-Limit (requests in flight); enriched lookups also carry X-Quota-*
(monthly enriched lookups). Limits may change during the beta.
How to get your key
- Subscribe to issued.live Plus or Pro. We issue keys by hand and email yours to the address on your issued.live account within one business day.
- No key after one business day? Contact us from that address.
- We store only a hash of your key and cannot show it again, so keep it safe. If you lose it or it leaks, contact us and we will replace it.
Using your key
- Send it only in the
Authorization: Bearer YOUR_KEYheader, and only tohttps://URLs. - Never put it in a URL (
?key=): URLs are written to server, proxy and browser logs. Never ship it in browser or app code that others can read; call the API from your server. - Keep the
attributiontext (andgrip_attributionwhere present) with any API data you display or pass on: some fields come from licensed datasets (see Data sources).
Beta conditions
- Free during the beta, one key per issued.live subscription, for you or your organisation only. Do not share, publish, sell or sublicense it.
- Limits may change during the beta, and so may fields and endpoints. We announce breaking changes on this page and email key holders.
- No SLA. Beta keys come with no uptime commitment.
- Revocation. We may suspend or revoke a key that is abused or used against our Terms, and we revoke it when the issued.live subscription it came with ends.
- End of the beta: 30 days after WorldIP’s paid plans launch. We will email you before then. Nothing is charged automatically.
- Support is best effort, through our contact form.
The full terms are in our Terms of Use (API keys and the beta).
Authentication
Present your key on every keyed request as a Bearer token, over HTTPS only. Do not use the
?key= query parameter: it is accepted only for older integrations, and a key in a URL is
written to server logs and can leak through referrers and browser history.
Authorization: Bearer YOUR_KEY
Scopes
Each key carries one or more scopes. A request is rejected with 403 forbidden_scope
if its key lacks the scope the endpoint requires.
| Scope | Grants |
|---|---|
ext:read | The IP profile lookup (/api/v1/ext/lookup) and keyed basic lookups on https://worldip.io/{ip}. |
pulse:read | The keyed Pulse event stream + summary (Business keys). |
* | All scopes (issued only to trusted / enterprise integrations). |
Key locking (optional)
A key can be pinned so a leaked value is useless elsewhere:
- Origin lock — restricts browser calls to one site
(enforced whenever the request carries an
Origin/Referer). Mismatch →403 origin_not_allowed. - IP allow-list — restricts calls to specific caller IPs,
the strongest server-to-server lock. Off-list →
403 ip_not_allowed.
IP profile lookup
One consolidated intelligence profile for an IPv4 address: PTR, ASN, organization, country,
CIDR, trust score, VPN/proxy/Tor/datacenter classification (including a residential &
mobile proxy verdict), BGP route + recent routing anomalies, the hosted-domain count, and Web3 roles. The same route takes an IPv6 address; see
IPv6 lookups for what an IPv6 profile contains.
The assembly is cached per IP for five minutes at the origin, so repeat lookups return in
milliseconds (X-Ext-Cache: HIT / MISS). Responses are never cached by
shared caches (Cache-Control: private, no-store), so every call is counted.
| Path parameter | Description |
|---|---|
ipv4 | Dotted-quad IPv4 address, e.g. 8.8.8.8. Invalid input → 400 bad_ip. |
ipv6 | Any valid IPv6 notation, e.g. 2001:4860:4860::8888 (echoed back in canonical compressed form). Invalid input → 400 bad_ip. |
curl -s https://worldip.io/api/v1/ext/lookup/8.8.8.8 \
-H "Authorization: Bearer YOUR_KEY"
{
"ip": "8.8.8.8",
"reserved": false,
"reserved_note": null,
"ptr": "dns.google",
"asn": { "number": 15169, "name": "Google LLC" },
"org": { "name": "Google LLC", "slug": "google-llc", "category": "hosting" },
"country": { "code": "US", "name": "United States" },
"cidr": "8.8.8.0/24",
"trust": { "score": 92, "band": "Trusted", "color": "#3fb950" },
"web3": [],
"bgp": {
"prefix": "8.8.8.0/24",
"origin_asn": 15169,
"moas": false,
"anomalies": []
},
"forward_dns": null,
"flags": [
{ "key": "hosting", "label": "Hosting/DC", "level": "warn", "emoji": "🖥️",
"title": "Datacenter / hosting network - server addresses, not home connections." }
],
"classification": {
"is_vpn": false,
"is_proxy": false,
"is_relay": false,
"relay_source": null,
"is_anonymous": false,
"access_type": "hosting",
"proxy_density_30d": null,
"vpn_density_30d": null,
"is_tor": false,
"is_datacenter": true,
"is_vpn_likely": false,
"verdict": "hosting",
"confidence": "high",
"score": 0,
"source": "worldip-classification"
},
"grip": null,
"grip_attribution": null,
"attribution": "Includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com, used under the MaxMind GeoLite End User License Agreement; GeoLite2 incorporates GeoNames data (https://www.geonames.org) under CC BY 4.0. Includes the IPinfo Lite dataset (https://ipinfo.io) under CC BY-SA 4.0. License details: https://worldip.io/data-sources",
"links": {
"ip": "https://worldip.io/8.8.8.8",
"asn": "https://worldip.io/asn/AS15169",
"org": "https://worldip.io/org/google-llc"
},
"generated_at": "2026-07-17T00:45:12+00:00"
}
Response fields
| Field | Type | Notes | Tier |
|---|---|---|---|
ip | string | Canonical IPv4 echoed back. | Free |
ptr | string | null | Reverse-DNS hostname. | Free |
asn | object | null | number, name. | Free |
org | object | null | name, slug, category. | Free |
country | object | null | ISO-2 code + name. | Free |
cidr | string | null | Allocated block this IP sits in. | Free |
links | object | Canonical worldip.io URLs for the IP/ASN/org. | Free |
forward_dns | object | null | How many domains are hosted on the IP: hosted_domain_count. On plan keys (Basic and up, beta keys included) this object carries the count only: hosted_domains is always an empty list, hostname and registerable_domain are always null, and hosted_domains_truncated is true whenever the count is above 0. Keys without a plan (such as keys issued before the beta) keep the original object, which also lists a sample of up to 25 names (usually about 10) and fills hostname and registerable_domain. For now the count comes from GRIP, covers IPv4 only and is present only while WorldIP holds a GRIP result for the address from the last few hours; otherwise forward_dns is null. | Basic |
classification | object | VPN / proxy / Tor / datacenter, access_type, residential/mobile-proxy verdict, confidence, score, and is_relay + relay_source (Apple iCloud Private Relay egress). | Pro |
trust | object | null | score 0-100, band, color. | Pro |
flags | array | Human-readable risk chips (Tor exit, Proxy/VPN, Hosting/DC, Malware). | Pro |
bgp | object | null | prefix and origin_asn (Basic and up); moas and the last 7 days’ routing anomalies[] ({type, severity, count}; Business and up). | Basic Business |
web3 | array | Blockchain node roles hosted on the IP (chain + role). | Business |
generated_at | string | ISO-8601 UTC timestamp of assembly. | Free |
attribution | string | Data-licence attribution for the geolocation, ASN and organization fields (MaxMind GeoLite2 with GeoNames, IPinfo Lite). Present on every plan; the keyless endpoint carries it as _meta.attribution. | Free |
version | integer | 6. IPv6 profiles only; an IPv4 profile has no version key. | Free |
address_type, prefixes, embedded_ipv4 | string, object, string | null | IPv6 only: address class, the containing /32 /48 /56 /64, and the IPv4 inside a NAT64 or 6to4 address. | Free |
rdns | object | IPv6 only: scan status, kind of PTR (isp_generated, wildcard or specific), checked_at, forward_check, note. | Free |
unavailable | object | IPv6 only: every field that is null because WorldIP has no IPv6 source for it, with the reason. | Free |
classification.verdict becomes
residential_proxy with is_proxy: true. Observations expire: an address
that is no longer seen as a proxy exit drops out of the verdict. Unlocked on the Pro tier.
classification.is_relay is true
when the address is an Apple iCloud Private Relay egress. We match it against our own copy of
Apple's published egress list, refreshed daily, and relay_source is then
"icloud_private_relay". When only GRIP flags the relay it is "grip",
and otherwise null. A relay egress carries traffic for many ordinary Apple users whose own
addresses are hidden, so it does not change verdict, is_vpn,
is_proxy or the trust score. IPv6 lookups use the same list; GRIP has no IPv6
data, so for IPv6 relay_source is "icloud_private_relay" or null.
IPv6 lookups
Both IP endpoints take IPv6 addresses: the free keyless https://worldip.io/{ipv6} and the keyed
/api/v1/ext/lookup/{ipv6}. An IPv6 profile has the same keys as an IPv4 one, so one parser
handles both, plus "version": 6, the containing prefixes and an rdns block.
Authentication, scopes, per-key rate and concurrency limits, the monthly allowance, plan data tiers,
CORS and the 5-minute origin cache work exactly as for IPv4.
| IPv6 field | Source | Endpoint |
|---|---|---|
country, region, city | The same geolocation release as our IPv4 data, rebuilt daily. City-level IPv6 geolocation is approximate and often absent. | Keyless + keyed |
asn, org.name, cidr | The same ASN and organization data as IPv4. cidr is the most specific network we hold for the address. | Keyless + keyed |
ptr, rdns (and the keyless forward_dns forward check) | WorldIP's own IPv6 reverse-DNS scans. | Keyless + keyed |
org.slug, org.category | The organization's slug and category (isp, hosting, cdn, …), as for IPv4. | Keyed (every plan) |
classification.is_datacenter, access_type, flags | Hosting/datacenter classification by the network's organization, as for IPv4. | Keyed (Pro+) |
classification.blocklists, is_bogon | IPv6 blocklists (Spamhaus DROPv6) and Team Cymru IPv6 fullbogons. | Keyed (Pro+) |
classification.is_relay | Apple iCloud Private Relay egress list, refreshed daily. | Keyed (Pro+) |
null, never false, and the unavailable object names each one
with the reason. is_vpn, is_proxy and is_tor are true only when
an IPv6 blocklist lists the address; otherwise they are null.
rdns.kind is isp_generated
when the name encodes the address (for example p200300c8....dip0.t-ipconnect.de, in hex, hextets,
nibbles or base 36) or comes from a network that gives every address its own generated name, and
wildcard for a name shared by many addresses. Such a name shows which network the address is in.
It is not evidence that a host is live there.
specific means we found no template or wildcard, not that the name was assigned by hand.
When our latest scan could not resolve the address, rdns.status is lookup_failed and
ptr is the last name we saw.
rdns.forward_check is confirmed, mismatch or not_checked;
forward_dns.confirmed is true only when it is confirmed.
curl -s https://worldip.io/2003:c8:734:9700::1
{
"ip": "2003:c8:734:9700::1",
"version": 6,
"ptr": "p200300c8073497000000000000000001.dip0.t-ipconnect.de",
"forward_dns": { "hostname": "p200300c8073497000000000000000001.dip0.t-ipconnect.de", "confirmed": true },
"asn": { "number": 3320, "name": "Deutsche Telekom AG" },
"org": { "name": "Deutsche Telekom AG" },
"country": { "code": "DE", "name": "Germany" },
"region": "Baden-Wurttemberg",
"city": "Leutkirch",
"cidr": "2003:c8:400::/38",
"address_type": "Global Unicast",
"prefixes": { "/32": "2003:c8::/32", "/48": "2003:c8:734::/48", "/56": "2003:c8:734:9700::/56", "/64": "2003:c8:734:9700::/64" },
"rdns": {
"status": "found",
"kind": "isp_generated",
"checked_at": "2026-09-30T10:34:08Z",
"forward_check": "confirmed",
"note": "ISP-generated name: the network names every address from a template, usually by encoding the address itself. It shows which network the address belongs to, not that a host is live there."
},
"_meta": { "keyless": true, "docs": "https://worldip.io/developers", "note": "...",
"attribution": "Includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com, used under the MaxMind GeoLite End User License Agreement; GeoLite2 incorporates GeoNames data (https://www.geonames.org) under CC BY 4.0. Includes the IPinfo Lite dataset (https://ipinfo.io) under CC BY-SA 4.0. License details: https://worldip.io/data-sources",
"generated_at": "...", "rate": { "limit": 1000, "remaining": 999, "reset": "...", "window_seconds": 86400 } }
}
curl -s https://worldip.io/api/v1/ext/lookup/2606:54c0:5898::1 -H "Authorization: Bearer YOUR_KEY"
"org": { "name": "Cloudflare, Inc.", "slug": "cloudflare-inc", "category": "cdn" },
"classification": {
"is_vpn": null, "is_proxy": null, "is_relay": true, "relay_source": "icloud_private_relay",
"is_anonymous": null, "access_type": "hosting", "is_tor": null, "is_datacenter": true,
"verdict": null, "confidence": null, "score": null, "is_bogon": false, "blocklists": [], ...
},
"trust": null, "bgp": null, "forward_dns": null,
"unavailable": { "trust": "Trust score is IPv4-only: ...", ... }
Reserved, private and link-local addresses return
reserved: true with no network data. An IPv4-mapped address (::ffff:8.8.8.8) is the
IPv4 address it carries, and every endpoint answers it as that address: the keyless endpoint and the MCP
tools return the IPv4 profile, and /api/v1/ext/lookup/::ffff:8.8.8.8 is the IPv4 lookup, counted
and cached once, as 8.8.8.8. NAT64 (64:ff9b::/96) and 6to4 (2002::/16)
addresses are IPv6 addresses; their profile adds embedded_ipv4 as a hint.
Pulse events
A geo-tagged stream of live "internet events" — BGP routing anomalies (MOAS, route leaks,
withdrawals, bogons, newly announced prefixes) and RIR allocation changes — each tagged with a country
and country-centroid lat/lon so it can be plotted directly on a map. Designed to be polled:
pass the returned next_since back as ?since= on the next call.
Business keys; the response carries the data-licence attribution for the location fields.
| Query param | Default | Description |
|---|---|---|
since | now − 300s | Unix seconds or ISO-8601; lower time bound. |
until | now | Upper time bound. |
limit | 500 | Max events, 1–2000. |
min_severity | 0 | Drop BGP events below this severity. |
country | all | ISO-2 country filter, e.g. US. |
types | all | CSV of moas,first_seen,withdrawal,aspath,bogon. |
category | all | all · bgp · rir. |
moas_sample | 50 | Return 1 of every N MOAS events (MOAS is a legitimate-anycast firehose). 1 = full stream. |
curl -s "https://worldip.io/api/v1/pulse/events?types=aspath,bogon&min_severity=5&limit=100" \
-H "Authorization: Bearer YOUR_KEY"
{
"events": [
{
"id": "bgp:14238894120583017472",
"category": "bgp",
"type": "aspath",
"label": "AS-path anomaly (possible leak/hijack)",
"severity": 7,
"detected_at": "2026-07-17T00:44:57+00:00",
"ts": 1768610697,
"prefix": "103.163.158.0/24",
"asn": 141804,
"counter_asn": 140171,
"country": "IN",
"lat": 22.35,
"lon": 78.67,
"detail": { "collector": "rrc05", "as_path": "13237 3320 6453 4755 141804" }
}
],
"count": 1,
"next_since": 1768610697,
"server_time": 1768610760,
"attribution": "Includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com, used under the MaxMind GeoLite End User License Agreement; GeoLite2 incorporates GeoNames data (https://www.geonames.org) under CC BY 4.0. Includes the IPinfo Lite dataset (https://ipinfo.io) under CC BY-SA 4.0. License details: https://worldip.io/data-sources"}
Pulse summary
Current event-type counts for the last hour and last 24 hours — a cheap poll for dashboards and alerting that don't need the full event bodies.
curl -s https://worldip.io/api/v1/pulse/summary \
-H "Authorization: Bearer YOUR_KEY"
{
"bgp_anomalies": [
{ "type": "moas", "category": "bgp", "label": "Multiple-origin route (MOAS)", "last_1h": 7111, "last_24h": 11250 },
{ "type": "aspath", "category": "bgp", "label": "AS-path anomaly (possible leak/hijack)", "last_1h": 9, "last_24h": 120 }
],
"rir_changes": [
{ "type": "allocation", "category": "rir", "label": "RIR allocation", "last_1h": 6, "last_24h": 214 }
],
"server_time": 1768610760,
"attribution": "Includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com, used under the MaxMind GeoLite End User License Agreement; GeoLite2 incorporates GeoNames data (https://www.geonames.org) under CC BY 4.0. Includes the IPinfo Lite dataset (https://ipinfo.io) under CC BY-SA 4.0. License details: https://worldip.io/data-sources"}
Public feeds (no key)
The same Pulse data also powers the auto-refresh on our Pulse pages, exposed as lightweight no-key poll endpoints. They share the site-wide per-IP request floor (see Rate limits); for higher volume or geo-tagged output, use the keyed Pulse events endpoint.
The most recent BGP routing anomalies (last hour, across RIS collectors).
{
"anomalies": [
{
"prefix": "200.7.251.0/24",
"unexpected_asn": 273140,
"expected_asn": 19114,
"pings": 314,
"last_seen": "2026-07-17 00:44:57",
"collector": "rrc25",
"as_path": "198150 174 12956 19114 273140"
}
]
}
Recent RIR ownership changes — allocations, transfers, and country/RIR re-assignments.
Accepts ?since_id= to fetch only newer rows.
{
"events": [
{
"id": 293167,
"changed_at": "2026-07-11 12:03:24",
"ip_start": 3627346432,
"ip_end": 3627346943,
"ip_start_str": "216.52.234.0",
"change_type": "allocation",
"old_value": null,
"new_value": "US",
"rir": "arin",
"cidr_guess": "216.52.234.0/23",
"org_name": "Unitas Global",
"org_slug": "unitas-global",
"asn": 10912,
"country_code": "US"
}
]
}
Anomalies of a single type with 24h totals. type ∈
moas, first_seen, withdrawal, bogon,
aspath.
{
"type": "aspath",
"totals": { "anomalies_24h": 120 },
"anomalies": [ /* ... */ ]
}
Rate limits
Limits are enforced with a sliding 60-second window: a key may make up to its per-minute
limit in any 60 seconds (e.g. a 1,200/min key can send 300 requests in 10 seconds;
the 1,201st request inside one 60-second window is rejected). Exceeding a limit returns
429 with a Retry-After header and a JSON body.
| Endpoint | Limit |
|---|---|
/api/v1/ext/lookup |
Per-key sliding window (your key's rate). Profiles are additionally cached 5 min per IP at the origin (IPv4 and IPv6 alike). |
/api/v1/pulse/events, /api/v1/pulse/summary |
Per-key sliding window (your key's rate). |
/api/pulse/* (no key) |
120/min per source IP. |
A high per-source-IP flood guard (3,000/min) also applies before authentication; it sits above every key's own limit, so your key's rate is the limit you will actually meet.
Concurrency
Each paid plan also limits concurrent (simultaneous, in-flight) requests per key:
Basic 5, Pro 10, Business
20, Scale 30, Enterprise
100+ (custom). A request beyond the limit returns
429 concurrency_exceeded with Retry-After: 1 — retry as soon as an earlier
request completes. Keyed responses carry X-Concurrency-Limit. Keyless and Free have no
concurrency limit: they are capped at 60 requests/min. Limits may change during the beta.
Rate-limit headers
Every keyed response — successes and 429s — tells you where you stand, so you
can pace yourself and confirm a limit change from a single response:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Your key's limit, requests per window. |
X-RateLimit-Remaining | Requests left in the current 60-second window. |
X-RateLimit-Reset | Unix time (seconds) when the oldest counted request leaves the window, freeing capacity. |
X-RateLimit-Window | Window length in seconds (60). |
X-Concurrency-Limit | Your key's limit on simultaneous in-flight requests (paid plans). |
Retry-After | On 429 only: seconds to wait before retrying. |
Plans with a monthly allowance also return X-Quota-Limit, X-Quota-Remaining and
X-Quota-Reset. The keyless worldip.io/{ip} endpoint reports its daily
allowance in the same X-RateLimit-* headers (Reset = next 00:00 UTC) and has a
separate 60/min burst guard.
{ "error": "rate_limited", "retry_after_sec": 42, "limit_per_min": 1200, "remaining": 0, "reset": 1790812842 }
Using your API key on the free endpoint
Send your key as Authorization: Bearer <key> to https://worldip.io/{ip}
(HTTPS only — a key sent over plain HTTP is refused with 403 https_required) and basic
lookups become unlimited: no 1,000/day cap and nothing deducted from your plan.
- Your key's own limits apply instead of the keyless 60/min burst guard: its concurrency limit
(
X-Concurrency-Limit) and per-minute limit (X-RateLimit-*). - Responses carry
X-Free-Daily-Limit,X-Free-Daily-Remaining,X-Free-Daily-ResetandX-Billing(free-dailywithin the first 1,000/day per requester IP,unlimitedbeyond it — both are free). In the body,_meta.keylessisfalseand_meta.billingmatches. - The key needs the
ext:readscope. An invalid, disabled or malformed key returns401/403— it is never silently served as keyless. Use the header rather than?key=, which ends up in logs. - Browsers: the endpoint answers the CORS preflight for
Authorizationand exposes all of the headers above.
Errors
Errors use standard HTTP status codes with a JSON body of
{ "error": "...", "message": "..." } (the 429 body is shown above).
| Status | error | Meaning |
|---|---|---|
| 400 | bad_ip | Malformed IPv4 or IPv6 address in the path. Answered before authentication, so it is never counted. |
| 401 | missing_key | No key supplied. Response also sends WWW-Authenticate: Bearer. |
| 401 | malformed_authorization | An Authorization header was sent but not in Bearer <key> form. |
| 401 | invalid_key | Key not recognized or disabled. |
| 403 | forbidden_scope | Key lacks the required scope. |
| 403 | origin_not_allowed | Key is origin-locked; the request Origin/Referer did not match. |
| 403 | ip_not_allowed | Key is IP-locked; caller IP is off the allow-list. |
| 403 | https_required | A key was sent over plain HTTP; use https://. |
| 403 | no_enriched_access | The key’s plan does not include the enriched endpoint. |
| 429 | rate_limited | Rate limit exceeded; retry after retry_after_sec. |
| 429 | concurrency_exceeded | Too many simultaneous requests for your key; retry when one completes. |
| 429 | quota_exceeded | Monthly enriched allowance spent (metered plans); resets at the start of next month. |
| 503 | db_unavailable | Backend temporarily unavailable; retry shortly. |
| 503 | temporarily_unavailable | A brief maintenance window; retry after the Retry-After seconds. |
Plans & data tiers
Web lookups on worldip.io are always free and need no signup. The API adds a monthly allowance of enriched lookups and unlocks progressively richer data — proxy/threat classification, trust scoring, live BGP and Web3 node roles — while keeping a free, no-signup tier. Paid plans are not on sale yet; during the beta, keys come with issued.live Plus and Pro (see Beta keys).
| Plan | Price | Enriched / mo | Concurrent | Adds |
|---|---|---|---|---|
| Keyless | $0 | — | 60/min | Basic endpoint only, 1,000/day per IP, no signup. Owner/org, ASN, country, PTR, CIDR, for IPv4 and IPv6. |
| Free | $0 | — | 60/min | Unlimited basic-endpoint lookups with a key (60/min). Enriched endpoint requires a paid plan. Coming with account sign-up. |
| Basic | $9 | 25,000 | 5 | + the enriched endpoint, /24 neighbors, BGP prefix and origin ASN. |
| Pro | $39 | 200,000 | 10 | + VPN/proxy/Tor/datacenter classification, residential & mobile proxy detection, botnet & compromised-host reputation, access type, trust score. |
| Business | $129 | 1,000,000 | 20 | + MOAS & routing anomalies, the Pulse API, Web3 node roles. |
| Scale | $499 | 5,000,000 | 30 | Everything in Business, at the highest volume, with priority support. |
| Enterprise | Contact us | Custom | 100+ | Custom limits and volume under a written agreement, SLA, dedicated support. |
Annual billing is two months free (~17% off). See full pricing for details. Paid plans and self-serve keys are not open yet; during the beta, keys come with issued.live Plus and Pro — Beta keys. Limits may change during the beta.
Get launch updates
Paid plans and self-serve keys are not open yet. Drop your email and we'll message you the day they open — and again for major new endpoints. No spam, unsubscribe anytime. Already on issued.live Plus or Pro? Get your free beta key instead.
Frequently Asked Questions
How do I get an API key?
During the beta, keys are issued free to customers of issued.live Plus and Pro, the sister service of WorldIP: we email the key to the address on your issued.live account within one business day (details: worldip.io/developers#beta-keys). Self-serve keys and paid plans are not open yet. Without a key, the keyless endpoint (curl https://worldip.io/8.8.8.8 — 1,000 lookups/day, no signup) and the public Pulse feeds work today.
Do the web pages and the API share the same data?
Yes. Every field the API returns is the same intelligence rendered on worldip.io — the API just gives you one cached JSON call instead of scraping a page.
What does the /ext/ path mean?
It is the stable path of the keyed IP-intelligence lookup (/api/v1/ext/lookup). Call it server-side with your API key in the Authorization header, over HTTPS; never put a key in browser code or a URL.
Is IPv6 supported?
Yes. worldip.io/{ipv6} (free, no key) returns geolocation (country, plus region and city where available), reverse DNS from our own IPv6 scans, ASN, org name and CIDR. /api/v1/ext/lookup/{ipv6} adds org category, hosting/datacenter classification, IPv6 blocklists and iCloud Private Relay detection, on the same keys, quotas and limits as IPv4. VPN and proxy exit detection, trust score, live BGP and the hosted-domain count are IPv4-only; in an IPv6 profile those fields are null and the unavailable object says why. Most IPv6 reverse-DNS names are generated by the ISP from the address, and rdns.kind flags them.
What format are responses?
JSON, UTF-8. A success is 200 OK with the record at the top level; errors use standard HTTP status codes (400, 401, 403, 429, 503) with a JSON error body.
Does the API return the domains hosted on an IP?
The free keyless endpoint and the MCP tools carry domains_hosted for IPv4 addresses: how many domains are hosted on the address, counted once a week from the DNS snapshot of issued.live, WorldIP's sister service. It is a count, not a list. The keyed lookup is unchanged. issued.live's Reverse IP (paid plans) lists the hostnames seen on an address, current and past: https://issued.live/pricing.