{
  "openapi": "3.0.7",
  "info": {
    "title": "IPGeolocation.io: IP Security API",
    "version": "3.0",
    "description": "Detect VPNs, proxies, residential proxies, Tor exit nodes, relays, bot activity,\nspam activity, and other risk signals for any IPv4 or IPv6 address.\n\nThe API returns a threat score along with detailed flags indicating whether\nthe IP address belongs to anonymization services, cloud providers, or known\nattacker infrastructure. When available, provider names, confidence scores,\nand last-seen timestamps are also returned.\n\nTwo endpoints are available:\n\n- **Single lookup** (`GET /v3/security`) returns security intelligence for one IP.\n- **Bulk lookup** (`POST /v3/security-bulk`) accepts up to 50,000 IPs in a\n  single request.\n\nBoth endpoints support response filtering using the `fields`, `excludes` and `output`\nparameters to reduce payload size and return only the data you need.\n\n ## Authentication\n\nTwo authentication methods are supported:\n\n### API Key\n\nPass your API key as the `apiKey` query parameter on every request. You can find your\nkey in the [IPGeolocation dashboard](https://app.ipgeolocation.io/). Store it in\nserver-side environment variables. Avoid exposing it in client-side JavaScript.\n\n### Request Origin (CORS)\n\nAvailable on paid plans only. Whitelist your domain in the dashboard under the\n\"API Keys\" section. Once configured, requests from that domain (and all its subdomains)\nare accepted without passing `apiKey`. Enter your root domain (e.g. `example.com`),\nnot the full URL.\n\nEach plan has a limit on the number of extra API keys and request origins:\n\n| Plan | Extra API Keys + Request Origins |\n|---|---|\n| Starter (150K requests) | 1 |\n| Core (250K requests) | 1 |\n| Plus (500K requests) | 2 |\n| Pro (1M requests) | 2 |\n| Business (2M requests) | 3 |\n| Premium (5M requests) | 3 |\n\nAdditional keys or origins can be added for $2.50 per month each.\n\n## Response Formats\n\nThe API supports JSON (default) and XML output.\n\n- Set the `output` query parameter to `json` or `xml`.\n- Alternatively, set the `Accept` header to `application/json`, `application/xml`,\n  or `text/xml`.\n\nIf neither is specified, the response is returned as JSON. XML responses use a\n`LinkedHashMap` root element.\n\n## Credit Usage\n\nCredits are charged only for successful **HTTP 200** responses. The exact number of\ncredits consumed by a request is returned in the `X-Credits-Charged` response header.\n\nA **single IP security lookup** (`GET /v3/security`) consumes **2 credits** per request.\nFor **bulk lookups** (`POST /v3/security-bulk`), **2 credits are charged for each valid IP**\nin the request.\n\nFor bulk requests, the total credits charged equal the number of valid IPs multiplied\nby the per-IP credit cost. Private, bogon, and malformed IP addresses are not counted\nas valid and therefore do not consume credits.\n\n## Field Filtering\n\nUse `fields` to return only specific fields, or `excludes` to remove\nfields you do not need. Both parameters support dot-notation for\nnested fields such as `security.is_vpn` or `security.threat_score`.\n\nThe `ip` field is always returned and cannot be excluded.\n\n## Parameter Name Casing\n\nQuery parameter names are case-sensitive. Use exact names such as\n`apiKey`, `ip`, `fields`, `excludes`, and `output`.\n\n## Rate Limits\n\nThe IP Security API is available **only on paid plans**.\n\nPaid subscriptions do not have fixed daily, hourly, or monthly rate limits.\nIf the monthly quota is exceeded, requests continue and a surcharge may be\napplied according to the subscribed plan.\n\nFree plans cannot access the IP Security API. Requests made with a free plan\nAPI key return HTTP 401 Unauthorized.\n",
    "contact": {
      "name": "IPGeolocation Support",
      "url": "https://ipgeolocation.io",
      "email": "support@ipgeolocation.io"
    },
    "termsOfService": "https://ipgeolocation.io/tos.html",
    "license": {
      "name": "Proprietary",
      "url": "https://ipgeolocation.io/tos.html"
    }
  },
  "externalDocs": {
    "description": "IPGeolocation IP Security API documentation",
    "url": "https://ipgeolocation.io/documentation/ip-security-api.html"
  },
  "servers": [
    {
      "url": "https://api.ipgeolocation.io",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": [

      ]
    }
  ],
  "paths": {
    "/v3/security": {
      "get": {
        "operationId": "lookupIpSecurity",
        "summary": "Single IP security lookup",
        "description": "Returns threat intelligence and anonymization signals for a single\nIPv4 or IPv6 address.\n\nIf the `ip` parameter is omitted, the API automatically detects the\ncaller's public IP address and returns its security risk signals.\n\nThe response includes a threat score and multiple indicators such\nas VPN usage, proxy usage, Tor exit node detection, relay networks,\nbot activity, spam activity, and cloud hosting infrastructure.\n\nWhen available, provider names, confidence scores, and last-seen\ntimestamps are included.\n\nUse the `fields` and `excludes` parameters to control which parts\nof the response are returned.\n",
        "tags": [
          "IP Security"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/Ip"
          },
          {
            "$ref": "#/components/parameters/Fields"
          },
          {
            "$ref": "#/components/parameters/Excludes"
          },
          {
            "$ref": "#/components/parameters/Output"
          }
        ],
        "responses": {
          "200": {
            "description": "Security intelligence for the requested IP.",
            "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/IpSecurityResponse"
                },
                "example": {
                  "security": {
                    "threat_score": 80,
                    "is_tor": false,
                    "is_proxy": true,
                    "proxy_provider_names": [
                      "Zyte Proxy"
                    ],
                    "proxy_confidence_score": 80,
                    "proxy_last_seen": "2025-12-12",
                    "is_residential_proxy": true,
                    "is_vpn": true,
                    "vpn_provider_names": [
                      "Nord VPN"
                    ],
                    "vpn_confidence_score": 80,
                    "vpn_last_seen": "2026-01-19",
                    "is_relay": false,
                    "relay_provider_name": "",
                    "is_anonymous": true,
                    "is_known_attacker": true,
                    "is_bot": false,
                    "is_spam": false,
                    "is_cloud_provider": true,
                    "cloud_provider_name": "Packethub S.A."
                  }
                }
              },
              "application/xml": {
                "schema": {
                  "$ref": "#/components/schemas/IpSecurityResponse"
                },
                "example": "<LinkedHashMap>\n  <ip>2.56.188.34</ip>\n  <security>\n      <threat_score>80</threat_score>\n      <is_tor>false</is_tor>\n      <is_proxy>true</is_proxy>\n      <proxy_provider_names>Zyte Proxy</proxy_provider_names>\n      <proxy_confidence_score>80</proxy_confidence_score>\n      <proxy_last_seen>2025-12-12</proxy_last_seen>\n      <is_residential_proxy>true</is_residential_proxy>\n      <is_vpn>true</is_vpn>\n      <vpn_provider_names>Nord VPN</vpn_provider_names>\n      <vpn_confidence_score>80</vpn_confidence_score>\n      <vpn_last_seen>2026-01-19</vpn_last_seen>\n      <is_relay>false</is_relay>\n      <relay_provider_name></relay_provider_name>\n      <is_anonymous>true</is_anonymous>\n      <is_known_attacker>true</is_known_attacker>\n      <is_bot>false</is_bot>\n      <is_spam>false</is_spam>\n      <is_cloud_provider>true</is_cloud_provider>\n      <cloud_provider_name>Packethub S.A.</cloud_provider_name>\n  </security>\n</LinkedHashMap>\n"
              }
            }
          },
          "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"
          }
        }
      }
    },
    "/v3/security-bulk": {
      "post": {
        "operationId": "bulkLookupIpSecurity",
        "summary": "Bulk IP security lookup",
        "description": "Returns security intelligence for up to **50,000 IPv4 or IPv6\naddresses** in a single request.\n\nThe request body must contain an `ips` array.\n\nEach IP is processed independently. Invalid, bogon, or private\nIP addresses return an object containing only a `message` field.\n\nCredits are charged **per valid IP address** using the same\npricing rules as the single lookup endpoint.\n\nWhen at least one entry is invalid, the response header\n`X-Successful-Record` indicates the number of successful\nlookups.\n\nOnly the `POST` method is supported for this endpoint.\n",
        "tags": [
          "IP Security"
        ],
        "parameters": [
          {
            "$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\nan IPv4 address or IPv6 address. The array must not be empty and\nmust not contain more than 50,000 entries.\n",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkSecurityRequest"
              },
              "examples": {
                "mixedIps": {
                  "summary": "Mixed IPv4 and IPv6",
                  "value": {
                    "ips": [
                      "8.8.8.8",
                      "91.128.103.196",
                      "2607:fb91:16c6:8860:e531:2d1d:4944:6c7c"
                    ]
                  }
                },
                "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 IP address.\n\nValid entries return a security lookup object containing the IP address\nand its associated security intelligence.\n\nInvalid, private, or bogon IP addresses return an object containing only\na `message` field.\n\nThe `X-Successful-Record` response header is returned only when the request\ncontains one or more invalid entries and indicates the number of successful\nlookups.\n",
            "headers": {
              "X-Credits-Charged": {
                "description": "Total number of API credits consumed. Equals credits per lookup\nmultiplied by the count of valid IPs.\n",
                "schema": {
                  "type": "number",
                  "example": 3
                }
              },
              "X-Successful-Record": {
                "description": "Number of valid IP addresses that were successfully resolved in\nthis bulk request. Invalid, bogon, and private IPs are not counted.\nThis header is included only when at least one bulk entry returns an\nerror message and total successful lookups are fewer than submitted\nentries.\n",
                "schema": {
                  "type": "number",
                  "example": 4
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/BulkSecurityResponseItem"
                  }
                },
                "example": [
                  {
                    "ip": "2.56.188.34",
                    "security": {
                      "threat_score": 80,
                      "is_tor": false,
                      "is_proxy": true,
                      "proxy_provider_names": [
                        "Zyte Proxy"
                      ],
                      "proxy_confidence_score": 80,
                      "proxy_last_seen": "2025-12-12",
                      "is_residential_proxy": true,
                      "is_vpn": true,
                      "vpn_provider_names": [
                        "Nord VPN"
                      ],
                      "vpn_confidence_score": 80,
                      "vpn_last_seen": "2026-01-19",
                      "is_relay": false,
                      "relay_provider_name": "",
                      "is_anonymous": true,
                      "is_known_attacker": true,
                      "is_bot": false,
                      "is_spam": false,
                      "is_cloud_provider": true,
                      "cloud_provider_name": "Packethub S.A."
                    }
                  },
                  {
                    "message": "'10.0.0.1' is a bogon IP address."
                  }
                ]
              },
              "application/xml": {
                "schema": {
                  "type": "array",
                  "xml": {
                    "name": "ArrayList",
                    "wrapped": true
                  },
                  "items": {
                    "$ref": "#/components/schemas/BulkSecurityResponseItem",
                    "xml": {
                      "name": "item"
                    }
                  }
                },
                "example": "<ArrayList>\n  <item>\n    <ip>2.56.188.34</ip>\n    <security>\n        <threat_score>80</threat_score>\n        <is_tor>false</is_tor>\n        <is_proxy>true</is_proxy>\n        <proxy_provider_names>Zyte Proxy</proxy_provider_names>\n        <proxy_confidence_score>80</proxy_confidence_score>\n        <proxy_last_seen>2025-12-12</proxy_last_seen>\n        <is_residential_proxy>true</is_residential_proxy>\n        <is_vpn>true</is_vpn>\n        <vpn_provider_names>Nord VPN</vpn_provider_names>\n        <vpn_confidence_score>80</vpn_confidence_score>\n        <vpn_last_seen>2026-01-19</vpn_last_seen>\n        <is_relay>false</is_relay>\n        <relay_provider_name></relay_provider_name>\n        <is_anonymous>true</is_anonymous>\n        <is_known_attacker>true</is_known_attacker>\n        <is_bot>false</is_bot>\n        <is_spam>false</is_spam>\n        <is_cloud_provider>true</is_cloud_provider>\n        <cloud_provider_name>Packethub S.A.</cloud_provider_name>\n    </security>\n  <item>\n      <message>'10.0.0.0' is a bogon IP address.</message>\n  </item>\n</ArrayList>\n"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "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"
          }
        }
      }
    }
  },
  "components": {
    "parameters": {
      "Ip": {
        "name": "ip",
        "in": "query",
        "required": false,
        "description": "An IPv4 address or IPv6 address to look up. When omitted, the API\nresolves the public IP of the requesting client. Empty or whitespace-only values\nare treated the same as omission and resolve caller IP. Pass `ip` only once. If multiple `ip` query parameters are sent,\nvalues may be merged and treated as invalid input (HTTP 400).\n",
        "schema": {
          "type": "string"
        },
        "examples": {
          "ipv4": {
            "summary": "IPv4 address",
            "value": "91.128.103.196"
          },
          "ipv6": {
            "summary": "IPv6 address",
            "value": "2607:fb91:16c6:8860:e531:2d1d:4944:6c7c"
          }
        }
      },
      "Fields": {
        "name": "fields",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of fields or objects to return. Everything else is omitted.\nThe `ip` field is always returned regardless of this filter.\n\nSupports dot-notation for nested fields: `security.is_tor`, `security.threat_score`.\n\nIf the same field or object is specified in both `fields` and `excludes`, the\nobject is still returned, but it will be empty.\n\nIf you list both an object key and one of its nested fields separated by comma\n(e.g. `security,security.is_vpn`), the full object is returned.\n\nUnknown field paths are ignored. The API still returns HTTP 200.\n\nAvailable on all plans including Free.\n",
        "schema": {
          "type": "string"
        },
        "examples": {
          "none": {
            "summary": "Return the full response (no field filtering)",
            "value": ""
          },
          "threatScoreOnly": {
            "summary": "Return only the threat score",
            "value": "security.threat_score"
          },
          "moreThanOneFields": {
            "summary": "Return specific fields",
            "value": "security.is_tor,security.is_vpn"
          }
        }
      },
      "Excludes": {
        "name": "excludes",
        "in": "query",
        "required": false,
        "description": "Comma-separated list of fields or objects to remove from the response. The `ip`\nfield cannot be excluded.\n\nSupports dot-notation for nested fields: `security.is_relay`.\n\nIf the same field or object is specified in both `fields` and `excludes`, the\nobject is still returned, but it will be empty.\n\nUnknown fields or object keys in `excludes` are ignored. The API still returns\nHTTP 200.\n\nAvailable on all plans including Free.\n",
        "schema": {
          "type": "string"
        },
        "examples": {
          "none": {
            "summary": "Do not exclude any fields",
            "value": ""
          },
          "excludeFields": {
            "summary": "Exclude proxy provider names and residential proxy flag",
            "value": "security.proxy_provider_names,security.is_residential_proxy"
          }
        }
      },
      "Output": {
        "name": "output",
        "in": "query",
        "required": false,
        "description": "Desired response format. Defaults to `json` if not specified. You can also\ncontrol the format using the `Accept` header (`application/json`,\n`application/xml`, or `text/xml`). If both are provided, the `output` parameter\ntakes precedence.\n\nIf `output` is unknown or unsupported, it is ignored and the response defaults\nto JSON (`application/json`) with HTTP 200.\n",
        "schema": {
          "type": "string",
          "enum": [
            "json",
            "xml"
          ],
          "default": "json"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Bad request. Returned for one of the following reasons:\n\n- The provided IPv4 or IPv6 address is invalid.\n- Special characters such as ( ) [ ] { } | ^ ` are present in the API URL,\n  either in a parameter name or its value (especially in the API key).\n- For the `security-bulk` endpoint:\n  - The request payload is empty or missing.\n  - The JSON body is malformed.\n  - The `ips` field is missing or the `ips` array is empty.\n  - More than 50,000 IP addresses are provided in the request.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "invalidIp": {
                "summary": "Invalid IPv4/IPv6 input",
                "value": {
                  "message": "Provided name, service or IP address '999.999.999.999' is not valid."
                }
              },
              "specialCharacters": {
                "summary": "Special characters in API URL or key",
                "value": {
                  "message": "Invalid character found in the request target."
                }
              },
              "malformedJson": {
                "summary": "Malformed JSON body for bulk endpoint",
                "value": {
                  "message": "Malformed JSON request or invalid field"
                }
              },
              "missingIps": {
                "summary": "Bulk body missing ips field",
                "value": {
                  "message": "IP addresses for bulk lookup are missing"
                }
              },
              "emptyBulkIps": {
                "summary": "Bulk ips array is empty",
                "value": {
                  "message": "'ips' must not be empty or null"
                }
              },
              "tooManyBulkEntries": {
                "summary": "Bulk body exceeds 50,000 entries",
                "value": {
                  "message": "No. of lookup queries cannot be more than 50000"
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Unauthorized. Returned for one of the following reasons:\n\n- The `apiKey` URL parameter is missing.\n- An invalid (random or incorrect) API key is provided.\n- The account has been disabled or locked due to abuse or illegal activity.\n- The API request is made using an API key for a database subscription.\n- The API request is made using a free subscription API key.\n- The subscription is in a 'paused' state.\n- The subscription trial has expired.\n- The account’s active-until date has passed and renewal or upgrade is required.\n- A domain name is passed in the `ip` parameter when calling the IP Security API.\n- The bulk IP security lookup endpoint is called using a free subscription API key.\n- The bulk IP security lookup endpoint is called using Request Origin (CORS)\n  authentication. Bulk requests require an `apiKey` and cannot be authenticated\n  using Request Origin alone.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "missingApiKey": {
                "summary": "Missing API key",
                "value": {
                  "message": "Please provide an API key (as 'apiKey=YOUR_API_KEY' URL parameter) to use IPGeolocation API. To get your free API Key, sign up at https://app.ipgeolocation.io/login"
                }
              },
              "invalidApiKey": {
                "summary": "Invalid API key",
                "value": {
                  "message": "Provided API key is not valid. Contact technical support for assistance at support@ipgeolocation.io"
                }
              },
              "lockedAccount": {
                "summary": "Account locked or disabled",
                "value": {
                  "message": "Your account has been locked to use IPGeolocation API. Contact technical support for assistance at support@ipgeolocation.io"
                }
              },
              "databaseSubscriptionKey": {
                "summary": "Database subscription API key used for REST API",
                "value": {
                  "message": "You cannot query IPGeolocation API on a database plan subscription."
                }
              },
              "freePlanAccess": {
                "summary": "Free subscription used for IP Security API",
                "value": {
                  "message": "IP Security API is not supported on your current subscription. This feature is available on paid subscriptions only."
                }
              },
              "pausedSubscription": {
                "summary": "Subscription is paused",
                "value": {
                  "message": "Your subscription has been paused. Please resume your subscription to use IPGeolocation API."
                }
              },
              "expiredSubscription": {
                "summary": "Subscription expired or trial ended",
                "value": {
                  "message": "Your subscription has expired. Please subscribe to a paid plan to continue using IPGeolocation API."
                }
              },
              "domainLookupNotSupported": {
                "summary": "Domain lookup used with Security API",
                "value": {
                  "message": "Domain lookup is not supported for the IP Security API."
                }
              },
              "requestOriginBulk": {
                "summary": "Bulk endpoint called using Request Origin authentication",
                "value": {
                  "message": "Bulk queries are not allowed with request origins. Please use an API key to perform bulk queries."
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found. Returned for one of the following reasons:\n\n- A syntactically valid IPv4 or IPv6 address does not exist in the IPGeolocation database.\n- An IPv4 address, IPv6 address, or domain name is passed as a path variable\n  instead of as a URL query parameter (e.g., using `/v3/ipgeo/8.8.8.8`\n  instead of `/v3/ipgeo?ip=8.8.8.8`).\n- A non-existent or incorrect API endpoint is called.\n\nInvalid or malformed IPv4, IPv6, or domain input returns HTTP 400 instead.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "ipNotInDatabase": {
                "summary": "IPv4/IPv6 not found in database",
                "value": {
                  "message": "Provided IPv4 or IPv6 address does not exist in our database."
                }
              },
              "ipAsPathVariable": {
                "summary": "IP passed as path variable instead of query parameter",
                "value": {
                  "message": "No endpoint GET /v3/ipgeo/8.8.8.8."
                }
              },
              "wrongEndpoint": {
                "summary": "Incorrect or non-existent endpoint",
                "value": {
                  "message": "No endpoint GET /v3/security-invalid."
                }
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "Method Not Allowed. Returned when an unsupported HTTP method is used\nto call an endpoint.\n\nOnly GET and POST methods are supported:\n\n- `GET` is allowed for the `ipgeo` endpoint.\n- `POST` is allowed for the `ipgeo-bulk` endpoint.\n\nAny other HTTP method, or using the correct method on the wrong endpoint,\nresults in HTTP 405.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "getNotAllowedForBulk": {
                "summary": "GET used on bulk endpoint",
                "value": {
                  "message": "Request method 'GET' is not supported"
                }
              },
              "postNotAllowedForSingle": {
                "summary": "POST used on single lookup endpoint",
                "value": {
                  "message": "Request method 'POST' is not supported"
                }
              },
              "unsupportedMethod": {
                "summary": "Unsupported HTTP method",
                "value": {
                  "message": "Request method is not supported"
                }
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Payload too large. Returned by the edge proxy (nginx) when raw POST body size\nexceeds configured limits before the request reaches the application.\n\nThis status is based on payload byte size, not on the number of IP entries. It\ncan occur even when `ips` contains only one very large value.\n\nIf both conditions apply (oversized body and `ips` count > 50,000), HTTP 413 may\nbe returned first because edge validation runs before application-level checks.\n",
        "content": {
          "text/html": {
            "schema": {
              "type": "string"
            },
            "example": "<html>\n  <head>\n    <title>413 Request Entity Too Large</title>\n  </head>\n  <body>\n    <center><h1>413 Request Entity Too Large</h1></center>\n    <hr><center>nginx/1.24.0 (Ubuntu)</center>\n  </body>\n</html>\n"
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "Unsupported media type. The `Content-Type` header is not set to `application/json`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Content-Type 'application/x-www-form-urlencoded' is not supported"
            }
          }
        }
      },
      "Locked": {
        "description": "Locked. The provided IP address belongs to a bogon IP range or a private\nnetwork and cannot be looked up.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "'10.0.0.1' is a bogon IP address."
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too Many Requests. Returned for one of the following reasons:\n- The API usage limit has been reached for a Paid subscription with\n  status 'past due', 'deleted', or 'trial expired'.\n- The surcharge API usage limit has been reached for the subscribed plan.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "usageLimitReached": {
                "summary": "API usage limit reached",
                "value": {
                  "message": "You have exceeded the limit of PLAN_USAGE_LIMIT requests per PLAN_INERVAL for your subscribed PLAN plan. Please throttle your requests or upgrade your plan to continue using IPGeolocation API without interruption."
                }
              },
              "surchargeLimitReached": {
                "summary": "Surcharge usage limit reached",
                "value": {
                  "message": "You have reached the surcharge amount limit of PLAN_USAGE_LIMIT_AND_SURCHARGE_LIMIT on your subscribed PLAN plan. Please throttle your requests or upgrade your plan to continue using IPGeolocation API without interruption."
                }
              }
            }
          }
        }
      },
      "ClientClosedRequest": {
        "description": "The client closed the connection before the server finished processing the\nrequest. This usually happens when the client sets a very short request or\nconnection timeout. Increase the timeout on the client side.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Client closed the request before the server could respond."
            }
          }
        }
      },
      "InternalServerError": {
        "description": "Internal Server Error. The server encountered an unexpected condition\nthat prevented it from fulfilling the request. If the issue persists,\ncontact support@ipgeolocation.io.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Something went wrong on the server side."
            }
          }
        }
      },
      "BadGateway": {
        "description": "Bad Gateway. The API server received an invalid response from an upstream\nserver while processing the request. This is usually temporary.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Upstream service error. Please try again later."
            }
          }
        }
      },
      "ServiceUnavailable": {
        "description": "Service Unavailable. The API is temporarily unavailable due to maintenance\nor overload. Please try again later.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "Service temporarily unavailable. Please try again later."
            }
          }
        }
      },
      "GatewayTimeout": {
        "description": "Gateway Timeout. The API server did not receive a timely response from\nan upstream server.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "The server timed out while processing the request."
            }
          }
        }
      },
      "HttpVersionNotSupported": {
        "description": "HTTP Version Not Supported. The server does not support the HTTP protocol\nversion used in the request.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "example": {
              "message": "HTTP version not supported."
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "description": "Returned for any non-200 response. Contains only a human-readable `message`.\nMessage text can vary by status and condition; examples in this spec are\nrepresentative, not exhaustive, and should not be treated as stable machine\ncodes.\n",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable explanation of what went wrong. Use HTTP status for control flow.",
            "example": "Provided name, service or IP address '999.999.999.999' is not valid."
          }
        }
      },
      "BulkSecurityRequest": {
        "type": "object",
        "description": "Request body for the bulk security lookup. Contains a single `ips` field\nwith an array of IP addresses to look up.\n",
        "required": [
          "ips"
        ],
        "properties": {
          "ips": {
            "type": "array",
            "description": "Array of IPv4 addresses or IPv6 addresses to look up.\nMust not be empty. Maximum 50,000 entries per request. Each entry is\nresolved independently, so you can mix IPv4 and IPv6 freely.\n",
            "minItems": 1,
            "maxItems": 50000,
            "items": {
              "type": "string"
            },
            "examples": [
              "8.8.8.8",
              "91.128.103.196",
              "2607:fb91:16c6:8860:e531:2d1d:4944:6c7c"
            ]
          }
        }
      },
      "BulkSecurityResponseItem": {
        "description": "A single element in the bulk lookup response array. Each element is either a\nfull security object or an error object containing only `message`.\n",
        "oneOf": [
          {
            "$ref": "#/components/schemas/BulkSecuritySuccessItem"
          },
          {
            "$ref": "#/components/schemas/BulkSecurityErrorItem"
          }
        ]
      },
      "BulkSecuritySuccessItem": {
        "type": "object",
        "required": [
          "ip",
          "security"
        ],
        "properties": {
          "ip": {
            "type": "string",
            "description": "IP address for this lookup result.",
            "example": "2.56.188.34"
          },
          "security": {
            "$ref": "#/components/schemas/Security"
          }
        }
      },
      "BulkSecurityErrorItem": {
        "type": "object",
        "description": "Error object returned for an invalid entry in the bulk lookup request. Contains only\na `message` field. Note: unlike success entries, error entries do NOT include the\noriginal `ip` field, so the only way to correlate errors to inputs is by array\nindex. The response array preserves the same order as the request `ips` array.\n",
        "required": [
          "message"
        ],
        "properties": {
          "message": {
            "type": "string",
            "description": "Human-readable error for the specific bulk entry.",
            "example": "Provided name, service or IP address 'invalid-ip' is not valid."
          }
        }
      },
      "IpSecurityResponse": {
        "type": "object",
        "xml": {
          "name": "LinkedHashMap"
        },
        "required": [
          "ip"
        ],
        "properties": {
          "ip": {
            "type": "string",
            "description": "IP address used for the lookup.",
            "example": "2.56.188.34"
          },
          "security": {
            "$ref": "#/components/schemas/Security"
          }
        }
      },
      "Security": {
        "type": "object",
        "description": "Threat intelligence and anonymization signals for the IP. Costs 2 credits.\n",
        "properties": {
          "threat_score": {
            "type": "number",
            "description": "Overall threat score from 0 (clean) to 100 (high risk). Aggregated from\nall the individual signals below.\n",
            "minimum": 0,
            "maximum": 100,
            "example": 80
          },
          "is_tor": {
            "type": "boolean",
            "description": "Whether the IP is a known Tor exit node.",
            "example": false
          },
          "is_proxy": {
            "type": "boolean",
            "description": "Whether the IP belongs to a known proxy service.",
            "example": true
          },
          "proxy_provider_names": {
            "type": "array",
            "description": "Names of proxy providers associated with this IP, if any.",
            "items": {
              "type": "string"
            },
            "examples": [
              "Zyte Proxy"
            ]
          },
          "proxy_confidence_score": {
            "type": "number",
            "description": "Confidence that this IP is a proxy, from 0 to 100. Only meaningful when\n`is_proxy` is `true`.\n",
            "minimum": 0,
            "maximum": 100,
            "example": 90
          },
          "proxy_last_seen": {
            "type": "string",
            "description": "Date when this IP was last observed acting as a proxy, in `YYYY-MM-DD`\nformat. Empty string if never seen.\n",
            "example": "2025-12-12"
          },
          "is_residential_proxy": {
            "type": "boolean",
            "description": "Whether the IP is a known residential proxy.",
            "example": true
          },
          "is_vpn": {
            "type": "boolean",
            "description": "Whether the IP belongs to a known VPN provider.",
            "example": true
          },
          "vpn_provider_names": {
            "type": "array",
            "description": "Names of VPN providers associated with this IP, if any.",
            "items": {
              "type": "string"
            },
            "examples": [
              "Nord VPN"
            ]
          },
          "vpn_confidence_score": {
            "type": "number",
            "description": "Confidence that this IP is a VPN endpoint, from 0 to 100. Only meaningful\nwhen `is_vpn` is `true`.\n",
            "minimum": 0,
            "maximum": 100,
            "example": 90
          },
          "vpn_last_seen": {
            "type": "string",
            "description": "Date when this IP was last observed as a VPN endpoint, in `YYYY-MM-DD`\nformat. Empty string if never seen.\n",
            "example": "2026-01-19"
          },
          "is_relay": {
            "type": "boolean",
            "description": "Whether the IP is part of a known relay network (e.g. iCloud Private Relay).",
            "example": false
          },
          "relay_provider_name": {
            "type": "string",
            "description": "Name of the relay provider, if any. Empty string if not a relay.",
            "example": ""
          },
          "is_anonymous": {
            "type": "boolean",
            "description": "Whether the IP is associated with any anonymization method (VPN, proxy,\nTor, or relay).\n",
            "example": true
          },
          "is_known_attacker": {
            "type": "boolean",
            "description": "Whether the IP has been flagged in known attacker or threat feeds.",
            "example": true
          },
          "is_bot": {
            "type": "boolean",
            "description": "Whether the IP is associated with known bot activity.",
            "example": false
          },
          "is_spam": {
            "type": "boolean",
            "description": "Whether the IP is listed in spam databases.",
            "example": false
          },
          "is_cloud_provider": {
            "type": "boolean",
            "description": "Whether the IP belongs to a cloud hosting or data center provider.",
            "example": true
          },
          "cloud_provider_name": {
            "type": "string",
            "description": "Name of the cloud provider, if applicable. Empty string otherwise.",
            "example": "Packethub S.A."
          }
        }
      }
    },
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "query",
        "name": "apiKey",
        "description": "API key passed as the `apiKey` query parameter. Get yours from the\n[IPGeolocation dashboard](https://app.ipgeolocation.io/). For client-side\nusage, consider using Request Origin (CORS) authentication instead to\navoid exposing your key.\n"
      }
    }
  },
  "tags": [
    {
      "name": "IP Security",
      "description": "IP security intelligence endpoints used to detect VPNs,\nproxies, Tor exit nodes, relay networks, bot activity,\nspam activity, cloud providers, and other anonymization\ntechnologies associated with IP addresses.\n\nThe single lookup endpoint (`GET /v3/security`) analyzes\none IP per request.\n\nThe bulk lookup endpoint (`POST /v3/security-bulk`)\naccepts up to 50,000 IP addresses per request.\n",
      "externalDocs": {
        "description": "IPGeolocation IP Security API documentation",
        "url": "https://ipgeolocation.io/documentation/ip-security-api.html"
      }
    }
  ]
}
