IP Lookup API — geolocation, RDAP, ASN and security data

IP lookUp is a free REST API that turns any IP address into geolocation, RDAP registry, ASN/network, and VPN/proxy/threat-intel data. Call GET /api/v1/ip for a baseline result with no signup, or add ?include=geo,network,security for the full field set documented below.

Intro

IP lookUp turns a caller's (or any queried) IP address into trust & security signals, geolocation, and network/ASN identity — resolved live from RDAP, geo, and threat-intel data rather than static lookup tables.

Base URL: /api/v1

A basic lookup needs no signup or API key — enrichment groups and higher limits unlock with a free token.

Quickstart

1. Basic lookup — no key required

curl /api/v1/ip

2. Add enrichment groups

curl "/api/v1/ip?include=geo,network,security"

3. Authenticate with a token for higher limits

curl -H "Authorization: Bearer <token>" "/api/v1/ip?include=all"

Try it

Build a real request against this API and see the live response.

Endpoint

GET /api/v1/ip

Include groups

What data you get

Every field below is part of the v2 JSON response envelope, generated from the live API schema.

Geo

Field Type Description
geo.alternatives web.geoAltV2[] Alternatives are the losing geo sources' readings for this IP: each is that source's most-specific covering location plus its own source name and date. Omitted when only one source covers the IP.
geo.city string City is the city name from the winning source; "geo" group.
geo.cityNameLocal string CityNameLocal is the city's Russian name from the offline GeoNames gazetteer — resolved from the winner's (countryCode, region, city) text. Empty when the gazetteer has no match, no ru altname exists for the matched city, or there was nothing to resolve (no country/city on the winner). Part of the "geo" group like City itself — omitted on a baseline country-only response.
geo.confidence string Confidence flags city-level geo precision as "low" for network types where the city reading is unreliable (by default, mobile/carrier ranges, where the registered location often differs from the subscriber's).
geo.continent string Continent is the two-letter continent code, re-derived alongside CountryName from the country table; baseline.
geo.countryCode string CountryCode is the ISO 3166-1 alpha-2 country code from the winning geo source (DB-IP City Lite or an RFC 8805 geofeed); baseline (always present whenever any geo data exists for the IP).
geo.countryName string CountryName is the country's display name, re-derived from the country table for CountryCode (so a country-only override never carries a stale name); baseline.
geo.date string Date is the winning geo source's last-seen date, RFC3339 UTC date-time — the same format as the top-level cachedAt. Omitted when unknown.
geo.geonameId integer GeonameID is the matched GeoNames gazetteer entry's id — a stable cross-source city identifier distinct from City's raw text. Nilable: nil (JSON null/absent) means a resolve miss, never a fabricated 0. Part of the "geo" group like City itself.
geo.isEu boolean IsEu reports whether CountryCode is an EU member state, re-derived from the country table like CountryName/Continent; baseline.
geo.lat number Lat is the latitude in decimal degrees; nil means genuinely unknown, distinct from a real 0.0 reading at the equator. "geo" group.
geo.license string License is the winning source's data license (e.g. "CC BY 4.0" for dbip-city) — provenance/attribution detail, not baseline. Present only alongside the extended geo fields above, on a verbose request. Omitted when the source has no recorded license.
geo.lon number Lon is the longitude in decimal degrees; same nil-vs-0.0 semantics as Lat. "geo" group.
geo.matchConfidence string MatchConfidence is the match-quality signal for the cityNameLocal/geonameId resolve: "high" when country+admin1+name all matched, "low" when it fell back to a country+name-only homonym pick. Omitted (not "unknown") on a resolve miss — a consumer must not read absence as low confidence, only as "no match at all". Deliberately a SEPARATE field from Confidence above: Confidence is net-type-driven geo precision (mobile/MVNO carrier heuristic), MatchConfidence is gazetteer string-match quality — unrelated signals, never merged.
geo.postal string Postal is the postal/ZIP code; always empty today (DB-IP City Lite carries no postal data) — reserved for a future source. "geo" group.
geo.region string Region is the state/province/administrative-region name from the winning source; part of the "geo" group (entitlement.SetGeo) — empty on a baseline country-only response.
geo.regionMatchConfidence string RegionMatchConfidence reports the stored raw-region to GeoNames admin1 resolution quality. Omitted when the raw fallback is used.
geo.retrievedDate string RetrievedDate is when the continuous RIR crawler retrieved the winning source observation, RFC3339 UTC. Verbose-only and omitted for non-RIR or legacy unmarked RIR rows; this is deliberately distinct from Date (SCD-2 last_seen).
geo.source string Source is geo provenance: the name of the trust-ranked winning geo source (e.g. "dbip-city" or "aws-geofeed"). Always populated when geo is present (the winner is whichever source the merge picked); omitempty is kept only for the degenerate case of an unnamed source.
geo.timezone string Timezone is the IANA zone name (e.g. "Europe/Moscow") for the resolved location; "geo" group.
geo.url string URL is the winning geo source's own reference link (its dataset homepage or download page, e.g. "https://db-ip.com/db/lite.php" for dbip-city) — attribution/provenance detail alongside License, not a per-IP resource link. Same gating and omission rule as License.

Network

Field Type Description
network.allAsns string[] AllASNs lists every ASN Team Cymru reports announcing this prefix (multi-origin); always a non-nil array, empty when there's only one/none.
network.allocated string Allocated is Prefix's allocation date from Team Cymru — an allocation TIMESTAMP, not a usage-type flag (see UsageHint for that).
network.asName string ASName is the Team Cymru AS holder name — the coarse registered name, distinct from the refined network.classification.provider.
network.asn string ASN is the announcing Autonomous System number from Team Cymru (e.g. "AS15169"); baseline (always present for a routable IP with ASN data).
network.asnDomain string AsnDomain is the offline iplocate org's domain, sibling to AsnOrg; nil under the same conditions.
network.asnFetchedAt string ASNFetchedAt is the fetch time of the Team Cymru ASN facts above (asn/ allAsns/asName/prefix/registry/allocated/usageHint); see RDAPFetchedAt's doc above for the nil-vs-empty-string rule. Verbose-only.
network.asnOrg string AsnOrg/AsnDomain carry the offline iplocate org name/domain, populated from the MariaDB data resolver. nil/null when the resolver is off or the IP has no matching ASN block. These are distinct from the live Cymru facts above (asn/asName/prefix/registry/allocated/usageHint).
network.classification netinfo.Result Classification is the synthesized IP-type verdict (hosting/datacenter/ residential/mobile/…); always populated for a routable IP.
network.prefix string Prefix is the announced CIDR block covering the IP, from Team Cymru.
network.rdap rdap.Info RDAP is a pointer so the block is JSON null when there is no RDAP data at all; when the "network" group isn't included in the response it instead carries a trimmed {country, handle, name} subset (always present at baseline). asnOrg/asnDomain above are nullable for the same not-included reason.
network.rdapFetchedAt string RDAPFetchedAt/ASNFetchedAt are the fetch times of the RDAP registry record and the Team Cymru ASN facts above, RFC3339 (same format as the top-level cachedAt). Verbose-only: nil (omitted) on a non-verbose request. On a verbose request the pointer distinguishes two states that both stringify to "": nil means the source was never resolved (disabled, or genuinely no data), while a non-nil pointer to "" means the sibling data (rdap/asn) IS present but the store that served it can't report a fetch time (e.g. a MariaDB-only deployment). Without this, a consumer can't tell "no data" from "data, unknown age".
network.registry string Registry is the RIR that allocated Prefix (e.g. "ripencc", "arin"), from Team Cymru.
network.usageHint string UsageHint is Team Cymru's coarse allocation type (e.g. "DIRECT ALLOCATION", "ASSIGNED PA"), not a usage-type classification of the IP itself.

Security

Field Type Description
privacy.isAnonymous boolean IsAnonymous is derived as IsTor || IsVPN || IsProxy; inherits IsTor's degraded-false posture when the cloudtor matcher didn't run, and IsProxy's when the net-flags resolver didn't run/match.
privacy.isProxy boolean IsProxy is the IPFire libloc "is-anonymous-proxy" network flag: false when the underlying resolver is disabled, has no covering data for the address, or errored — same best-effort posture as IsVPN's rules signal. No other proxy data source is wired.
privacy.isRelay boolean IsRelay always reports false — no adopted data source (unused today).
privacy.isResidentialProxy boolean IsResidentialProxy always reports false — no free data source exists (known gap).
privacy.isTor boolean IsTor reuses the cloudtor Tor-exit match (flags.isTor); degraded to false (not an authoritative negative) when Tor detection isn't enabled server-side.
privacy.isVpn boolean IsVPN is the coarse VPN/hosting-posture signal: true only when network.classification.source is "rule" (X4BNet-derived hosting/ datacenter rows) AND type is hosting or datacenter — excludes the weaker cloud- and heuristic-sourced hosting matches.
threat.isMalicious boolean IsMalicious is the aggregate malicious-IP verdict across the loaded threat-intelligence feeds; only present when the security group was evaluated.
threat.reports web.threatReportV2[] Reports is the verbose evidence-API payload: one entry per persisted MISP event backing this IP's match. Omitted (nil) for a non-verbose caller, an unmatched/unevaluated IP, or when the evidence lookup errored.
threat.sources string[] Sources lists which loaded threat-intel feeds flagged the IP; always a non-nil array, empty ([]) for a clean IP.
threat.threatLevel integer ThreatLevel is the aggregated (most-severe/min) MISP threat_level_id across every matching entry that carries one: 1=High, 2=Medium, 3=Low, 4=Undefined. Nil (omitted) when no matching entry carries a level — e.g. a clean IP, or a match backed only by thin/index-only (non-MISP) sources. Gated identically to isMalicious/sources (the security group only) — independent of verbose, unlike Reports below.
recon.isScanner boolean IsScanner is the advisory active-recon/brute-force verdict from the Dataplane.org matcher; only present when recon was actually evaluated (this whole block is null otherwise). NOT threat.isMalicious.
recon.lastSeen string LastSeen is the most recent contributing signal's own observation timestamp (RFC3339, same format as cachedAt/geo.date) — lets a consumer judge how fresh the scanning activity is, since Dataplane's recon feeds age out via a configured decay window rather than staying "hot" forever between refreshes. Omitted when unknown (e.g. IsScanner false, or every contributing row carried an unparseable timestamp).
recon.sources string[] Sources lists which Dataplane.org signal(s) recently observed the IP (e.g. "sshpwauth", "telnetlogin"); always a non-nil array, empty ([]) for a clean IP — mirrors threat.sources' convention.
censorship.confirmedRate number ConfirmedRate is the fraction of OONI measurements classified as confirmed blocking over the rolling window, for the caller's ASN+country.
censorship.isCensored boolean IsCensored reports whether ConfirmedRate exceeds the configured blocking threshold for the caller's ASN+country (OONI-derived).
censorship.sampleSize integer SampleSize is the number of OONI measurements aggregated into ConfirmedRate.
fraud.level string Level buckets Score into low/medium/high against the service's configured thresholds.
fraud.score integer Score is the 0-100 risk-score rollup: a weighted sum of the fired Signals, saturating at 100.
fraud.signals string[] Signals names every weighted input that fired (e.g. "hosting", "vpn", "tor", "malicious", "censored", "ptrMissing", "bulkMail"), so Score is explainable; empty ([]) for a clean IP.

Plan & Limits

Field Type Description
plan.groups map<web.groupPlanV2> Groups is keyed by metered group name (geo/network/security); request-scoped like limited[]/gated[] — a group this request's metering pipeline never reached (not requested, gated, or concurrent-duplicate withheld) has no entry, since there is no live-peek primitive for an unrequested group's cardinality without mutating its SET.
plan.servedFromTopup string[] ServedFromTopup lists metered groups whose per-day budget was exhausted this request and were served from the persistent top-up bucket instead.
plan.tier string Tier duplicates the top-level Tier field (self-contained for a consumer reading only the plan section, same as GET /api/v1/usage's own "tier").
plan.tokenName string TokenName is the API token's name, present when the caller authenticated via an opaque API token; omitted for a session-JWT-authed or anonymous caller.

Endpoints

Endpoint Metered group ?include= support Description
GET /api/v1/ip geo, network, security (opt-in) yes — geo, network, security, all Baseline classification, always returned; opt into geo/network/security enrichment with ?include=.
GET /api geo, network, security (opt-in) yes — geo, network, security, all Version-agnostic alias — always mirrors the current latest baseline endpoint (today /api/v1/ip).

Snippets

Ready-to-paste examples for calling the API from common languages.

Anonymous
Authenticated
Anonymous
Authenticated
Anonymous
Authenticated
Anonymous
Authenticated
Anonymous
Authenticated

Auth & Limits

Auth & tokens

Create and manage API tokens from your dashboard — sign in, no separate application process.

Send it as a request header: Authorization: Bearer <token>

A basic lookup never needs a key at all. A token buys higher per-group limits than the anonymous tier — see the comparison below.

Get a token

Limits & metering

Enrichment is metered per unique caller IP, tracked separately for each group — geo, network, security — against both a per-day and a per-minute budget. The baseline /api/v1/ip fields are always returned; only the enrichment groups are budgeted.

Going over budget never fails the request. The response still comes back HTTP 200 with status: "partial" and the withheld group listed in limited[] — that group's fields are simply null for this call.

The response's plan section shows your tier, the remaining per-day/per-minute budget for each requested group, and your top-up balance — so you can see exactly what's left without a separate call.

Dimension Anonymous With API token
Baseline lookup Always available, no signup Always available
Enriched groups (geo/network/security) Metered at the anonymous tier's per-day/per-minute budget Metered at your tier's own (usually higher) per-day/per-minute budget
Exact limit figures See /pricing.html or GET /api/v1/usage — always read live from your account
Over budget HTTP 200 with status: "partial" and the group listed in limited[] — never a hard error

Open-source projects can request a free Pro or Business tier for one year, on request.

View pricing & tiers

Frequently asked questions

Is the IP lookup API free to use?
Yes. GET /api/v1/ip needs no signup or API key and returns baseline classification, network and DNS facts plus country-level geolocation for free. The geo, network and security enrichment groups are metered per unique IP per day; registering for a free token moves that metering to your account's own (usually higher) budget, and open-source projects can request a free Pro or Business tier for a year.
What data does the IP lookup API return?
Every response includes IP classification, ASN/network facts, DNS (PTR/hostnames) and country-level geolocation. Add ?include=geo,network,security to also get extended geo fields, the full RDAP registry record, and privacy/threat/fraud signals — see the full field reference at https://ip.xakki.pro/docs/.
Does the API detect VPN, proxy or Tor use?
Partly, and precisely: isVpn is inferred, not looked up against a VPN provider list — it's true only when the address's network classification is hosting/datacenter infrastructure (from curated hosting-network rules), the kind of network posture VPN services typically run on. isProxy comes from a separate anonymous-proxy network flag (IPFire libloc), also infrastructure-based, not a proxy-service database. isTor matches known Tor exit-node addresses. isAnonymous is simply isTor || isVpn || isProxy. Two related fields, isResidentialProxy and isRelay, are reserved in the schema but always return false today — no data source is wired for them, so don't treat them as working signals. The threat block separately reports known-malicious sources, and fraud rolls every signal into a single 0-100 risk score.
How is the API authenticated and rate-limited?
Create a token from your dashboard and send it as Authorization: Bearer <token>. Enrichment is metered by the number of distinct IP addresses you look up — per day and per minute, separately for each group — so repeat lookups of the same address within a window cost nothing. Going over budget never fails the request: it returns HTTP 200 with status: "partial" and the withheld group listed in limited[].
Can I look up ASN and RDAP registry data for an IP?
Yes. The network group returns the full RDAP registry record (org, contacts, remarks, status) plus Team Cymru ASN facts — announcing ASN, AS name, prefix, registry and allocation date.

Full reference

Browse the complete API surface in Swagger UI, or grab the raw OpenAPI spec.