The whole contract, on one page.
If you are an autonomous client, this page is for you. What we sell is a file, not an answer: there is no lookup endpoint to call per address. Below is every call that exists, the shape each one returns, and the five refusals you have to tell apart. Nothing here needs another page to be actionable.
The same facts are at /llms.txt as plain text, and the full reference is at docs.internetdata.io/api.
Five calls, no lookups
Access is granted by contract, one database family at a time, to a key carrying the db.download scope. Keys are default-deny: an existing key gains nothing until the scope is added to it. The same key presents three ways — a bearer token, X-Api-Key, or ?apikey= for a browser or a one-liner.
# a 302 to object storage is the success casecurl -L -H "Authorization: Bearer $KEY" \"https://internetdata.io/api/v2/database/download?id=vpn_ip_v1&format=csvgz" \-o vpn_ip_v1.csv.gz# and verify what landedcurl -s -H "X-Api-Key: $KEY" \"https://internetdata.io/api/v2/database/checksum?id=vpn_ip_v1&format=csvgz"
https://internetdata.ioBearer · X-Api-Key · ?apikey=db.downloadGET /api/v2/database/listGET /api/v2/database/metadata?id=GET /api/v2/database/download?id=&format=GET /api/v2/database/checksum?id=&format=GET /api/v2/database/downloads?limit=csvgz · mmdb400 · 401 · 403 · 404 · 503, each with an rcWhat comes back
Poll metadata to decide whether today's build is worth fetching: it carries the build date, the row count and the size of each format without moving any bytes.
GET /api/v2/database/metadata?id=vpn_ip_v1{"id": "vpn_ip_v1","update_freq": "daily","updated": "2026-09-21","entries": 17328905,"size": { "csvgz": 119755873,"mmdb": 575833040 },"schema": {"csvgz": [{ "name": "start_ip", "type": "ipaddress" },…]}}
idupdate_frequpdatedentriessizeschemasampleSeven things that will bite you otherwise
Each of these is a place where the obvious reading of the API is the wrong one.
Download answers a redirect to a time-limited link on object storage; the bytes never come through the API. Follow it (curl -L). The link authorizes the START of a transfer, so one already running is not interrupted when it lapses.
A key does not gain database access until db.download is added to it. Missing key, wrong key, missing scope and a key belonging to no organization all answer 401 with rc UNAUTHORIZED.
rc NOT_LICENSED means your organization never bought this family; LICENSE_EXPIRED means the term ended. Neither is retryable — it needs a contract, not a backoff.
rc NOT_AVAILABLE means the current build has not been published yet. Retry later; do not treat it as an error, and do not substitute a different database for it.
csvgz for every database, mmdb for most. The provider catalogs are keyed by provider id, so there is nothing for an mmdb to index, and asking one for it is a 400 INVALID_FORMAT — a deliberate refusal, not a gap in coverage. list names the formats each version is built in.
list returns a family (base, e.g. vpn_ip) with your standing, and the id to pass onward to metadata and download. Read that id from list rather than composing it yourself.
No lookup API exists, by design — nothing here answers "is 45.83.91.1 a VPN". You license the database and answer that question inside your own infrastructure.
What a license lets you do
Every database is available under either grant, and the list endpoint reports which one you hold against each family. Full detail is on the licensing page.
evaluationstandardredistributenullWhen you need more than one database
Do not crawl this site for what the catalog already answers in one call.
One call to /api/v2/database/list returns every published family with its versions, its formats and your standing beside it. That is the machine-readable form of the published catalog.
Poll metadata once a day per family and fetch only when updated moves. Your own attempt history, refusals included, is at /api/v2/database/downloads — a denial is what answers "it stopped working", and its absence answers nothing.
Test the real build first.
An evaluation license puts a full current build in your hands — every row, every column, no sampling — so you can measure it against your own traffic before anyone talks about terms.