{
  "openapi": "3.0.3",
  "info": {
    "title": "InternetData API",
    "description": "The InternetData API: download the databases your organization is licensed\nfor, and manage the account behind them.\n\nSee https://docs.internetdata.io for guides and https://github.com/internetdata\nfor the official client libraries.\n",
    "contact": {
      "name": "InternetData Support",
      "email": "support@internetdata.io",
      "url": "https://internetdata.io"
    },
    "termsOfService": "https://internetdata.io/terms",
    "version": "2026.10.15"
  },
  "servers": [
    {
      "url": "https://internetdata.io"
    }
  ],
  "tags": [
    {
      "name": "Database",
      "description": "Download IP database files and fetch their checksums.",
      "x-displayName": "Database"
    },
    {
      "name": "Database v2",
      "description": "The current database API. Authenticate with an API key carrying the\n`db.download` scope, presented any of three ways: `Authorization: Bearer\n<key>`, `X-Api-Key: <key>`, or `?apikey=<key>`. They are the same key;\nthe query parameter is there for curl and the browser, which is how a\ndatabase is usually fetched.\n\nAccess is granted by CONTRACT, one dataset family at a time: there is no\nself-service purchase and no subscription behind it. The Open databases\nare licensed to every organization from the start, a `standard` license\nto each, and are free under CC BY-SA 4.0 besides. `list` marks them\n`open`.\n\nA successful download answers `302` with a time-limited URL pointing\nstraight at object storage. Follow the redirect (`curl -L`); the link\nauthorizes the START of a transfer, so a download already running is not\ninterrupted when it lapses.\n",
      "x-displayName": "Database v2"
    },
    {
      "name": "Account",
      "description": "Who the credential belongs to, and what it may do.",
      "x-displayName": "Account"
    },
    {
      "name": "Organization",
      "description": "The organization it is scoped to.",
      "x-displayName": "Organization"
    },
    {
      "name": "API keys",
      "description": "Creating, listing and rotating credentials.",
      "x-displayName": "API keys"
    },
    {
      "name": "Authorization",
      "description": "Obtaining and revoking tokens.",
      "x-displayName": "Authorization"
    }
  ],
  "paths": {
    "/api/v2/database/list": {
      "get": {
        "tags": [
          "Database v2"
        ],
        "operationId": "listDatabases",
        "summary": "List",
        "description": "The whole published catalog, with your organization's license beside\neach entry, so `standing` says whether a database is yours today\n(`licensed`), was (`expired`), or has never been bought (`unlicensed`).\n",
        "security": [
          {
            "ApiKeyQueryAuth": []
          },
          {
            "ApiKeyHeaderAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "databases"
                  ],
                  "properties": {
                    "databases": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Database"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/V2Unauthorized"
          }
        }
      }
    },
    "/api/v2/database/download": {
      "get": {
        "tags": [
          "Database v2"
        ],
        "operationId": "downloadDatabaseV2",
        "summary": "Download",
        "description": "Answers `302`; the bytes come straight from object storage rather than\nthrough this API. Follow the redirect.\n",
        "security": [
          {
            "ApiKeyQueryAuth": []
          },
          {
            "ApiKeyHeaderAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          },
          {
            "$ref": "#/components/parameters/DbFormat"
          }
        ],
        "responses": {
          "302": {
            "description": "Follow the Location header to object storage.",
            "headers": {
              "Location": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "The database is not built in the requested format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/V2Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/V2NotLicensed"
          },
          "404": {
            "$ref": "#/components/responses/V2UnknownDatabase"
          },
          "503": {
            "$ref": "#/components/responses/V2NotAvailable"
          }
        }
      }
    },
    "/api/v2/database/metadata": {
      "get": {
        "tags": [
          "Database v2"
        ],
        "operationId": "databaseMetadataV2",
        "summary": "Metadata",
        "description": "Poll this to decide whether today's build is worth fetching: it carries\n`updated` and `entries` without downloading anything.\n\nNo `format` parameter - one document describes every format the database\nis built in. Needs no license: it answers for every database `list`\nreturns, whatever its `standing`.\n",
        "security": [
          {
            "ApiKeyQueryAuth": []
          },
          {
            "ApiKeyHeaderAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DatabaseMetadata"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/V2Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/V2UnknownDatabase"
          },
          "503": {
            "$ref": "#/components/responses/V2NotAvailable"
          }
        }
      }
    },
    "/api/v2/database/checksum": {
      "get": {
        "tags": [
          "Database v2"
        ],
        "operationId": "databaseChecksumV2",
        "summary": "Checksums",
        "description": "Checksums for one published file, so a download can be verified after it lands.\n",
        "security": [
          {
            "ApiKeyQueryAuth": []
          },
          {
            "ApiKeyHeaderAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          },
          {
            "$ref": "#/components/parameters/DbFormat"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "id",
                    "format",
                    "checksums"
                  ],
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "format": {
                      "$ref": "#/components/schemas/DatabaseFormat"
                    },
                    "checksums": {
                      "$ref": "#/components/schemas/DbChecksums"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The database is not built in the requested format.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/V2Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/V2NotLicensed"
          },
          "404": {
            "$ref": "#/components/responses/V2UnknownDatabase"
          },
          "503": {
            "$ref": "#/components/responses/V2NotAvailable"
          }
        }
      }
    },
    "/api/v2/database/downloads": {
      "get": {
        "tags": [
          "Database v2"
        ],
        "operationId": "listDownloads",
        "summary": "History",
        "description": "Refusals are listed too: a denial is what answers \"it stopped working\",\nand its absence answers nothing.\n",
        "security": [
          {
            "ApiKeyQueryAuth": []
          },
          {
            "ApiKeyHeaderAuth": []
          },
          {
            "BearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "How many attempts to return. Clamped to 200.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 50
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "downloads"
                  ],
                  "properties": {
                    "downloads": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Download"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/V2Unauthorized"
          }
        }
      }
    },
    "/api/v1/database/download": {
      "get": {
        "tags": [
          "Database"
        ],
        "operationId": "databaseDownload",
        "summary": "Download",
        "description": "Returns the requested database file as a binary download.\nThe response's `Content-Type` depends on `format`:\n`application/gzip` for `csvgz`, `application/octet-stream` for `mmdb`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          },
          {
            "$ref": "#/components/parameters/DbFormat"
          }
        ],
        "responses": {
          "200": {
            "description": "Database file.",
            "headers": {
              "Content-Disposition": {
                "description": "Attachment with the database filename.",
                "schema": {
                  "type": "string"
                }
              }
            },
            "content": {
              "application/gzip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              },
              "application/octet-stream": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/v1/database/checksum": {
      "get": {
        "tags": [
          "Database"
        ],
        "operationId": "databaseChecksum",
        "summary": "Checksums",
        "description": "Returns MD5, SHA-1, SHA-256, and SHA-512 checksums for the currently\npublished version of the requested database.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          },
          {
            "$ref": "#/components/parameters/DbFormat"
          }
        ],
        "responses": {
          "200": {
            "description": "Checksums for the requested database.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DbChecksumSuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/v1/database/metadata": {
      "get": {
        "tags": [
          "Database"
        ],
        "operationId": "databaseMetadata",
        "summary": "Metadata",
        "description": "Returns publish freshness information for the currently published version\nof the requested database: when it was last updated, how many entries\nthe dataset contains, and the size of each output format in bytes.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/DbId"
          }
        ],
        "responses": {
          "200": {
            "description": "Metadata for the requested database.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DbMetadataSuccessResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "security": [
          {
            "ApiKeyAuth": []
          }
        ]
      }
    },
    "/api/v1/iam/identity": {
      "get": {
        "operationId": "accountIdentity",
        "tags": [
          "Account"
        ],
        "summary": "Identity",
        "description": "The identity behind this credential: what it is, the organization it is\nscoped to, and the scopes it currently holds.\n\n`user` is present for an OAuth token and ABSENT for an API key, which\nhas an organization but no person behind it. `credential.kind` says\nwhich you are holding, so a client can branch without guessing from a\nmissing field.\n\nNarrower than what the console shows its own user on purpose: an\nintegration needs a name to display and an organization to address, not\na profile. The `scopes` array is what the credential may do RIGHT NOW,\nso a client can render its own capabilities rather than discovering\nthem from a 403.\n",
        "security": [
          {
            "BearerAuth": [
              "account.read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The caller.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Identity"
                },
                "examples": {
                  "ok": {
                    "summary": "A token granted read access",
                    "value": {
                      "rc": "SUCCESS",
                      "user": {
                        "id": "3d86d1ef-f70b-4063-a3b8-f69605a8fc57",
                        "fullname": "Ada Lovelace",
                        "email": "ada@example.com"
                      },
                      "org": {
                        "id": "7b309476-0e70-4225-9a46-5e25650094dd"
                      },
                      "scopes": [
                        "account.read",
                        "apikeys.read"
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          }
        }
      }
    },
    "/api/v1/iam/org": {
      "get": {
        "operationId": "accountOrg",
        "tags": [
          "Organization"
        ],
        "summary": "Organization",
        "description": "The organization this credential is scoped to.\n\nThere is no way to name a different one. A credential describes exactly\none organization, so an identifier in the path could only ever be your\nown or a refusal.\n",
        "security": [
          {
            "BearerAuth": [
              "org.read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The organization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountOrgWrap"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          }
        }
      }
    },
    "/api/v1/iam/org/members": {
      "get": {
        "operationId": "accountOrgMembers",
        "tags": [
          "Organization"
        ],
        "summary": "Members",
        "description": "Read-only. Adding or removing a member is an invitation flow with email\nin the middle rather than a POST, and modeling it as one here would\npromise something this API does not do.\n",
        "security": [
          {
            "BearerAuth": [
              "org.read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The members.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRc"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          }
        }
      }
    },
    "/api/v1/iam/apikeys": {
      "get": {
        "operationId": "accountListApikeys",
        "tags": [
          "API keys"
        ],
        "summary": "List",
        "description": "Metadata only. A key's secret is never in a list - not here and not in\nthe console - because a list is the response that ends up in logs,\ncaches and support tickets.\n\n`retrievable` says whether the secret could still be read back at all.\nA key issued before this product stored secrets recoverably was never\nkept, so `reveal` will refuse it permanently; rotating produces one\nthat can be read.\n",
        "security": [
          {
            "BearerAuth": [
              "apikeys.read"
            ]
          }
        ],
        "responses": {
          "200": {
            "description": "The organization's keys, newest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApikeyList"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          }
        }
      },
      "post": {
        "operationId": "accountCreateApikey",
        "tags": [
          "API keys"
        ],
        "summary": "Create",
        "description": "Creates a key and returns its secret.\n\nThis is the ONLY response that ever carries the secret, and only\nbecause this is the moment it comes into existence. Store it now.\n",
        "security": [
          {
            "BearerAuth": [
              "apikeys.manage"
            ]
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountCreateApikeyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The new key, including its secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountCreatedApikey"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/AccountInvalid"
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          }
        }
      }
    },
    "/api/v1/iam/apikeys/{id}/rotate": {
      "post": {
        "operationId": "accountRotateApikey",
        "tags": [
          "API keys"
        ],
        "summary": "Rotate",
        "description": "Replaces the secret behind a key, keeping its id, name and settings.\nThe previous secret stops working immediately. The new secret comes\nback in the answer, so this needs `apikeys.reveal` as well as\n`apikeys.manage`.\n",
        "security": [
          {
            "BearerAuth": [
              "apikeys.manage",
              "apikeys.reveal"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApikeyIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "The key, with its new secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountCreatedApikey"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        }
      }
    },
    "/api/v1/iam/apikeys/{id}/revoke": {
      "post": {
        "operationId": "accountRevokeApikey",
        "tags": [
          "API keys"
        ],
        "summary": "Revoke",
        "description": "Stops the key working. Revocation is soft: the key stays listed with a\n`revoked_at`, because the organization still owns whatever it did while\nit was alive.\n",
        "security": [
          {
            "BearerAuth": [
              "apikeys.manage"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApikeyIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRc"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          },
          "404": {
            "$ref": "#/components/responses/AccountNotFound"
          }
        }
      }
    },
    "/api/v1/iam/apikeys/{id}/reveal": {
      "post": {
        "operationId": "accountRevealApikey",
        "tags": [
          "API keys"
        ],
        "summary": "Reveal",
        "description": "Returns an existing key's secret.\n\nIts own scope rather than part of `apikeys.manage`, because the two are\ndifferent acts: rotating replaces a secret you never see, while this\nhands one over.\n\nRefused with `NOT_RETRIEVABLE` for a key issued before this product\nstored secrets recoverably - that secret was never kept, so no retry\nwill ever produce it. Rotate the key instead.\n",
        "security": [
          {
            "BearerAuth": [
              "apikeys.reveal"
            ]
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/ApikeyIdParam"
          }
        ],
        "responses": {
          "200": {
            "description": "The key's secret.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRevealedApikey"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AccountUnauthorized"
          },
          "403": {
            "$ref": "#/components/responses/AccountForbidden"
          },
          "404": {
            "description": "No such key in this organization, or its secret was never stored\nrecoverably (`NOT_RETRIEVABLE`).\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountRc"
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/oauth-authorization-server": {
      "get": {
        "operationId": "oauthMetadata",
        "tags": [
          "Authorization"
        ],
        "summary": "Discovery",
        "description": "RFC 8414 authorization server metadata: the endpoints, the grant types\nand the scopes this server supports.\n\nRead this rather than hardcoding endpoints. It is also served at\n`/.well-known/openid-configuration`, identically, because several\nclients probe that path first.\n",
        "security": [],
        "responses": {
          "200": {
            "description": "The server's metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OauthMetadata"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/device_authorization": {
      "post": {
        "operationId": "oauthDeviceAuthorization",
        "tags": [
          "Authorization"
        ],
        "summary": "Device authorization",
        "description": "Starts the device flow. Show the `user_code` to the person and send them\nto `verification_uri`; `verification_uri_complete` has the code already\nembedded, which is what to open if you can open a browser at all.\n\nThen poll `/oauth/token`, no faster than `interval` seconds.\n",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/DeviceAuthorizationRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "A pending device authorization.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeviceAuthorization"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_request`, `unauthorized_client` when the client may not use\nthe device flow, or `slow_down` when this address has started too\nmany authorizations.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OauthError"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_client`: the `client_id` is not registered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OauthError"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/authorize": {
      "get": {
        "operationId": "oauthAuthorize",
        "tags": [
          "Authorization"
        ],
        "summary": "Authorize",
        "description": "The browser entry point for the authorization-code flow. This is a\nredirect target, not something to call from code.\n\nAny client may sign in without registering first by using a Client ID\nMetadata Document: make `client_id` an https URL that serves your\nclient's metadata as JSON, naming that same URL as its `client_id`,\nwith `token_endpoint_auth_method` `none` and your `redirect_uris`. An\nhttps redirect URI must be on the same origin as the `client_id`; a\nloopback one (`http://127.0.0.1`, `http://[::1]`, `http://localhost`)\nmatches on any port. Such a client is granted `apikeys.use` at most.\n\nAn unknown `client_id` or an unregistered `redirect_uri` is shown to the\nUSER and never redirected, because sending an error to an address we\nhave not verified belongs to you is how an open redirector works.\nEverything else comes back to your `redirect_uri` with `error`, your\n`state`, and `iss`.\n",
        "security": [],
        "parameters": [
          {
            "name": "client_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "redirect_uri",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "response_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "code"
              ]
            }
          },
          {
            "name": "code_challenge",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "code_challenge_method",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "S256"
              ]
            },
            "description": "S256, named explicitly. `plain`, or no method at all, is refused rather than downgraded."
          },
          {
            "name": "scope",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "state",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Returned unchanged. Use it to bind the response to your request."
          },
          {
            "name": "resource",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "RFC 8707. What the token is FOR, so it cannot be replayed elsewhere:\nthis brand's MCP server, the only resource it issues tokens for.\nAnything else answers `invalid_target`. A client that names none is\ngiven that server.\n"
          }
        ],
        "responses": {
          "302": {
            "description": "A redirect to the consent screen, or back to your redirect_uri with an error."
          },
          "400": {
            "description": "Shown to the user. An unverified redirect target is never sent an error."
          },
          "429": {
            "description": "Shown to the user. Too many authorizations from one address."
          }
        }
      }
    },
    "/oauth/token": {
      "post": {
        "operationId": "oauthToken",
        "tags": [
          "Authorization"
        ],
        "summary": "Token",
        "description": "Three grant types.\n\n`urn:ietf:params:oauth:grant-type:device_code` polls a device\nauthorization. Until the person approves it answers\n`authorization_pending`; poll faster than `interval` and it answers\n`slow_down`, which means widen your interval and keep it widened.\n\n`authorization_code` exchanges a code from `/oauth/authorize`, with the\n`code_verifier` matching the challenge you sent and the same\n`redirect_uri`. A code works once: presenting it again also revokes\nwhat the first exchange issued.\n\n`refresh_token` exchanges a refresh token. The presented token is\nconsumed whatever happens next, so store the new one before using it.\nPresenting a consumed refresh token again ends the whole authorization,\nsince it means the token was copied.\n",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Tokens.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "400": {
            "description": "An RFC 6749 error. `authorization_pending` and `slow_down` are\nnormal answers while polling a device authorization, not failures.\n`access_denied` means the person refused, and `expired_token` that\nthe device code is no longer valid: it expired, or it was already\nexchanged or refused. `invalid_grant` means the code, device code or\nrefresh token is not valid for this `client_id`. `invalid_target`\nmeans `resource` names something other than what was authorized.\n`slow_down` also answers any grant when this address sends too many\nrequests.\n",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OauthError"
                }
              }
            }
          },
          "401": {
            "description": "`invalid_client`: the `client_id` is not registered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OauthError"
                }
              }
            }
          }
        }
      }
    },
    "/oauth/revoke": {
      "post": {
        "operationId": "oauthRevoke",
        "tags": [
          "Authorization"
        ],
        "summary": "Revoke",
        "description": "RFC 7009. Always answers 200, including for a token that was never\nvalid - an endpoint that distinguished the two would be a way to test\nwhether a stolen string is a live credential.\n\nRevoking a REFRESH token ends the whole authorization and takes its\naccess tokens with it. Revoking an access token affects only that token.\n",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/x-www-form-urlencoded": {
              "schema": {
                "$ref": "#/components/schemas/RevokeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Always, whatever was presented.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "query",
        "name": "apikey",
        "description": "UUID-format API key issued to the customer. Each key is authorized for a\nspecific set of database ids; requesting any other id returns 403.\n\nv1 only. The v2 endpoints take a console-issued key as a bearer token.\n"
      },
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "`Authorization: Bearer <key>`, with a key from the console. Keys are\ndefault-deny: each operation names the scope it needs, and an existing\nkey does not gain an operation until that scope is added to it.\n"
      },
      "ApiKeyHeaderAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "`X-Api-Key: <key>`. The same v2 key, for clients that do not set a bearer."
      },
      "ApiKeyQueryAuth": {
        "type": "apiKey",
        "in": "query",
        "name": "apikey",
        "description": "`?apikey=<key>`. Convenient in a browser or a curl one-liner, which is\nhow a database is usually fetched; prefer a header elsewhere.\n\nThis is the same v2 key as the other two schemes. A v1 credential is a\ndifferent vocabulary and fails validation here, as it would anywhere.\n"
      }
    },
    "parameters": {
      "DbId": {
        "name": "id",
        "in": "query",
        "required": true,
        "description": "Database identifier (e.g. `vpn_ip_v1`, `resproxy_provider_v1`).",
        "schema": {
          "type": "string",
          "pattern": "^[a-zA-Z0-9_]+$",
          "example": "vpn_ip_v1"
        }
      },
      "DbFormat": {
        "name": "format",
        "in": "query",
        "required": true,
        "description": "Database file format.",
        "schema": {
          "$ref": "#/components/schemas/DatabaseFormat"
        }
      },
      "ApikeyIdParam": {
        "name": "id",
        "in": "path",
        "required": true,
        "description": "The key's id, as returned by the list endpoint. Never the key itself.",
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "description": "A machine-readable result code. Deliberately not an enum: a code\nadded later must stay parseable by a client generated today.\n"
          }
        }
      },
      "DatabaseFormat": {
        "type": "string",
        "description": "A file format a database version is published in.",
        "enum": [
          "csvgz",
          "mmdb"
        ],
        "example": "mmdb"
      },
      "Standing": {
        "type": "string",
        "description": "Where your license for a database family stands today. `licensed` is a\nlive grant, `expired` one whose term has ended, and `unlicensed` a\ndatabase published but never bought.\n",
        "enum": [
          "licensed",
          "expired",
          "unlicensed"
        ]
      },
      "Database": {
        "type": "object",
        "description": "One database FAMILY, with your organization's license beside it. A\nlicense covers the family, while a download names a specific version,\nso the ids passed to `download` and `checksum` come from `versions`.\n",
        "required": [
          "base",
          "name",
          "summary",
          "standing",
          "open",
          "license_type",
          "starts",
          "expires",
          "renews_at",
          "notice_due_at",
          "versions"
        ],
        "properties": {
          "base": {
            "type": "string",
            "description": "The family, e.g. `vpn_ip`. What a license is held against.",
            "example": "vpn_ip"
          },
          "name": {
            "type": "string",
            "example": "VPN IP"
          },
          "summary": {
            "type": "string",
            "description": "One line on what the newest version contains."
          },
          "standing": {
            "$ref": "#/components/schemas/Standing"
          },
          "open": {
            "type": "boolean",
            "description": "An Open database: free under CC BY-SA 4.0 (credit InternetData,\nhttps://internetdata.io, and share what you build from it under\nthe same license). Every organization holds a `standard` license\nto it from the start, which `standing` and `license_type` report\nlike any other.\n"
          },
          "license_type": {
            "type": "string",
            "nullable": true,
            "enum": [
              "evaluation",
              "standard",
              "redistribute",
              null
            ],
            "description": "What your license permits you to do with the data. Null when there\nis no license, which is every family with standing `unlicensed`.\n"
          },
          "starts": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "expires": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "A hard stop. Null when the license has no end date, which is the normal case for a rolling agreement, and when there is no license. A rolling license reports its turnover date in renews_at instead."
          },
          "renews_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When a rolling license next renews. Null when the license has no defined term, when expires sets a hard stop instead, and when there is no license."
          },
          "notice_due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "The last day notice of non-renewal can be given for the term ending at renews_at. Null whenever renews_at is, and when the agreement records no notice period."
          },
          "versions": {
            "type": "array",
            "description": "Every published version of this family, oldest first. Old versions\nare frozen rather than migrated, so both stay downloadable.\n",
            "items": {
              "$ref": "#/components/schemas/DatabaseVersion"
            }
          }
        }
      },
      "DatabaseVersion": {
        "type": "object",
        "required": [
          "id",
          "version",
          "summary",
          "formats"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "The versioned id. Pass this to `download`, `checksum` and `metadata`.",
            "example": "vpn_ip_v1"
          },
          "version": {
            "type": "integer",
            "example": 1
          },
          "summary": {
            "type": "string"
          },
          "formats": {
            "type": "array",
            "description": "The formats this version is BUILT in. Asking for another is a 400,\nnot a gap - the `_provider` catalogs are keyed by provider id, so no\nMMDB exists for them.\n",
            "items": {
              "$ref": "#/components/schemas/DatabaseFormat"
            }
          },
          "sample_formats": {
            "type": "array",
            "description": "The formats an evaluation sample is published in, if any.",
            "items": {
              "$ref": "#/components/schemas/DatabaseFormat"
            }
          }
        }
      },
      "Download": {
        "type": "object",
        "description": "One download ATTEMPT, refusals included.",
        "required": [
          "dataset_id",
          "format",
          "outcome",
          "sample",
          "open",
          "bytes",
          "http_status",
          "apikey_id",
          "client_ip",
          "user_agent",
          "created"
        ],
        "properties": {
          "dataset_id": {
            "type": "string"
          },
          "format": {
            "type": "string"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "ok",
              "unauthorized",
              "denied",
              "expired",
              "unknown",
              "unavailable"
            ]
          },
          "sample": {
            "type": "boolean",
            "description": "The evaluation sample rather than the database itself."
          },
          "open": {
            "type": "boolean",
            "description": "A download of an Open database.\n"
          },
          "bytes": {
            "type": "integer",
            "format": "int64",
            "nullable": true,
            "description": "Object size at redirect time, NOT bytes delivered: the transfer is a\npresigned redirect straight to object storage, so we never observe\nhow much of it was taken.\n"
          },
          "http_status": {
            "type": "integer",
            "nullable": true
          },
          "apikey_id": {
            "type": "string",
            "nullable": true,
            "description": "The key that made the request. Null when it could not be resolved."
          },
          "client_ip": {
            "type": "string",
            "nullable": true
          },
          "user_agent": {
            "type": "string",
            "nullable": true
          },
          "created": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "DatabaseMetadataColumn": {
        "type": "object",
        "required": [
          "name",
          "type"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "type": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "DatabaseMetadata": {
        "type": "object",
        "description": "The build document written by the exporter, served through unchanged.",
        "required": [
          "id",
          "updated",
          "entries",
          "schema",
          "size"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "update_freq": {
            "type": "string",
            "description": "How often a new build is published."
          },
          "updated": {
            "type": "string",
            "format": "date",
            "description": "ISO-8601 date (YYYY-MM-DD) the published build was generated on.",
            "example": "2026-09-04"
          },
          "entries": {
            "type": "integer",
            "format": "int64",
            "description": "Row count in the current build."
          },
          "schema": {
            "type": "object",
            "description": "Columns, keyed by format.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/DatabaseMetadataColumn"
              }
            }
          },
          "sample": {
            "type": "object",
            "description": "A few real rows, keyed by format.",
            "additionalProperties": {
              "type": "array",
              "items": {
                "type": "object"
              }
            }
          },
          "size": {
            "type": "object",
            "description": "Bytes per format.",
            "additionalProperties": {
              "type": "integer",
              "format": "int64"
            }
          },
          "sample_size": {
            "type": "object",
            "description": "Bytes per format of the evaluation sample, where one is published.",
            "additionalProperties": {
              "type": "integer",
              "format": "int64"
            }
          },
          "sample_entries": {
            "type": "integer",
            "description": "Row count in the evaluation sample."
          }
        }
      },
      "DbChecksumSuccessResponse": {
        "type": "object",
        "required": [
          "rc",
          "data"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "SUCCESS"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/DbChecksums"
          }
        }
      },
      "DbChecksums": {
        "type": "object",
        "required": [
          "md5",
          "sha1",
          "sha256",
          "sha512"
        ],
        "properties": {
          "md5": {
            "type": "string",
            "description": "Hex-encoded MD5 digest."
          },
          "sha1": {
            "type": "string",
            "description": "Hex-encoded SHA-1 digest."
          },
          "sha256": {
            "type": "string",
            "description": "Hex-encoded SHA-256 digest."
          },
          "sha512": {
            "type": "string",
            "description": "Hex-encoded SHA-512 digest."
          }
        }
      },
      "DbMetadataSuccessResponse": {
        "type": "object",
        "required": [
          "rc",
          "data"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "SUCCESS"
            ]
          },
          "data": {
            "$ref": "#/components/schemas/DbMetadata"
          }
        }
      },
      "DbMetadata": {
        "type": "object",
        "required": [
          "updated",
          "entries",
          "size"
        ],
        "properties": {
          "updated": {
            "type": "string",
            "format": "date",
            "description": "ISO-8601 calendar date (YYYY-MM-DD) on which the currently published version was generated.",
            "example": "2026-04-25"
          },
          "entries": {
            "type": "integer",
            "format": "int64",
            "minimum": 0,
            "description": "Number of data rows in the published dataset (excluding the CSV header).",
            "example": 114000000
          },
          "size": {
            "type": "object",
            "required": [
              "csvgz"
            ],
            "description": "Sizes in bytes of the published files, keyed by format.",
            "properties": {
              "csvgz": {
                "type": "integer",
                "format": "int64",
                "minimum": 0,
                "description": "Size of the gzipped CSV file in bytes."
              },
              "mmdb": {
                "type": "integer",
                "format": "int64",
                "minimum": 0,
                "description": "Size of the MMDB file in bytes (omitted when the dataset has no MMDB output)."
              }
            }
          }
        }
      },
      "DbInvalidApiKeyError": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "INVALID_APIKEY"
            ]
          }
        }
      },
      "DbInvalidFormatError": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "INVALID_FORMAT"
            ]
          }
        }
      },
      "DbInvalidIdError": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "INVALID_ID"
            ]
          }
        }
      },
      "DbUnauthorizedIdError": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "UNAUTHORIZED_ID"
            ]
          }
        }
      },
      "DbNotFoundError": {
        "type": "object",
        "required": [
          "rc"
        ],
        "properties": {
          "rc": {
            "type": "string",
            "enum": [
              "DB_NOT_FOUND"
            ]
          }
        }
      },
      "AccountRc": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string",
            "description": "The outcome. `SUCCESS` on success; otherwise the reason."
          }
        },
        "required": [
          "rc"
        ]
      },
      "Identity": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string"
          },
          "user": {
            "$ref": "#/components/schemas/AccountUser"
          },
          "org": {
            "$ref": "#/components/schemas/AccountOrgRef"
          },
          "scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What this credential may do right now."
          }
        },
        "required": [
          "rc",
          "user",
          "org",
          "scopes"
        ]
      },
      "AccountUser": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "fullname": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          }
        },
        "required": [
          "id"
        ]
      },
      "AccountOrgRef": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          }
        },
        "required": [
          "id"
        ]
      },
      "AccountOrgWrap": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string"
          },
          "org": {
            "$ref": "#/components/schemas/AccountOrg"
          }
        },
        "required": [
          "rc",
          "org"
        ]
      },
      "AccountOrg": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "created": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "id"
        ]
      },
      "ApikeyList": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string"
          },
          "keys": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApikeyDetail"
            }
          }
        },
        "required": [
          "rc",
          "keys"
        ]
      },
      "ApikeyDetail": {
        "description": "Key METADATA. Never the key itself.",
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "key_prefix": {
            "type": "string",
            "description": "The leading, non-secret part, so a key is recognizable without storing it."
          },
          "created": {
            "type": "string",
            "format": "date-time"
          },
          "expires": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "last_used_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "revoked_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "allowed_cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Source-IP allowlist. EMPTY MEANS UNRESTRICTED, not deny-all."
          },
          "allowed_scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "retrievable": {
            "type": "boolean",
            "description": "Whether this key's secret can still be read back. False permanently for a key issued before secrets were stored recoverably."
          }
        },
        "required": [
          "id",
          "name",
          "key_prefix",
          "created"
        ]
      },
      "AccountCreateApikeyRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "A label you will recognize later. Shown wherever the key is listed."
          },
          "allowed_scopes": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What the new key may do. Omit for a key that carries no named scope, which is the safe default."
          }
        },
        "required": [
          "name"
        ]
      },
      "AccountCreatedApikey": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string"
          },
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "The secret. Returned once, here, and never again."
          },
          "key_prefix": {
            "type": "string"
          },
          "allowed_cidrs": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "allowed_scopes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "required": [
          "rc",
          "id",
          "key"
        ]
      },
      "AccountRevealedApikey": {
        "type": "object",
        "properties": {
          "rc": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "description": "The secret."
          }
        },
        "required": [
          "rc",
          "key"
        ]
      },
      "OauthMetadata": {
        "type": "object",
        "properties": {
          "issuer": {
            "type": "string"
          },
          "authorization_endpoint": {
            "type": "string"
          },
          "token_endpoint": {
            "type": "string"
          },
          "device_authorization_endpoint": {
            "type": "string"
          },
          "revocation_endpoint": {
            "type": "string"
          },
          "scopes_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "response_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "grant_types_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "code_challenge_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "client_id_metadata_document_supported": {
            "type": "boolean",
            "description": "Any client may sign in with an https `client_id` serving its own metadata."
          },
          "token_endpoint_auth_methods_supported": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Always `none`. Every client is public and has no secret."
          },
          "authorization_response_iss_parameter_supported": {
            "type": "boolean",
            "description": "RFC 9207. A redirect back from the authorization endpoint carries `iss`."
          },
          "service_documentation": {
            "type": "string"
          }
        },
        "required": [
          "issuer",
          "authorization_endpoint",
          "token_endpoint"
        ]
      },
      "DeviceAuthorizationRequest": {
        "type": "object",
        "properties": {
          "client_id": {
            "type": "string"
          },
          "scope": {
            "type": "string",
            "description": "Space-delimited. Anything your client is not registered for is dropped rather than refused."
          },
          "resource": {
            "type": "string",
            "description": "RFC 8707: what the token is for."
          }
        },
        "required": [
          "client_id"
        ]
      },
      "DeviceAuthorization": {
        "type": "object",
        "properties": {
          "device_code": {
            "type": "string",
            "description": "Yours. Poll with it; never show it to anyone."
          },
          "user_code": {
            "type": "string",
            "description": "Short and typable. This is what the person confirms."
          },
          "verification_uri": {
            "type": "string"
          },
          "verification_uri_complete": {
            "type": "string",
            "description": "The same page with the code already filled in."
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until both codes expire."
          },
          "interval": {
            "type": "integer",
            "description": "Seconds between polls."
          }
        },
        "required": [
          "device_code",
          "user_code",
          "verification_uri",
          "expires_in",
          "interval"
        ]
      },
      "TokenRequest": {
        "type": "object",
        "properties": {
          "grant_type": {
            "type": "string",
            "description": "`urn:ietf:params:oauth:grant-type:device_code`, `authorization_code` or `refresh_token`."
          },
          "client_id": {
            "type": "string"
          },
          "device_code": {
            "type": "string",
            "description": "Required by the device code grant."
          },
          "code": {
            "type": "string",
            "description": "Required by the authorization code grant."
          },
          "code_verifier": {
            "type": "string",
            "description": "Required by the authorization code grant."
          },
          "redirect_uri": {
            "type": "string",
            "description": "Required by the authorization code grant: the `redirect_uri` the code was issued against, exactly."
          },
          "resource": {
            "type": "string",
            "description": "Authorization code grant, optional: RFC 8707, and it must name what was authorized."
          },
          "refresh_token": {
            "type": "string",
            "description": "Required by the refresh token grant."
          }
        },
        "required": [
          "grant_type",
          "client_id"
        ]
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "description": "Always `Bearer`."
          },
          "expires_in": {
            "type": "integer",
            "description": "Seconds until the access token expires."
          },
          "refresh_token": {
            "type": "string",
            "description": "Always returned. A refresh consumes the token it presents, so keep this one."
          },
          "scope": {
            "type": "string",
            "description": "What was actually granted, which may be narrower than what was asked for."
          },
          "mslm:apikey_id": {
            "type": "string",
            "description": "Not part of OAuth, and only for our own clients. The ID of the API\nkey the person picked when they approved, returned by every grant\nwhile this authorization may still read that key back. Absent when\nno key was picked, or when the person's role no longer allows\nreading keys back.\n"
          },
          "mslm:apikey": {
            "type": "string",
            "description": "Not part of OAuth, and only for our own clients: a client that signed\nin with a Client ID Metadata Document never receives a key. The API\nkey itself, so a device ends up holding an ordinary key. Returned by\nthe device code and authorization code grants only, never by a\nrefresh, and only alongside\n`mslm:apikey_id`. Absent when that key's secret cannot be read back,\nwhich is the case for a key created before keys could be shown again\nin the console; a rotated key can be.\n"
          }
        },
        "required": [
          "access_token",
          "token_type",
          "expires_in"
        ]
      },
      "RevokeRequest": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "An access token or a refresh token."
          },
          "client_id": {
            "type": "string",
            "description": "Accepted and not checked."
          }
        },
        "required": [
          "token"
        ]
      },
      "OauthError": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ]
      }
    },
    "responses": {
      "V2Unauthorized": {
        "description": "Missing or invalid bearer key, the key lacks the `db.download` scope, or\nit belongs to no organization.\n`rc`: `UNAUTHORIZED`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "V2NotLicensed": {
        "description": "Your organization holds no license for this database, or its term has\nended.\n`rc`: `NOT_LICENSED`, `LICENSE_EXPIRED`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "V2UnknownDatabase": {
        "description": "No such database.\n`rc`: `UNKNOWN_DATASET`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "V2NotAvailable": {
        "description": "The current build has not been published yet.\n`rc`: `NOT_AVAILABLE`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "The request query parameters were malformed.\nPossible `rc` values: `INVALID_FORMAT`, `INVALID_ID`.\n",
        "content": {
          "application/json": {
            "schema": {
              "oneOf": [
                {
                  "$ref": "#/components/schemas/DbInvalidFormatError"
                },
                {
                  "$ref": "#/components/schemas/DbInvalidIdError"
                }
              ]
            }
          }
        }
      },
      "Unauthorized": {
        "description": "The `apikey` query parameter was missing or not recognized.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DbInvalidApiKeyError"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The `apikey` is valid but is not authorized for the requested database id.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DbUnauthorizedIdError"
            }
          }
        }
      },
      "NotFound": {
        "description": "The requested database file does not exist on the server.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DbNotFoundError"
            }
          }
        }
      },
      "AccountUnauthorized": {
        "description": "No credential was presented, or it is not valid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AccountRc"
            }
          }
        }
      },
      "AccountForbidden": {
        "description": "The credential does not hold the scope this endpoint requires. The\nmissing scope is deliberately not named.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AccountRc"
            }
          }
        }
      },
      "AccountNotFound": {
        "description": "No such key in this organization.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AccountRc"
            }
          }
        }
      },
      "AccountInvalid": {
        "description": "The request body is missing a required field.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AccountRc"
            }
          }
        }
      }
    }
  },
  "x-tagGroups": [
    {
      "name": "InternetData Database API",
      "tags": [
        "Database",
        "Database v2"
      ]
    },
    {
      "name": "InternetData IAM API",
      "tags": [
        "Account",
        "Organization",
        "API keys"
      ]
    },
    {
      "name": "InternetData Authorization",
      "tags": [
        "Authorization"
      ]
    }
  ]
}
