{
  "openapi": "3.1.0",
  "info": {
    "title": "Litport API",
    "version": "1.0.0",
    "description": "Public free-proxy retrieval and authenticated account operations (tokens, packages, and pay-per-GB). No endpoint creates or deletes proxy tokens."
  },
  "servers": [
    {
      "url": "https://litport.net"
    }
  ],
  "paths": {
    "/api/free-proxy": {
      "get": {
        "operationId": "listFreeProxies",
        "summary": "List public free proxies",
        "description": "Returns a bare array. Invalid numeric and sort inputs currently fall back to defaults instead of returning 400.",
        "security": [],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Case-insensitive ISO-2 code. The value is uppercased; no aliases are applied.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Accepted range 10–1000. Invalid or out-of-range values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 10,
              "maximum": 1000,
              "default": 50
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Accepted range 1–1000. Invalid or out-of-range values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1000,
              "default": 1
            }
          },
          {
            "name": "sortBy",
            "in": "query",
            "required": false,
            "description": "Field: pingAt, responseTimeMs, or createdAt. Direction: asc or desc. Invalid values are ignored.",
            "schema": {
              "type": "string",
              "enum": [
                "pingAt_asc",
                "pingAt_desc",
                "responseTimeMs_asc",
                "responseTimeMs_desc",
                "createdAt_asc",
                "createdAt_desc"
              ]
            }
          },
          {
            "name": "anonymity",
            "in": "query",
            "required": false,
            "description": "Exact filter: transparent, anonymous, elite, or unknown. Unknown values usually return an empty array.",
            "schema": {
              "type": "string",
              "enum": [
                "transparent",
                "anonymous",
                "elite",
                "unknown"
              ]
            }
          },
          {
            "name": "anonymityLevel",
            "in": "query",
            "required": false,
            "description": "Deprecated alias: high = anonymous or elite, low = transparent. Exact filter. Unknown values usually return an empty array.",
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "low"
              ],
              "deprecated": true
            }
          },
          {
            "name": "protocol",
            "in": "query",
            "required": false,
            "description": "Exact filter such as http, https, or socks5. Unknown values usually return an empty array.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "list",
            "in": "query",
            "required": false,
            "description": "Named generated-list preset: https (HTTPS-capable), fast (rounded latency below 1000 ms), stable (rounded seven-day uptime at least 90% with at least 50 checks), or anonymous (anonymous or elite). Unknown values are ignored."
          },
          {
            "name": "uptimeRating",
            "in": "query",
            "required": false,
            "description": "Minimum 24-hour uptime percentage, 1–100. Invalid values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "responseTimeMs",
            "in": "query",
            "required": false,
            "description": "Maximum HTTP response time in milliseconds, 1–10000. Invalid values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000
            }
          },
          {
            "name": "checkedWithinMin",
            "in": "query",
            "required": false,
            "description": "Maximum age of pingAt in minutes, 1–1440. Snapshot defaults to 30; timestamps later than request time are excluded by this freshness filter.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1440
            }
          },
          {
            "name": "format",
            "in": "query",
            "required": false,
            "description": "json, csv, txt, or txt-proto. Unknown values fall back to JSON.",
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "csv",
                "txt",
                "txt-proto"
              ],
              "default": "json"
            }
          },
          {
            "name": "download",
            "in": "query",
            "required": false,
            "description": "When present for a supported format, returns an attachment.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Free proxies in the requested format.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/FreeProxy"
                  }
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              },
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/api/free-proxy/snapshot": {
      "get": {
        "operationId": "snapshotFreeProxies",
        "summary": "Retrieve one consistent fresh free-proxy snapshot",
        "description": "Returns the whole matching live dataset in one response. checkedWithinMin defaults to 30 and invalid values return 400.",
        "security": [],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Case-insensitive ISO-2 code. The value is uppercased; no aliases are applied.",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 2
            }
          },
          {
            "name": "anonymity",
            "in": "query",
            "required": false,
            "description": "Exact filter: transparent, anonymous, elite, or unknown. Unknown values usually return an empty array.",
            "schema": {
              "type": "string",
              "enum": [
                "transparent",
                "anonymous",
                "elite",
                "unknown"
              ]
            }
          },
          {
            "name": "anonymityLevel",
            "in": "query",
            "required": false,
            "description": "Deprecated alias: high = anonymous or elite, low = transparent. Exact filter. Unknown values usually return an empty array.",
            "schema": {
              "type": "string",
              "enum": [
                "high",
                "low"
              ],
              "deprecated": true
            }
          },
          {
            "name": "protocol",
            "in": "query",
            "required": false,
            "description": "Exact filter such as http, https, or socks5. Unknown values usually return an empty array.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "list",
            "in": "query",
            "required": false,
            "description": "Named generated-list preset: https (HTTPS-capable), fast (rounded latency below 1000 ms), stable (rounded seven-day uptime at least 90% with at least 50 checks), or anonymous (anonymous or elite). Unknown values are ignored.",
            "schema": {}
          },
          {
            "name": "uptimeRating",
            "in": "query",
            "required": false,
            "description": "Minimum 24-hour uptime percentage, 1–100. Invalid values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100
            }
          },
          {
            "name": "responseTimeMs",
            "in": "query",
            "required": false,
            "description": "Maximum HTTP response time in milliseconds, 1–10000. Invalid values are ignored.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000
            }
          },
          {
            "name": "checkedWithinMin",
            "in": "query",
            "required": false,
            "description": "Maximum age of pingAt in minutes, 1–1440. Snapshot defaults to 30; timestamps later than request time are excluded by this freshness filter.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 1440,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A consistent matching snapshot, capped at 20,000 rows.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "generatedAt",
                    "count",
                    "totalCount",
                    "truncated",
                    "maxAgeMin",
                    "proxies"
                  ],
                  "properties": {
                    "generatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "count": {
                      "type": "integer"
                    },
                    "totalCount": {
                      "type": "integer"
                    },
                    "truncated": {
                      "type": "boolean"
                    },
                    "maxAgeMin": {
                      "type": "integer",
                      "minimum": 1,
                      "maximum": 1440
                    },
                    "proxies": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/FreeProxy"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens": {
      "get": {
        "operationId": "listTokens",
        "summary": "List the caller's existing tokens",
        "description": "Returns customer-visible metadata and credentials for the caller's existing tokens. A paged list; see the packageId filter and the shared pagination rule.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Integer 1-100; default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's page.nextCursor, sent back unchanged.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "unlimited or ppg.",
            "schema": {
              "type": "string",
              "enum": [
                "unlimited",
                "ppg"
              ]
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "active, expired, or disabled.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "expired",
                "disabled"
              ]
            }
          },
          {
            "name": "packageId",
            "in": "query",
            "required": false,
            "description": "An owned package's public numeric ID. An unknown or foreign value returns an empty list. A malformed value is INVALID_PACKAGE_ID.",
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owned token metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenList"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}": {
      "get": {
        "operationId": "getToken",
        "summary": "Read one owned token",
        "description": "Returns the identical customer-visible shape as a matching element of GET /tokens, including proxy credentials.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The owned token.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "$ref": "#/components/schemas/Token"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}/usage": {
      "get": {
        "operationId": "getTokenUsage",
        "summary": "Read usage for one owned token",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "from",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "to",
            "in": "query",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "groupBy",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "hour",
                "day",
                "month"
              ],
              "default": "day"
            }
          },
          {
            "name": "include",
            "in": "query",
            "description": "Comma-separated optional expansions. Use `domains` for destinations, or `charges` with a PPG token and `groupBy=hour` for persisted charge components.",
            "schema": {
              "type": "string",
              "example": "domains,charges"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Customer-visible traffic summary and sparse ascending buckets.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}/location": {
      "get": {
        "operationId": "getTokenLocation",
        "summary": "Read one token's saved and effective location",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Saved target, current effective location, and change status.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenLocationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "changeTokenLocation",
        "summary": "Choose a movable token's location (datacenter/ISP region+city, or mobile city+carrier)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No precondition header is required or honored. The latest committed, successful write becomes the new state; the latest write always wins. `409 CONCURRENT_CHANGE` means another write to the same token or package landed at the same moment -- retry the same request. A rotating datacenter/ISP or Multi-location token moves at once, with no waiting period. A static datacenter/ISP token, or a standard US Shared Mobile token, uses its once-a-week or once-per-48-hour allowance; a repeat inside that window is `409 CHANGE_LIMIT` with `nextChangeAt`. A PUT identical to the currently saved target succeeds without a new change. For any mobile token, a carrier with no working phone in the chosen city falls back to another carrier in the same city; `effective` reports which one.",
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "region",
                      "city"
                    ],
                    "properties": {
                      "region": {
                        "type": "string",
                        "description": "A canonical US state slug from location/options, or \"any\"."
                      },
                      "city": {
                        "type": "string",
                        "description": "A canonical city slug from location/options, or \"any\"."
                      },
                      "country": {
                        "type": "string",
                        "const": "us"
                      }
                    }
                  },
                  {
                    "type": "object",
                    "additionalProperties": false,
                    "required": [
                      "city",
                      "carrier"
                    ],
                    "properties": {
                      "city": {
                        "type": "string"
                      },
                      "carrier": {
                        "type": "string"
                      },
                      "country": {
                        "type": "string",
                        "const": "us"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated location state.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenLocationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}/location/options": {
      "get": {
        "operationId": "listTokenLocationOptions",
        "summary": "List the values currently usable for a token's next location field",
        "description": "A complete list: every currently usable option, always with page.nextCursor: null.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "level",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "region",
                "city",
                "carrier"
              ]
            },
            "description": "Datacenter/ISP: region, then city. Mobile: city, then carrier."
          },
          {
            "name": "region",
            "in": "query",
            "description": "Required when level=city for a datacenter/ISP token.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "city",
            "in": "query",
            "description": "Required when level=carrier for a mobile token.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usable values for this token, right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenLocationOptionsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}/rotation": {
      "put": {
        "operationId": "changeTokenRotation",
        "summary": "Change a rotating token's rotation interval",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No precondition header is required or honored. The latest committed, successful write becomes the new state; the latest write always wins. `409 CONCURRENT_CHANGE` means another write to the same token or package landed at the same moment -- retry the same request. A Multi-location token always answers `409 NOT_SUPPORTED`: the phone the proxy is on sets its interval.",
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "intervalSec"
                ],
                "properties": {
                  "intervalSec": {
                    "type": "integer",
                    "description": "Must be one of the token's own rotation.options."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated rotation interval.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenRotationResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tokens/{tokenId}/new-ip": {
      "post": {
        "operationId": "replaceTokenIp",
        "summary": "Get a new IP in the same location (static datacenter/ISP only)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No request body. Reuses the token's own saved location on every attempt, including a retry. Uses the once-a-week replacement allowance; a repeat inside that week is `409 CHANGE_LIMIT` with `nextChangeAt`. This is the one write that is not safe to repeat blindly: on an ambiguous result, read GET .../location first and retry only when `nextChangeAt` is not already later than the current time.",
        "parameters": [
          {
            "name": "tokenId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Updated location state, with a new effective IP.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenLocationResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/packages": {
      "get": {
        "operationId": "listPackages",
        "summary": "List owned proxy packages",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owned packages.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageList"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/packages/{packageId}": {
      "get": {
        "operationId": "getPackage",
        "summary": "Read one owned proxy package",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "packageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Owned package.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/packages/{packageId}/allowed-ips": {
      "get": {
        "operationId": "getPackageAllowedIps",
        "summary": "Read a package's allowed-IP list",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "packageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The package's allowed-IP list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageAllowedIpsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "setPackageAllowedIps",
        "summary": "Set a package's whole allowed-IP list",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No precondition header is required or honored. The latest committed, successful write becomes the new state; the latest write always wins. `409 CONCURRENT_CHANGE` means another write to the same token or package landed at the same moment -- retry the same request. All-or-nothing: one invalid IP rejects the whole request. Send {\"ips\": []} to clear the list. Limited to 20 writes per 60 seconds per package, in addition to the account-wide key limit.",
        "parameters": [
          {
            "name": "packageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": false,
                "required": [
                  "ips"
                ],
                "properties": {
                  "ips": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "description": "Exact public IPv4 literal. IPv6 is unsupported; contact support."
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageAllowedIpsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "415": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/packages/{packageId}/allowed-ips/{ip}": {
      "put": {
        "operationId": "addPackageAllowedIp",
        "summary": "Add one IP to a package's allowed-IP list",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No precondition header is required or honored. The latest committed, successful write becomes the new state; the latest write always wins. `409 CONCURRENT_CHANGE` means another write to the same token or package landed at the same moment -- retry the same request. No request body. Adding an IP already active is a successful no-op. Limited to 20 writes per 60 seconds per package.",
        "parameters": [
          {
            "name": "packageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "ip",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Exact public IPv4 literal."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageAllowedIpsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "removePackageAllowedIp",
        "summary": "Remove one IP from a package's allowed-IP list",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "description": "No precondition header is required or honored. The latest committed, successful write becomes the new state; the latest write always wins. `409 CONCURRENT_CHANGE` means another write to the same token or package landed at the same moment -- retry the same request. No request body. Removing an IP already absent is a successful no-op; the row is only marked revoked, so audit history stays. Limited to 20 writes per 60 seconds per package.",
        "parameters": [
          {
            "name": "packageId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "ip",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Exact public IPv4 literal."
          }
        ],
        "responses": {
          "200": {
            "description": "Updated list.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PackageAllowedIpsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pay-per-gb/pools": {
      "get": {
        "operationId": "listPayPerGbPools",
        "summary": "List customer-selectable pay-per-GB pools",
        "description": "A complete list: every selectable pool, priced at the account's current plan discount, with its usable hubs and supported geo levels. Always page.nextCursor: null; takes no limit or cursor.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Selectable pools.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPerGbPoolsResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pay-per-gb/geo": {
      "get": {
        "operationId": "listPayPerGbGeoOptions",
        "summary": "Discover geo targeting values for one or more pay-per-GB pools",
        "description": "A paged list: the country, region, or city values every requested pool supports, selecting pools by authKey.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "pool",
            "in": "query",
            "required": true,
            "description": "Required, non-empty. Each value is a customer-selectable pay-per-GB pool's authKey. An unknown or non-selectable key returns INVALID_POOL.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "level",
            "in": "query",
            "required": true,
            "description": "Required. One of country, region, or city.",
            "schema": {
              "type": "string",
              "enum": [
                "country",
                "region",
                "city"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "description": "Lowercase geo slug. Required when level is region or city.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "description": "Lowercase geo slug. Optional; with level city, narrows the list to one state.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "description": "Optional search text, trimmed and capped at 80 characters.",
            "schema": {
              "type": "string",
              "maxLength": 80
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Integer 1-100; default 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "required": false,
            "description": "The previous page's page.nextCursor, sent back unchanged.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Geo options available to every requested pool.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPerGbGeoResponse"
                }
              }
            }
          },
          "400": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/pay-per-gb/balance": {
      "get": {
        "operationId": "getPayPerGbBalance",
        "summary": "Read account balance and plan",
        "description": "Returns the authenticated account's current billing balance and plan, to explain an insufficient-balance proxy error.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [],
        "responses": {
          "200": {
            "description": "Account balance and plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPerGbBalanceResponse"
                }
              }
            }
          },
          "401": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "405": {
            "description": "A method this path does not support.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Request failed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "lit_<secret>",
        "description": "API key created in /users/settings."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message",
              "requestId",
              "docsUrl"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "requestId": {
                "type": "string"
              },
              "docsUrl": {
                "type": "string",
                "format": "uri"
              },
              "nextChangeAt": {
                "type": "string",
                "format": "date-time",
                "description": "Present only on a 409 CHANGE_LIMIT."
              }
            }
          }
        }
      },
      "FreeProxy": {
        "type": "object",
        "properties": {
          "protocol": {
            "type": [
              "string",
              "null"
            ]
          },
          "host": {
            "type": [
              "string",
              "null"
            ]
          },
          "port": {
            "type": [
              "integer",
              "null"
            ]
          },
          "externalIp": {
            "type": [
              "string",
              "null"
            ]
          },
          "geoCountry": {
            "type": [
              "string",
              "null"
            ]
          },
          "geoCountryFlagEmoji": {
            "type": [
              "string",
              "null"
            ]
          },
          "geoRegion": {
            "type": [
              "string",
              "null"
            ]
          },
          "geoCity": {
            "type": [
              "string",
              "null"
            ]
          },
          "geoTimezone": {
            "type": [
              "string",
              "null"
            ]
          },
          "asn": {
            "type": [
              "integer",
              "string",
              "null"
            ]
          },
          "asnOrgName": {
            "type": [
              "string",
              "null"
            ]
          },
          "https": {
            "type": [
              "boolean",
              "null"
            ]
          },
          "anonymity": {
            "type": [
              "string",
              "null"
            ]
          },
          "anonymityRating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "anonymityLevel": {
            "type": [
              "string",
              "null"
            ]
          },
          "anonymityLevelRating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "responseTimeMs": {
            "type": [
              "number",
              "null"
            ]
          },
          "responseTimeRating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "uptimeRating": {
            "type": [
              "integer",
              "null"
            ]
          },
          "uptime7d": {
            "type": [
              "number",
              "null"
            ]
          },
          "checks7d": {
            "type": [
              "integer",
              "null"
            ]
          },
          "uptime24h": {
            "type": [
              "number",
              "null"
            ]
          },
          "checks24h": {
            "type": [
              "integer",
              "null"
            ]
          },
          "sourcesCount": {
            "type": [
              "integer",
              "null"
            ]
          },
          "responseTimeMedianMs": {
            "type": [
              "number",
              "null"
            ]
          },
          "lastAliveAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "createdAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "pingAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Token": {
        "type": "object",
        "required": [
          "id",
          "type",
          "status",
          "createdAt",
          "ingress",
          "packageId",
          "ipAuth",
          "username",
          "password"
        ],
        "example": {
          "id": 12345,
          "type": "unlimited",
          "status": "active",
          "label": "Production crawler",
          "createdAt": "2026-08-01T10:15:00.000Z",
          "expiresAt": "2026-12-01T00:00:00.000Z",
          "ingress": {
            "hub": "us-11",
            "protocol": "http",
            "mode": "assigned",
            "host": "hub-us-11-1.litport.net",
            "port": 31337,
            "status": "available"
          },
          "packageId": 45,
          "ipAuth": {
            "host": "hub-us-11-1.litport.net",
            "port": 31338
          },
          "location": {
            "country": "us",
            "region": "new-york",
            "city": "new-york-city"
          },
          "rotation": {
            "intervalSec": 600,
            "options": [
              600,
              1800,
              3600
            ],
            "changeable": true
          },
          "username": "proxy-username",
          "password": "proxy-password"
        },
        "properties": {
          "id": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "enum": [
              "unlimited",
              "ppg"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "expired",
              "disabled"
            ]
          },
          "label": {
            "type": [
              "string",
              "null"
            ]
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "ingress": {
            "type": "object",
            "required": [
              "hub",
              "protocol",
              "mode"
            ],
            "description": "A ppg token is request-selected: hub, protocol and pool are chosen per request, and the ports come from GET /pay-per-gb/pools. An unlimited token is assigned exactly one endpoint and always reports its resolved host and port.",
            "properties": {
              "hub": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "protocol": {
                "type": "string",
                "enum": [
                  "http",
                  "socks5"
                ]
              },
              "mode": {
                "type": "string",
                "enum": [
                  "request-selected",
                  "assigned"
                ]
              },
              "supportedProtocols": {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "description": "request-selected tokens only."
              },
              "host": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "assigned tokens only. null when status is hub-unavailable."
              },
              "port": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "assigned tokens only. null when status is hub-unavailable."
              },
              "status": {
                "type": "string",
                "enum": [
                  "available",
                  "hub-unavailable"
                ],
                "description": "assigned tokens only. hub-unavailable means the token names a hub that is no longer in service; contact support to move it."
              }
            }
          },
          "poolSelection": {
            "type": "object",
            "required": [
              "mode"
            ],
            "properties": {
              "mode": {
                "type": "string",
                "enum": [
                  "auth-parameter",
                  "fixed"
                ]
              },
              "pool": {
                "anyOf": [
                  {
                    "type": "object",
                    "required": [
                      "authKey",
                      "name"
                    ],
                    "properties": {
                      "authKey": {
                        "type": "string"
                      },
                      "name": {
                        "type": "string"
                      }
                    },
                    "additionalProperties": false
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "additionalProperties": false
          },
          "packageId": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Public numeric package ID when this token belongs to an owned package, otherwise null."
          },
          "ipAuth": {
            "anyOf": [
              {
                "type": "object",
                "required": [
                  "host",
                  "port"
                ],
                "properties": {
                  "host": {
                    "type": "string"
                  },
                  "port": {
                    "type": "integer"
                  }
                },
                "additionalProperties": false
              },
              {
                "type": "null"
              }
            ],
            "description": "The token's passwordless endpoint, or null when it has none right now. It accepts connections only from the package's allowed IPs."
          },
          "location": {
            "description": "Present only on a token whose location can move. See Tokens: Location.",
            "anyOf": [
              {
                "type": "object",
                "required": [
                  "country",
                  "region",
                  "city"
                ],
                "properties": {
                  "country": {
                    "const": "us"
                  },
                  "region": {
                    "type": "string"
                  },
                  "city": {
                    "type": "string"
                  }
                }
              },
              {
                "type": "object",
                "required": [
                  "country",
                  "city",
                  "carrier"
                ],
                "properties": {
                  "country": {
                    "const": "us"
                  },
                  "city": {
                    "type": "string"
                  },
                  "carrier": {
                    "type": "string"
                  }
                }
              }
            ]
          },
          "rotation": {
            "type": "object",
            "description": "Present on every token that rotates on a timer. See Tokens: Rotation.",
            "required": [
              "intervalSec",
              "options",
              "changeable"
            ],
            "properties": {
              "intervalSec": {
                "type": "integer"
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "changeable": {
                "type": "boolean"
              }
            }
          },
          "rotateUrl": {
            "type": "string",
            "format": "uri",
            "description": "Private Device only. As secret as the password next to it."
          },
          "username": {
            "type": "string"
          },
          "password": {
            "type": "string"
          }
        }
      },
      "TokenList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Token"
            }
          },
          "page": {
            "type": "object",
            "properties": {
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "TokenLocationResponse": {
        "type": "object",
        "required": [
          "data"
        ],
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "tokenId",
              "kind",
              "mode",
              "target",
              "effective",
              "status",
              "canChangeNow",
              "nextChangeAt"
            ],
            "properties": {
              "tokenId": {
                "type": "integer"
              },
              "kind": {
                "type": "string",
                "enum": [
                  "datacenter",
                  "isp",
                  "mobile"
                ]
              },
              "mode": {
                "type": "string",
                "enum": [
                  "rotating",
                  "static"
                ]
              },
              "target": {
                "type": "object",
                "description": "Datacenter/ISP: {country, region, city}, either \"any\". Mobile: {country, city, carrier}."
              },
              "effective": {
                "type": [
                  "object",
                  "null"
                ],
                "description": "The current IP's actual location, or null when not yet known."
              },
              "status": {
                "type": "string",
                "enum": [
                  "pending",
                  "ready",
                  "unavailable",
                  "package-inactive",
                  "allowance-exhausted"
                ]
              },
              "canChangeNow": {
                "type": "boolean"
              },
              "nextChangeAt": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "date-time",
                "description": "When a used-up change allowance resets, if it is currently used up."
              }
            }
          }
        }
      },
      "TokenLocationOptionsResponse": {
        "type": "object",
        "required": [
          "data",
          "page"
        ],
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeoOption"
            }
          },
          "page": {
            "type": "object",
            "properties": {
              "nextCursor": {
                "const": null
              }
            }
          }
        }
      },
      "TokenRotationResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "tokenId",
              "intervalSec",
              "options",
              "changeable"
            ],
            "properties": {
              "tokenId": {
                "type": "integer"
              },
              "intervalSec": {
                "type": "integer"
              },
              "options": {
                "type": "array",
                "items": {
                  "type": "integer"
                }
              },
              "changeable": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "Package": {
        "type": "object",
        "required": [
          "id",
          "status",
          "product",
          "country",
          "quantity",
          "addOns",
          "limits",
          "renewsAt",
          "endsAt",
          "tokenIds"
        ],
        "example": {
          "id": 45,
          "status": "active",
          "product": {
            "key": "dc-shared-rotating",
            "name": "DC Shared Rotating"
          },
          "country": "us",
          "quantity": 2,
          "addOns": [
            "high-speed"
          ],
          "limits": {
            "speedMbps": 20,
            "connections": 300,
            "requestsPerSec": 25
          },
          "renewsAt": "2027-01-01T00:00:00.000Z",
          "endsAt": null,
          "tokenIds": [
            12345,
            12346
          ]
        },
        "properties": {
          "id": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "awaiting-payment",
              "active",
              "suspended",
              "ended",
              "setup-failed"
            ]
          },
          "product": {
            "type": "object",
            "properties": {
              "key": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "name": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          },
          "country": {
            "type": [
              "string",
              "null"
            ]
          },
          "quantity": {
            "type": [
              "integer",
              "null"
            ]
          },
          "addOns": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "high-speed",
                "more-allowed-ips",
                "multi-location"
              ]
            }
          },
          "limits": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "speedMbps": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "connections": {
                    "type": [
                      "integer",
                      "null"
                    ]
                  },
                  "requestsPerSec": {
                    "type": [
                      "number",
                      "null"
                    ]
                  }
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "renewsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "endsAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "tokenIds": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          }
        }
      },
      "PackageList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Package"
            }
          },
          "page": {
            "type": "object",
            "properties": {
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "PackageResponse": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Package"
          }
        }
      },
      "PackageAllowedIpsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "packageId",
              "limit",
              "ips",
              "available",
              "unavailableCode"
            ],
            "properties": {
              "packageId": {
                "type": "integer"
              },
              "limit": {
                "type": "integer",
                "enum": [
                  1,
                  50
                ]
              },
              "ips": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "available": {
                "type": "boolean"
              },
              "unavailableCode": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "UsageCache": {
        "type": "object",
        "description": "Cache outcomes and successfully served free cached bytes for the period. Byte and saved-cost values are base-10 decimal strings so clients do not lose precision. `savedCostUnits` is present only for PPG tokens and is omitted for unlimited tokens.",
        "required": [
          "hits",
          "misses",
          "bypasses",
          "hitRate",
          "freeUploadedBytes",
          "freeDownloadedBytes",
          "freeTotalBytes"
        ],
        "properties": {
          "hits": {
            "type": "integer",
            "minimum": 0,
            "description": "Eligible requests served from the cache."
          },
          "misses": {
            "type": "integer",
            "minimum": 0,
            "description": "Eligible requests fetched from the origin because no usable entry was present."
          },
          "bypasses": {
            "type": "integer",
            "minimum": 0,
            "description": "Requests that did not use the cache."
          },
          "hitRate": {
            "type": "number",
            "minimum": 0,
            "maximum": 1,
            "description": "hits divided by hits plus misses; zero when there are no hits or misses."
          },
          "freeUploadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Base-10 decimal string of cached bytes uploaded by the customer."
          },
          "freeDownloadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Base-10 decimal string of cached bytes downloaded by the customer."
          },
          "freeTotalBytes": {
            "type": "string",
            "pattern": "^[0-9]+$",
            "description": "Base-10 decimal string equal to freeUploadedBytes plus freeDownloadedBytes."
          },
          "savedCostUnits": {
            "type": "string",
            "pattern": "^[0-9]+(?:\\.\\d+)?$",
            "description": "Base-10 decimal string of the PPG charge avoided at the historical price. Omitted for unlimited tokens."
          }
        }
      },
      "UsageTotals": {
        "type": "object",
        "required": [
          "requests",
          "uploadedBytes",
          "downloadedBytes",
          "totalBytes",
          "cache"
        ],
        "properties": {
          "requests": {
            "type": "integer"
          },
          "uploadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "downloadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "totalBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "cache": {
            "$ref": "#/components/schemas/UsageCache"
          }
        }
      },
      "UsageDomainItem": {
        "type": "object",
        "properties": {
          "protocol": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "tcp",
              "udp",
              null
            ]
          },
          "destination": {
            "type": "string"
          },
          "port": {
            "type": [
              "integer",
              "null"
            ]
          },
          "requests": {
            "type": "integer"
          },
          "uploadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "downloadedBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "totalBytes": {
            "type": "string",
            "pattern": "^[0-9]+$"
          },
          "lastSeenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "firstSeenAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "UsageDomainBreakdown": {
        "type": "object",
        "properties": {
          "limit": {
            "type": "integer",
            "const": 150
          },
          "totalDestinationCount": {
            "type": "integer"
          },
          "displayedCount": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean"
          },
          "range": {
            "type": "object",
            "properties": {
              "from": {
                "type": "string",
                "format": "date-time"
              },
              "to": {
                "type": "string",
                "format": "date-time"
              },
              "timezone": {
                "type": "string",
                "const": "UTC"
              },
              "periodClamped": {
                "type": "boolean"
              },
              "endClamped": {
                "type": "boolean"
              }
            }
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/UsageDomainItem"
            }
          },
          "other": {
            "$ref": "#/components/schemas/UsageDomainItem"
          }
        }
      },
      "UsageResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "tokenId": {
                "type": "integer"
              },
              "range": {
                "type": "object"
              },
              "trafficBasis": {
                "type": "string",
                "enum": [
                  "customer_chargeable",
                  "observed"
                ],
                "description": "`customer_chargeable` for PPG tokens and `observed` for unlimited tokens."
              },
              "summary": {
                "$ref": "#/components/schemas/UsageTotals"
              },
              "buckets": {
                "type": "array",
                "items": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/UsageTotals"
                    },
                    {
                      "type": "object"
                    }
                  ]
                }
              },
              "domainBreakdown": {
                "$ref": "#/components/schemas/UsageDomainBreakdown"
              }
            }
          }
        }
      },
      "PayPerGbHub": {
        "type": "object",
        "required": [
          "id",
          "name",
          "hostname"
        ],
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "hostname": {
            "type": "string"
          }
        }
      },
      "PayPerGbPool": {
        "type": "object",
        "required": [
          "name",
          "proxiesType",
          "authKey",
          "pricePerGb",
          "httpPort",
          "socks5Port",
          "hubs",
          "geoLevels"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "proxiesType": {
            "type": "string"
          },
          "authKey": {
            "type": "string",
            "description": "The pool-<auth-key> value for the PPG proxy username."
          },
          "pricePerGb": {
            "type": "string",
            "pattern": "^[0-9]+(?:\\.\\d+)?$",
            "description": "Base-10 decimal string, already adjusted for the account's plan discount."
          },
          "httpPort": {
            "type": "integer"
          },
          "socks5Port": {
            "type": "integer"
          },
          "hubs": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayPerGbHub"
            }
          },
          "geoLevels": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "country",
                "region",
                "city"
              ]
            },
            "description": "Broadest first. Empty when this pool has no geo targeting."
          }
        }
      },
      "PayPerGbPoolsResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayPerGbPool"
            }
          },
          "page": {
            "type": "object",
            "properties": {
              "nextCursor": {
                "const": null
              }
            }
          }
        }
      },
      "GeoOption": {
        "type": "object",
        "required": [
          "value",
          "label"
        ],
        "properties": {
          "value": {
            "type": "string",
            "description": "The exact lowercase slug to send as the matching country, region, or city proxy-username parameter."
          },
          "label": {
            "type": "string"
          },
          "emoji": {
            "type": "string",
            "description": "Present only for some country-level options."
          },
          "region": {
            "type": "string",
            "description": "Present on city options: the slug of the city's parent state. Send it as the region proxy-username parameter together with the city, because city slugs repeat across states."
          },
          "regionLabel": {
            "type": "string",
            "description": "Present on city options: the display name of the parent state."
          }
        }
      },
      "PayPerGbGeoResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GeoOption"
            }
          },
          "page": {
            "type": "object",
            "properties": {
              "nextCursor": {
                "type": [
                  "string",
                  "null"
                ]
              }
            }
          }
        }
      },
      "PayPerGbBalanceResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "required": [
              "balance",
              "plan"
            ],
            "properties": {
              "balance": {
                "type": "object",
                "required": [
                  "unitsActive",
                  "unitsReserved",
                  "unitsAvailable",
                  "unitsExpireAt"
                ],
                "properties": {
                  "unitsActive": {
                    "type": "string",
                    "pattern": "^-?[0-9]+(?:\\.\\d+)?$"
                  },
                  "unitsReserved": {
                    "type": "string",
                    "pattern": "^[0-9]+(?:\\.\\d+)?$"
                  },
                  "unitsAvailable": {
                    "type": "string",
                    "pattern": "^-?[0-9]+(?:\\.\\d+)?$"
                  },
                  "unitsExpireAt": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              },
              "plan": {
                "type": "object",
                "required": [
                  "id",
                  "expiresAt"
                ],
                "properties": {
                  "id": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "expiresAt": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "format": "date-time"
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
