openapi: 3.0.7
info:
title: 'IPGeolocation.io: IPGeolocation API'
version: "3.0"
description: |
Look up geolocation, network, company, ASN, timezone, currency, abuse contact, and security
threat data for any IPv4 address, IPv6 address, or domain name. The API also parses
User-Agent strings when requested.
Two endpoints are available:
- **Single lookup** (`GET /v3/ipgeo`) returns data for one IP or domain per request.
- **Bulk lookup** (`POST /v3/ipgeo-bulk`) accepts up to 50,000 IPs or domains in a
single request. Requires a paid plan.
Use query parameters to control which optional modules are included, which fields are
returned, and which fields are excluded. Both endpoints share the same query parameters
and the same response schema per IP.
## Authentication
Two authentication methods are supported:
### API Key
Pass your API key as the `apiKey` query parameter on every request. You can find your
key in the [IPGeolocation dashboard](https://app.ipgeolocation.io/). Store it in
server-side environment variables. Avoid exposing it in client-side JavaScript.
### Request Origin (CORS)
Available on paid plans only. Whitelist your domain in the dashboard under the
"API Keys" section. Once configured, requests from that domain (and all its subdomains)
are accepted without passing `apiKey`. Enter your root domain (e.g. `example.com`),
not the full URL.
Each plan has a limit on the number of extra API keys and request origins:
| Plan | Extra API Keys + Request Origins |
|---|---|
| Starter (150K requests) | 1 |
| Core (250K requests) | 1 |
| Plus (500K requests) | 2 |
| Pro (1M requests) | 2 |
| Business (2M requests) | 3 |
| Premium (5M requests) | 3 |
Additional keys or origins can be added for $2.50 per month each.
## Response Formats
The API supports JSON (default) and XML output.
- Set the `output` query parameter to `json` or `xml`.
- Alternatively, set the `Accept` header to `application/json`, `application/xml`,
or `text/xml`.
If neither is specified, the response is returned as JSON. XML responses use a
`LinkedHashMap` root element.
## Credits
Credits are charged only on successful HTTP 200 responses. The exact charge for any
request is returned in the `X-Credits-Charged` response header.
| Condition | Credits charged |
|---|---|
| Base lookup (location, ASN, company, network, currency, timezone) | 1 |
| Adding `dma_code`, `geo_accuracy`, `hostname`, or `user_agent` | 0 extra (still 1) |
| Adding `security` | +2 (total 3) |
| Adding `abuse` | +1 (total 2) |
| Adding `security` and `abuse` | +3 (total 4) |
| `include=*` (everything) | 4 |
| Only `security` via `include=security&fields=security` | 2 |
| Only `abuse` via `include=abuse&fields=abuse` | 1 |
For bulk requests, total credits equal credits per lookup multiplied by the number of
valid IPs. Private, bogon, and malformed IPs are not counted as valid and do not
consume credits.
## Response Language
Pass `lang` to get translated location names. English is the default. Non-English
responses require a paid plan.
## Field Filtering
Use `fields` to cherry-pick specific fields, or `excludes` to drop fields you do not
need. Both accept dot-notation for nested fields (e.g. `location.city`,
`security.threat_score`). The `ip` field is always present regardless of filters.
## Parameter Name Casing
Query parameter names are case-sensitive. Use exact names such as `apiKey`, `ip`,
`include`, `fields`, `excludes`, `lang`, and `output`.
## Rate Limits
- **Free plan:** 1,000 requests per day (hard limit).
- **Paid plans:** No daily, hourly, or monthly rate limit. If the monthly quota is
exceeded, requests continue and a surcharge is added to the monthly bill.
## Free vs. Paid Plan Differences
| Capability | Free | Paid |
|---|---|---|
| IPv4 / IPv6 lookup | Yes | Yes |
| Domain lookup | No | Yes |
| Bulk lookup (`/v3/ipgeo-bulk`) | No | Yes |
| `include` parameter (optional modules) | No | Yes |
| `lang` (non-English responses) | No | Yes |
| `fields` / `excludes` filtering | Yes | Yes |
| `network` object in default response | No | Yes |
| `company` object in default response | No | Yes |
| Basic `asn` fields (`as_number`, `organization`, `country`) | Yes | Yes |
| Extended `asn` fields (`type`, `domain`, `rir`, `date_allocated`) | No | Yes |
contact:
name: IPGeolocation Support
url: https://ipgeolocation.io/contact.html
email: [email protected]
termsOfService: https://ipgeolocation.io/tos.html
license:
name: Proprietary
url: https://ipgeolocation.io/tos.html
externalDocs:
description: IPGeolocation IP Location API documentation
url: https://ipgeolocation.io/documentation/ip-location-api.html
servers:
- url: https://api.ipgeolocation.io
description: Production
security:
- ApiKeyAuth: []
paths:
/v3/ipgeo:
get:
operationId: lookupIpGeolocation
summary: IPGeolocation.io Single IP Geolocation Lookup
description: |
Returns geolocation and enrichment data for a single IPv4 address, IPv6 address,
or domain name. When `ip` is omitted, the API resolves the caller's public IP
automatically, which is useful for client-side lookups.
The base response always includes `location`, `country_metadata`, `currency`,
`asn`, and `time_zone`. Paid plans also get `network` and `company` by default.
Use the `include` parameter to add optional modules such as `security`, `abuse`,
`user_agent`, `geo_accuracy`, `dma_code`, and hostname resolution.
Use `fields` and `excludes` to control exactly which parts of the response you
receive. This reduces payload size and can improve response times.
tags:
- IP Geolocation
parameters:
- $ref: "#/components/parameters/Ip"
- $ref: "#/components/parameters/Lang"
- $ref: "#/components/parameters/Include"
- $ref: "#/components/parameters/Fields"
- $ref: "#/components/parameters/Excludes"
- $ref: "#/components/parameters/Output"
responses:
"200":
description: Geolocation data for the requested IP or domain.
headers:
X-Credits-Charged:
description: Number of API credits consumed by this request.
schema:
type: number
example: 1
content:
application/json:
schema:
$ref: "#/components/schemas/IpGeolocationResponse"
examples:
paidFullResponse:
summary: Paid plan, all modules included
value:
ip: "91.128.103.196"
hostname: "91.128.103.196"
location:
continent_code: "EU"
continent_name: "Europe"
country_code2: "SE"
country_code3: "SWE"
country_name: "Sweden"
country_name_official: "Kingdom of Sweden"
country_capital: "Stockholm"
state_prov: "Stockholms län"
state_code: "SE-AB"
district: "Stockholm"
city: "Stockholm"
locality: "Stockholm"
accuracy_radius: "4.395"
confidence: "high"
dma_code: ""
zipcode: "164 40"
latitude: "59.40510"
longitude: "17.95510"
is_eu: true
country_flag: "https://ipgeolocation.io/static/flags/se_64.png"
geoname_id: "9972319"
country_emoji: "🇸🇪"
country_metadata:
calling_code: "+46"
tld: ".se"
languages:
- "sv-SE"
- "se"
- "sma"
- "fi-SE"
network:
connection_type: ""
route: "91.128.0.0/14"
is_anycast: false
currency:
code: "SEK"
name: "Swedish Krona"
symbol: "kr"
asn:
as_number: "AS1257"
organization: "Tele2 Sverige AB"
country: "SE"
type: "ISP"
domain: "tele2.com"
date_allocated: "2024-12-13"
rir: "RIPE"
company:
name: "Tele2 Sverige AB"
type: "ISP"
domain: "tele2.com"
security:
threat_score: 0
is_tor: false
is_proxy: false
proxy_provider_names: []
proxy_confidence_score: 0
proxy_last_seen: ""
is_residential_proxy: false
is_vpn: false
vpn_provider_names: []
vpn_confidence_score: 0
vpn_last_seen: ""
is_relay: false
relay_provider_name: ""
is_anonymous: false
is_known_attacker: false
is_bot: false
is_spam: false
is_cloud_provider: false
cloud_provider_name: ""
abuse:
route: "91.128.0.0/14"
country: "SE"
name: "Swipnet Staff"
organization: ""
kind: "group"
address: "Tele2 AB/Swedish IP Network, IP Registry, Torshamnsgatan 17 164 40 Kista SWEDEN"
emails:
- "[email protected]"
phone_numbers:
- "+46 8 5626 42 10"
time_zone:
name: "Europe/Stockholm"
offset: 1
offset_with_dst: 1
current_time: "2026-02-13 09:19:24.410+0100"
current_time_unix: 1770970764.41
current_tz_abbreviation: "CET"
current_tz_full_name: "Central European Standard Time"
standard_tz_abbreviation: "CET"
standard_tz_full_name: "Central European Standard Time"
is_dst: false
dst_savings: 0
dst_exists: true
dst_tz_abbreviation: "CEST"
dst_tz_full_name: "Central European Summer Time"
dst_start:
utc_time: "2026-03-29 TIME 01:00"
duration: "+1.00H"
gap: true
date_time_after: "2026-03-29 TIME 03:00"
date_time_before: "2026-03-29 TIME 02:00"
overlap: false
dst_end:
utc_time: "2026-10-25 TIME 01:00"
duration: "-1.00H"
gap: false
date_time_after: "2026-10-25 TIME 02:00"
date_time_before: "2026-10-25 TIME 03:00"
overlap: true
user_agent:
user_agent_string: "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 Edg/143.0.0.0"
name: "Edge"
type: "Browser"
version: "143"
version_major: "143"
device:
name: "Linux Desktop"
type: "Desktop"
brand: "Unknown"
cpu: "Intel x86_64"
engine:
name: "Blink"
type: "Browser"
version: "143"
version_major: "143"
operating_system:
name: "Linux"
type: "Desktop"
version: "??"
version_major: "??"
build: "??"
freeMinimalResponse:
summary: Free plan default response
value:
ip: "165.227.0.0"
location:
continent_code: "NA"
continent_name: "North America"
country_code2: "US"
country_code3: "USA"
country_name: "United States"
country_name_official: "United States of America"
country_capital: "Washington, D.C."
state_prov: "California"
state_code: "US-CA"
district: "Santa Clara County"
city: "Santa Clara"
zipcode: "95051"
latitude: "37.35983"
longitude: "-121.98144"
is_eu: false
country_flag: "https://ipgeolocation.io/static/flags/us_64.png"
geoname_id: "5346804"
country_emoji: "🇺🇸"
country_metadata:
calling_code: "+1"
tld: ".us"
languages:
- "en-US"
- "es-US"
- "haw"
- "fr"
currency:
code: "USD"
name: "US Dollar"
symbol: "$"
asn:
as_number: "AS14061"
organization: "DigitalOcean, LLC"
country: "US"
time_zone:
name: "America/Los_Angeles"
offset: -8
offset_with_dst: -8
current_time: "2026-02-09 09:54:51.206-0800"
current_time_unix: 1770659691.206
current_tz_abbreviation: "PST"
current_tz_full_name: "Pacific Standard Time"
standard_tz_abbreviation: "PST"
standard_tz_full_name: "Pacific Standard Time"
is_dst: false
dst_savings: 0
dst_exists: true
dst_tz_abbreviation: "PDT"
dst_tz_full_name: "Pacific Daylight Time"
dst_start:
utc_time: "2026-03-08 TIME 10:00"
duration: "+1.00H"
gap: true
date_time_after: "2026-03-08 TIME 03:00"
date_time_before: "2026-03-08 TIME 02:00"
overlap: false
dst_end:
utc_time: "2026-11-01 TIME 09:00"
duration: "-1.00H"
gap: false
date_time_after: "2026-11-01 TIME 01:00"
date_time_before: "2026-11-01 TIME 02:00"
overlap: true
application/xml:
schema:
$ref: "#/components/schemas/IpGeolocationResponse"
examples:
paidFullResponse:
summary: Paid plan, all modules included (XML)
value: |
<LinkedHashMap>
<ip>91.128.103.196</ip>
<hostname>91.128.103.196</hostname>
<location>
<continent_code>EU</continent_code>
<continent_name>Europe</continent_name>
<country_code2>SE</country_code2>
<country_code3>SWE</country_code3>
<country_name>Sweden</country_name>
<country_name_official>Kingdom of Sweden</country_name_official>
<country_capital>Stockholm</country_capital>
<state_prov>Stockholms län</state_prov>
<state_code>SE-AB</state_code>
<district>Stockholm</district>
<city>Stockholm</city>
<locality>Stockholm</locality>
<accuracy_radius>8.793</accuracy_radius>
<confidence>high</confidence>
<dma_code></dma_code>
<zipcode>164 40</zipcode>
<latitude>59.40510</latitude>
<longitude>17.95510</longitude>
<is_eu>true</is_eu>
<country_flag>https://ipgeolocation.io/static/flags/se_64.png</country_flag>
<geoname_id>9972319</geoname_id>
<country_emoji>🇸🇪</country_emoji>
</location>
<country_metadata>
<calling_code>+46</calling_code>
<tld>.se</tld>
<languages>sv-SE</languages>
<languages>se</languages>
<languages>sma</languages>
<languages>fi-SE</languages>
</country_metadata>
<network>
<connection_type></connection_type>
<route>91.128.0.0/14</route>
<is_anycast>false</is_anycast>
</network>
<currency>
<code>SEK</code>
<name>Swedish Krona</name>
<symbol>kr</symbol>
</currency>
<asn>
<as_number>AS1257</as_number>
<organization>Tele2 Sverige AB</organization>
<country>SE</country>
<type>ISP</type>
<domain>tele2.com</domain>
<date_allocated>2002-09-19</date_allocated>
<rir>RIPE</rir>
</asn>
<company>
<name>Tele2 Sverige AB</name>
<type>ISP</type>
<domain>tele2.com</domain>
</company>
<security>
<threat_score>0</threat_score>
<is_tor>false</is_tor>
<is_proxy>false</is_proxy>
<proxy_confidence_score>0</proxy_confidence_score>
<proxy_last_seen></proxy_last_seen>
<is_residential_proxy>false</is_residential_proxy>
<is_vpn>false</is_vpn>
<vpn_confidence_score>0</vpn_confidence_score>
<vpn_last_seen></vpn_last_seen>
<is_relay>false</is_relay>
<relay_provider_name></relay_provider_name>
<is_anonymous>false</is_anonymous>
<is_known_attacker>false</is_known_attacker>
<is_bot>false</is_bot>
<is_spam>false</is_spam>
<is_cloud_provider>false</is_cloud_provider>
<cloud_provider_name></cloud_provider_name>
</security>
<abuse>
<route>91.128.0.0/14</route>
<country>SE</country>
<name>Swipnet Staff</name>
<organization></organization>
<kind>group</kind>
<address>Tele2 AB/Swedish IP Network, IP Registry, Torshamnsgatan 17 164 40 Kista SWEDEN</address>
<emails>[email protected]</emails>
<phone_numbers>+46 8 5626 42 10</phone_numbers>
</abuse>
<time_zone>
<name>Europe/Stockholm</name>
<offset>1</offset>
<offset_with_dst>1</offset_with_dst>
<current_time>2026-03-02 13:32:39.256+0100</current_time>
<current_time_unix>1772454759.256</current_time_unix>
<current_tz_abbreviation>CET</current_tz_abbreviation>
<current_tz_full_name>Central European Standard Time</current_tz_full_name>
<standard_tz_abbreviation>CET</standard_tz_abbreviation>
<standard_tz_full_name>Central European Standard Time</standard_tz_full_name>
<is_dst>false</is_dst>
<dst_savings>0</dst_savings>
<dst_exists>true</dst_exists>
<dst_tz_abbreviation>CEST</dst_tz_abbreviation>
<dst_tz_full_name>Central European Summer Time</dst_tz_full_name>
<dst_start>
<utc_time>2026-03-29 TIME 01:00</utc_time>
<duration>+1.00H</duration>
<gap>true</gap>
<date_time_after>2026-03-29 TIME 03:00</date_time_after>
<date_time_before>2026-03-29 TIME 02:00</date_time_before>
<overlap>false</overlap>
</dst_start>
<dst_end>
<utc_time>2026-10-25 TIME 01:00</utc_time>
<duration>-1.00H</duration>
<gap>false</gap>
<date_time_after>2026-10-25 TIME 02:00</date_time_after>
<date_time_before>2026-10-25 TIME 03:00</date_time_before>
<overlap>true</overlap>
</dst_end>
</time_zone>
<user_agent>
<user_agent_string>PostmanRuntime/7.49.1</user_agent_string>
<name>PostmanRuntime</name>
<type>Robot</type>
<version>7.49.1</version>
<version_major>7</version_major>
<device>
<name>Postman Runtime</name>
<type>Robot</type>
<brand>Postman</brand>
<cpu>Unknown</cpu>
</device>
<engine>
<name>PostmanRuntime</name>
<type>Robot</type>
<version>7.49.1</version>
<version_major>7</version_major>
</engine>
<operating_system>
<name>Cloud</name>
<type>Cloud</type>
<version>??</version>
<version_major>??</version_major>
<build>??</build>
</operating_system>
</user_agent>
</LinkedHashMap>
freeMinimalResponse:
summary: Free plan default response (XML)
value: |
<LinkedHashMap>
<ip>165.227.0.0</ip>
<location>
<continent_code>NA</continent_code>
<continent_name>North America</continent_name>
<country_code2>US</country_code2>
<country_code3>USA</country_code3>
<country_name>United States</country_name>
<country_name_official>United States of America</country_name_official>
<country_capital>Washington, D.C.</country_capital>
<state_prov>California</state_prov>
<state_code>US-CA</state_code>
<district>Santa Clara County</district>
<city>Santa Clara</city>
<zipcode>95051</zipcode>
<latitude>37.35983</latitude>
<longitude>-121.98144</longitude>
<is_eu>false</is_eu>
<country_flag>https://ipgeolocation.io/static/flags/us_64.png</country_flag>
<geoname_id>5346804</geoname_id>
<country_emoji>🇺🇸</country_emoji>
</location>
<country_metadata>
<calling_code>+1</calling_code>
<tld>.us</tld>
<languages>en-US</languages>
<languages>es-US</languages>
<languages>haw</languages>
<languages>fr</languages>
</country_metadata>
<currency>
<code>USD</code>
<name>US Dollar</name>
<symbol>$</symbol>
</currency>
<asn>
<as_number>AS14061</as_number>
<organization>DigitalOcean, LLC</organization>
<country>US</country>
</asn>
<time_zone>
<name>America/Los_Angeles</name>
<offset>-8</offset>
<offset_with_dst>-8</offset_with_dst>
<current_time>2026-03-02 03:29:55.186-0800</current_time>
<current_time_unix>1772450995.186</current_time_unix>
<current_tz_abbreviation>PST</current_tz_abbreviation>
<current_tz_full_name>Pacific Standard Time</current_tz_full_name>
<standard_tz_abbreviation>PST</standard_tz_abbreviation>
<standard_tz_full_name>Pacific Standard Time</standard_tz_full_name>
<is_dst>false</is_dst>
<dst_savings>0</dst_savings>
<dst_exists>true</dst_exists>
<dst_tz_abbreviation>PDT</dst_tz_abbreviation>
<dst_tz_full_name>Pacific Daylight Time</dst_tz_full_name>
<dst_start>
<utc_time>2026-03-08 TIME 10:00</utc_time>
<duration>+1.00H</duration>
<gap>true</gap>
<date_time_after>2026-03-08 TIME 03:00</date_time_after>
<date_time_before>2026-03-08 TIME 02:00</date_time_before>
<overlap>false</overlap>
</dst_start>
<dst_end>
<utc_time>2026-11-01 TIME 09:00</utc_time>
<duration>-1.00H</duration>
<gap>false</gap>
<date_time_after>2026-11-01 TIME 01:00</date_time_after>
<date_time_before>2026-11-01 TIME 02:00</date_time_before>
<overlap>true</overlap>
</dst_end>
</time_zone>
</LinkedHashMap>
"400":
$ref: "#/components/responses/BadRequest"
"401":
$ref: "#/components/responses/Unauthorized"
"404":
$ref: "#/components/responses/NotFound"
"405":
$ref: "#/components/responses/MethodNotAllowed"
"423":
$ref: "#/components/responses/Locked"
"429":
$ref: "#/components/responses/TooManyRequests"
"499":
$ref: "#/components/responses/ClientClosedRequest"
"500":
$ref: "#/components/responses/InternalServerError"
"502":
$ref: "#/components/responses/BadGateway"
"503":
$ref: "#/components/responses/ServiceUnavailable"
"504":
$ref: "#/components/responses/GatewayTimeout"
"505":
$ref: "#/components/responses/HttpVersionNotSupported"
x-microcks-operation:
delay: 0
dispatcher: FALLBACK
/v3/ipgeo-bulk:
post:
operationId: bulkLookupIpGeolocation
summary: IPGeolocation.io Bulk IP Geolocation Lookup
description: |
Returns geolocation and enrichment data for up to 50,000 IPv4 addresses, IPv6
addresses, or domain names in a single request. The request body must be a JSON
object with an `ips` array.
This endpoint requires a paid plan. Calling it with a free
plan API key returns HTTP 401.
The response is a JSON array with one element per IP in the request. Each element
is either a full geolocation response object or an error object with only a
`message` field. Invalid, bogon, and unresolvable entries appear as error
objects. Invalid, private, and bogon IPs are not billed.
This endpoint supports the same query parameters as the single lookup endpoint,
including `lang`, `include`, `fields`, `excludes`, and `output`.
Credits are calculated as: credits per lookup multiplied by the number of valid
IPs in the request. The total is returned in the `X-Credits-Charged` response
header. When at least one submitted ip is invalid, the `X-Successful-Record`
response header indicates how many entries were successfully resolved.
Only the `POST` method is accepted. Sending a `GET` request returns HTTP 405.
tags:
- IP Geolocation
parameters:
- $ref: "#/components/parameters/Lang"
- $ref: "#/components/parameters/Include"
- $ref: "#/components/parameters/Fields"
- $ref: "#/components/parameters/Excludes"
- $ref: "#/components/parameters/Output"
requestBody:
required: true
description: |
A JSON object containing an `ips` array. Each element is a string representing
an IPv4 address, IPv6 address, or domain name. The array must not be empty and
must not contain more than 50,000 entries.
content:
application/json:
schema:
$ref: "#/components/schemas/BulkGeolocationRequest"
examples:
mixedIps:
summary: Mixed IPv4, IPv6, and domain
value:
ips:
- "8.8.8.8"
- "91.128.103.196"
- "2607:fb91:16c6:8860:e531:2d1d:4944:6c7c"
- "ipgeolocation.io"
ipv4Only:
summary: Multiple IPv4 addresses
value:
ips:
- "1.1.1.1"
- "8.8.4.4"
- "165.227.0.0"
responses:
"200":
description: |
An array of results, one per input entry. Valid entries return full
geolocation objects. Invalid, bogon, and unresolvable entries return
objects with only a `message` field.
`X-Successful-Record` is returned only when at least one submitted entry
fails and the number of successful lookups is lower than the number of
submitted entries.
headers:
X-Credit
# --- truncated at 32 KB (92 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/ipgeolocation/refs/heads/main/openapi/ipgeolocation-ip-location-openapi.yml