API Reference
One endpoint, one response shape: 10 groups on every lookup, every field on every plan. This page is the complete reference. How the classifications are made is documented on the methodology page.
On this page
Overview
The GeoIPHub API is a REST API that returns the full intelligence record for any IPv4 or IPv6 address: geolocation, routing, WHOIS, network evidence, anonymizer detection, threat flags, and an explainable risk score, all in a single response.
https://api.geoiphub.comKnown IPs are served from a memory-mapped database in sub-millisecond time. An IP not yet in the database is classified live in under 2.5 seconds, then persisted, so expect the first lookup of a brand-new IP to take longer than every lookup after it.
Authentication
Two modes. Anonymous requests need no key and are limited to 30 lookups per minute, which is useful for testing and small scripts. Production traffic should send an API key in the x-api-key header. Get a free key from the dashboard, no credit card required.
# Anonymous: 30 lookups/minute, no key
curl https://api.geoiphub.com/v1/lookup/8.8.8.8
# With an API key: production
curl -H "x-api-key: YOUR_API_KEY" \
https://api.geoiphub.com/v1/lookup/8.8.8.8Lookup endpoint
/v1/lookup/{ip}{ip} is any IPv4 or IPv6 address. The response is a single JSON object with 10 top-level groups; the complete shape is shown in the response sample below. There are no field tiers: every plan, including anonymous requests, receives every field.
Quickstart
Fields live inside their groups. Read data.geo.country_code, not data.country.
curl -H "x-api-key: YOUR_API_KEY" \
https://api.geoiphub.com/v1/lookup/8.8.8.8Response sample
The complete response for 8.8.8.8. The API does not return JSON null. A field with no value comes back as the string "none", and numeric fields such as geo_confidence come back as 0, so check against "none" rather than null when you parse.
{
"ip": "8.8.8.8",
"asn": {
"asn": 15169,
"org": "GOOGLE - Google LLC",
"asn_type": "hosting",
"user_type": "hosting",
"isp": "GOOGLE - Google LLC",
"domain": "none",
"connection_type": "datacenter",
"access_type": "datacenter",
"carrier": "none",
"mcc": "none",
"mnc": "none",
"rpki": "invalid"
},
"geo": {
"country_code": "US",
"country_name": "United States",
"country_names": { "en": "United States", "es": "Estados Unidos de América (los)", "fr": "États-Unis", "de": "Vereinigte Staaten von Amerika", "ja": "アメリカ合衆国", "zh-CN": "美国" },
"country_geoname_id": 6252001,
"continent_code": "NA",
"continent_name": "North America",
"continent_geoname_id": 6255149,
"is_in_european_union": false,
"flag_emoji": "🇺🇸",
"region": "California",
"city": "Mountain View",
"timezone": "none",
"latitude": 37.422,
"longitude": -122.085,
"geo_confidence": 0.8
},
"whois": {
"org": "none",
"country": "US",
"netname": "none",
"status": "none",
"registered": "2023-12-28T00:00:00.000Z",
"last_changed": "none",
"has_vpn_keywords": false,
"has_hosting_keywords": false
},
"network": {
"ptr_record": "dns.google",
"ptr_pattern": "none",
"fcrdns_valid": true,
"abuse_contact": "network-abuse@google.com",
"open_ports": [],
"service": "none",
"cloud_region": "none"
},
"detection": {
"is_proxy": false,
"is_vpn": false,
"is_tor": false,
"is_hosting": true,
"is_relay": false,
"is_mobile": false,
"is_satellite": false,
"is_anycast": true,
"is_residential_proxy": false,
"is_public_proxy": false,
"is_anonymous": false,
"proxy_type": "none",
"anonymity_level": "low",
"vpn_provider": "none",
"vpn_provider_tier": "none",
"relay_provider": "none",
"proxy_score": 0,
"vpn_confidence": 5,
"residential_proxy_score": 0,
"last_seen": "2026-07-05T16:21:06.000Z"
},
"threat": {
"is_abusive": false,
"is_bogon": false,
"is_crawler": false,
"is_spammer": false,
"is_scanner": false,
"is_botnet": false,
"is_cgnat": false,
"threat_types": [],
"blocklist_count": 0,
"blocklist_sources": [],
"dnsbl_sources": [],
"crawler": {
"verified": false,
"unverified": false,
"spoofed": false,
"name": "none",
"operator": "none",
"category": "none",
"verification_method": "none"
},
"botnet": {
"role": "none",
"family": "none",
"last_seen": "none"
},
"honeypot": {
"hits_30d": 0,
"type": "none",
"last_hit": "none"
},
"spammer_last_seen": "none"
},
"dns": {
"ptr_record": "dns.google",
"ptr_pattern": "none",
"fcrdns_valid": true
},
"scoring": {
"fraud_score": 10,
"confidence": 0.25,
"recommended_action": "allow",
"detection_methods": ["datacenter_ip"]
},
"meta": {
"last_classified_at": "2026-07-06T18:04:23.644Z",
"last_scanned": "2026-07-05T16:21:06.000Z",
"request_id": "f9791cfc-2a48-4f74-82cb-036f3b2eb86b",
"latency_ms": 1,
"sources": []
}
}Field reference
Every field, grouped exactly as the response groups them. Dotted names (e.g. crawler.verified) are nested objects inside their group. A field with no value returns the string "none" (or 0 for numeric fields), never null.
ip
The address that was looked up.
| Field | Type | Description |
|---|---|---|
| ip | string | The IPv4 or IPv6 address this response describes, echoed back. |
asn
Routing and network-type data from a BGP/ASN table refreshed every 3 days.
| Field | Type | Description |
|---|---|---|
| asn | number | Autonomous system number announcing this IP. |
| org | string | Organization name registered to the ASN. |
| asn_type | string | Classification of the AS, e.g. "hosting", "isp", "mobile", "satellite". |
| user_type | string | Usage classification derived from routing and rDNS, e.g. "residential", "hosting", "cellular", "business", "search_engine_spider". |
| isp | string | ISP name serving this IP. |
| domain | string | Domain associated with the ASN organization. |
| connection_type | string | Connection class, e.g. "datacenter", "residential", "mobile", "satellite". |
| access_type | string | Access medium read from rDNS markers, e.g. "fiber", "cable", "dsl", "cellular", "datacenter". |
| carrier | string | Mobile carrier name, when the IP belongs to a cellular network. |
| mcc | string | Mobile Country Code, for cellular IPs. |
| mnc | string | Mobile Network Code, for cellular IPs. |
| rpki | string | RPKI route-origin validation state: "valid", "invalid", or "unknown". |
geo
Location data from RIR registry records, BGP context, and licensed city-level data.
| Field | Type | Description |
|---|---|---|
| country_code | string | ISO 3166-1 alpha-2 country code. |
| country_name | string | Full country name. |
| country_names | object | Localized country names keyed by language code (en, de, es, fr, ja, ko, pt-BR, ru, zh-CN, fa). |
| country_geoname_id | number | GeoNames identifier for the country. |
| continent_code | string | Two-letter continent code, e.g. "NA", "EU". |
| continent_name | string | Full continent name. |
| continent_geoname_id | number | GeoNames identifier for the continent. |
| is_in_european_union | boolean | True when the country is an EU member state. |
| flag_emoji | string | Unicode flag emoji for the country. |
| region | string | Administrative region or state. |
| city | string | City-level location. |
| timezone | string | IANA timezone identifier. |
| latitude | number | Latitude in decimal degrees. |
| longitude | number | Longitude in decimal degrees. |
| geo_confidence | number | Confidence in the city-level answer. Returns 0 when there isn't enough evidence to state one. |
whois
Registration intelligence from RDAP across all 5 RIRs (ARIN, RIPE, APNIC, LACNIC, AFRINIC), refreshed weekly.
| Field | Type | Description |
|---|---|---|
| org | string | Registrant organization from the RDAP record. |
| country | string | Registration country from the RDAP record. |
| netname | string | Network name (netblock name) from the RDAP record. |
| status | string | Allocation status of the block, e.g. "ASSIGNED PA", "ALLOCATED PORTABLE". |
| registered | string | Registration date, when the registry publishes one. |
| last_changed | string | Date the registry record was last modified, when published. |
| has_vpn_keywords | boolean | Registration text matched at least one of 46 VPN keywords. |
| has_hosting_keywords | boolean | Registration text matched at least one of 27 hosting keywords. |
network
Evidence gathered from the network itself: reverse DNS, the published abuse contact, active port probes, and published cloud ranges.
| Field | Type | Description |
|---|---|---|
| ptr_record | string | Reverse DNS (PTR) hostname for the IP, when one resolves. |
| ptr_pattern | string | Classification of the PTR hostname, e.g. "residential", "mobile". |
| fcrdns_valid | boolean | Forward-confirmed reverse DNS: whether the PTR hostname resolves back to this IP. |
| abuse_contact | string | Abuse contact published in the registry record. |
| open_ports | number[] | Ports that answered during active probing. |
| service | string | Service identified on the probed ports. |
| cloud_region | string | Cloud provider region, when the IP falls in a provider's published range. |
detection
Anonymizer detection, verified by protocol handshakes on 25+ ports across 11 protocols and by 10 VPN providers' own published server lists.
| Field | Type | Description |
|---|---|---|
| is_proxy | boolean | IP responded as an open proxy during active probing. |
| is_vpn | boolean | IP verified as VPN infrastructure by handshake, provider server list, ASN, or WHOIS evidence. |
| is_tor | boolean | IP appears on the official Tor Project exit list (refreshed daily). |
| is_hosting | boolean | IP belongs to hosting or datacenter infrastructure. |
| is_relay | boolean | IP is a privacy relay (iCloud Private Relay or Cloudflare WARP), reported separately from VPNs. |
| is_mobile | boolean | IP belongs to a mobile/cellular network. |
| is_satellite | boolean | IP belongs to a satellite ISP (e.g. Starlink). |
| is_anycast | boolean | IP is announced from multiple locations (anycast), per the manycast.net census. Common for public DNS and CDNs. |
| is_residential_proxy | boolean | Inferred: true when a proxy is detected on a residential or mobile connection. Coarse ASN-based inference, not direct observation. |
| is_public_proxy | boolean | IP appears as a publicly listed open proxy. |
| is_anonymous | boolean | Composite flag: true when any anonymizer signal (VPN, proxy, Tor, relay) applies. |
| proxy_type | string | Protocol of the detected proxy (e.g. SOCKS5, HTTP CONNECT). |
| anonymity_level | string | Anonymity level of the detected proxy. |
| vpn_provider | string | Named VPN provider when the IP appears in a provider's own published server list, e.g. "NordVPN". |
| vpn_provider_tier | string | Tier of the attributed VPN provider, when known. |
| relay_provider | string | Named privacy-relay provider, e.g. "iCloud Private Relay", "Cloudflare WARP". |
| proxy_score | number | 0–100 proxy likelihood score. |
| vpn_confidence | number | 0–100 confidence that this IP is VPN infrastructure. |
| residential_proxy_score | number | Inferred residential-proxy likelihood; 0 when not applicable. |
| last_seen | string | ISO 8601 timestamp of the most recent detection evidence. |
threat
Threat flags from named public feeds (refreshed daily) plus verified crawler identification from 9 official IP-range feeds (refreshed every 2 days).
| Field | Type | Description |
|---|---|---|
| is_abusive | boolean | IP appears on abuse-focused threat feeds. |
| is_bogon | boolean | IP falls in unallocated or reserved space (Team Cymru bogon data). |
| is_crawler | boolean | IP belongs to a known crawler or AI bot. |
| is_spammer | boolean | IP is a known spam source. |
| is_scanner | boolean | IP belongs to known internet-wide scanner ranges (e.g. Shodan, Censys). |
| is_botnet | boolean | IP appears in botnet C2 data (Feodo Tracker). |
| is_cgnat | boolean | IP is in a carrier-grade NAT range shared by many users. Risk scores are capped for CGNAT ranges. |
| threat_types | string[] | Every threat category that applies to this IP. |
| blocklist_count | number | Number of blocklists currently listing this IP. |
| blocklist_sources | string[] | Names of the blocklists that listed this IP. |
| dnsbl_sources | string[] | Which of the 4 DNS blocklist zones listed this IP. |
| crawler.verified | boolean | Crawler identity confirmed against its operator's official IP ranges. |
| crawler.unverified | boolean | Crawler-like identity that could not be confirmed against official ranges. |
| crawler.spoofed | boolean | Claims a crawler identity but is not in the operator's official IP ranges. |
| crawler.name | string | Crawler name, e.g. "Googlebot", "GPTBot". |
| crawler.operator | string | Organization operating the crawler. |
| crawler.category | string | Crawler category. |
| crawler.verification_method | string | How the crawler identity was verified. |
| botnet.role | string | Role in the botnet, when known. |
| botnet.family | string | Malware family, when known. |
| botnet.last_seen | string | ISO 8601 timestamp of the last botnet sighting. |
| honeypot.hits_30d | number | Honeypot interactions recorded in the last 30 days. |
| honeypot.type | string | Type of honeypot interaction, when any exists. |
| honeypot.last_hit | string | ISO 8601 timestamp of the last honeypot interaction. |
| spammer_last_seen | string | ISO 8601 timestamp of the last spam sighting. |
dns
Reverse DNS (PTR) data for the IP, also mirrored inside the network group.
| Field | Type | Description |
|---|---|---|
| ptr_record | string | Reverse DNS (PTR) hostname for the IP, when one resolves. |
| ptr_pattern | string | Classification of the PTR hostname, e.g. "residential", "mobile". |
| fcrdns_valid | boolean | Forward-confirmed reverse DNS: whether the PTR hostname resolves back to this IP. |
scoring
An explainable 0–100 risk score from 40+ weighted signals, including exonerating signals and CGNAT caps.
| Field | Type | Description |
|---|---|---|
| fraud_score | number | 0–100 composite risk score. Exonerating signals subtract (residential ISP −20, verified crawler −30); CGNAT ranges are capped. |
| confidence | number | Overall confidence in the verdict, 0.0 to 1.0, based on how much evidence is available for this IP. |
| recommended_action | string | "allow" (0–25), "review" (26–50), "step_up" (51–75), or "block" (76–100). |
| detection_methods | string[] | The exact signals that fired for this IP: the score's reasoning, machine-readable. |
meta
Provenance and performance data for the lookup itself.
| Field | Type | Description |
|---|---|---|
| last_classified_at | string | ISO 8601 timestamp of the most recent classification. |
| last_scanned | string | ISO 8601 timestamp of the most recent active scan. |
| request_id | string | Unique identifier for this request; include it in support emails. |
| latency_ms | number | Server-side processing time for this lookup, in milliseconds. |
| sources | string[] | Data sources that contributed to this classification. |
Rate limits
| Tier | Limit | Notes |
|---|---|---|
| Anonymous | 30 lookups/min | No key required. Exceeding the limit triggers a temporary block. |
| Free | 1,500 lookups/day | Resets at 00:00 UTC. Every data field included. No credit card. |
| Paid plans | Higher daily limits | Same response, same fields, more volume. See pricing. |
Errors
Errors return conventional HTTP status codes with a JSON body containing a message field.
GET /v1/lookup/not-an-ip
{ "message": "Invalid IP address format" }| Status | Meaning |
|---|---|
| 400 | The supplied value is not a valid IPv4 or IPv6 address. |
| 404 | The IP is unknown and live classification failed. Rare; retrying later usually succeeds once the scanner can reach the address. |
| 429 | Rate limit exceeded. Anonymous traffic over 30 lookups/minute is temporarily blocked; keyed traffic over its daily quota is rejected until the UTC reset. |
Want to know how the classifications behind these fields are made? Read the methodology, or try the API without writing code using the free IP lookup tool.
Get Started Free