Skip to content
InternetData

Authentication

How to authenticate with the InternetData HTTP API.

The API takes two kinds of credential. An API key is for your own code: scripts, CI, a server that fetches a database every night. An OAuth token is for a program acting for a person, like the CLI signing in through your browser. Both work as a bearer token, and both are held to the same scopes. The legacy v1 endpoints take a key of their own, below.

API keys

Create a key in the console and give it the Download databases permission, which is the db.download scope. The database API takes it any of three ways, whichever suits your client:

bash
curl -H "Authorization: Bearer $KEY" https://internetdata.io/api/v2/database/list
curl -H "X-Api-Key: $KEY"            https://internetdata.io/api/v2/database/list
curl "https://internetdata.io/api/v2/database/list?apikey=$KEY"

They're the same key. The query parameter exists for curl and the browser, which is how a database is usually fetched; prefer a header where setting one is easy. The account endpoints (Account, Organization, API keys) take Authorization: Bearer only.

A key is refused anything its scopes don't name. It starts with none, and one with none can authenticate and nothing else.

OAuth tokens

A program that works for a person gets its token from our authorization server instead of asking them to paste a key. Two flows are supported:

  • Device authorization, for a command line or anything without a browser of its own: start one, show the person the user_code and verification_uri, and poll for the token while they approve it in the console.
  • Authorization code with PKCE, for anything that can open a browser and receive a redirect: send the person to authorize with an S256 code_challenge, then exchange the code. plain is refused.

Either way the person signs in, approves the scopes the program asked for, and can pick one of their organization's API keys. The token response then carries that key as mslm:apikey, so a device ends up holding an ordinary key for downloads. Send the access token itself as Authorization: Bearer $TOKEN.

The access token expires after expires_in seconds. Refresh it with the refresh_token grant, which consumes the refresh token you present and returns a new one, so store the new one before you use it. Revoking the refresh token ends the whole authorization, access tokens included; revoking an access token ends only that token.

Client IDs are issued on request: write to support@internetdata.io. Everything else, endpoints included, is in the discovery document at https://internetdata.io/.well-known/oauth-authorization-server.

Scopes

ScopeLets a credentialUsed by
db.downloadList, inspect and download the databases your organization is licensed for, and the Open onesDatabase v2
account.readRead who the credential belongs toIdentity
org.readRead your organization and its membersOrganization, Members
apikeys.readList your organization's API keys, without their secretsList
apikeys.manageCreate, rotate and revoke API keysCreate, Rotate, Revoke
apikeys.revealRead back the secret of an existing keyReveal, and the key a device picks when it signs in

db.download is the one permission an API key can be given. The other five are OAuth scopes: a person grants them when they approve a program, and they're narrowed on every request to what that person's role in the organization still allows. A member who loses a role loses it on their live tokens too. Identity returns what a credential may do right now.

Errors

The database API answers a missing or invalid key with 401:

json
{
  "rc": "UNAUTHORIZED"
}

A key that's valid but doesn't license the dataset you asked for answers 403 with NOT_LICENSED, and one whose term has ended answers 403 with LICENSE_EXPIRED. The difference matters: the first means buy it, the second means renew it. Every organization holds a standard license to each Open database from the start, so its key downloads them unless that license has ended.

A key used from an address outside its own allowed addresses, or its organization's, answers 403 with IP_NOT_ALLOWED on every database route. The key itself is fine: change the allowlist, or call from an address it allows, rather than rotating the key.

The account endpoints answer 401 with NO_CREDENTIAL or INVALID_CREDENTIAL, and 403 with FORBIDDEN when the credential lacks the scope. Which scope is missing is deliberately not named.

v1 (legacy)

The v1 database endpoints are still served for existing integrations. They take a UUID key in the apikey query parameter, in either format:

  • with dashes - b8e25dda-5f6a-471e-87eb-d8ab866ea90e
  • without - b8e25dda5f6a471e87ebd8ab866ea90e

A missing or invalid key answers 401:

json
{
  "rc": "INVALID_APIKEY"
}

v1 keys aren't accepted on v2 and v2 keys aren't accepted on v1: they're separate vocabularies. New integrations should use v2, which adds the catalog listing, download history, and time-limited download links served straight from object storage.