{
  "openapi": "3.1.0",
  "info": {
    "title": "PapaProxy.net API",
    "version": "0.1.0",
    "summary": "Manage proxies, orders, and billing for your PapaProxy.net account.",
    "description": "The PapaProxy.net REST API exposes the same operations as the Dashboard: price quotes, orders, IP top-ups, proxy credentials, IP whitelisting, rotating-proxy sessions, wallet, support tickets, and webhooks.\n\n## Authentication\n\nPass an API key as a bearer token:\n\n``\nAuthorization: Bearer <api_key>\n``\n\nCreate keys in the Dashboard under Settings → API keys (https://papaproxy.net/account_new/settings#api-keys) or with the `/api/v1/customers/me/api-keys` endpoints. Each key has an explicit set of scopes, and an endpoint is only available when the key holds the scope it requires.\n\nA few endpoints work without a key: `GET /api/v1/billing/countries`, `GET /api/v1/billing/composite/pricing-info`, `POST /api/v1/billing/composite/auto-plan`, and `POST /api/v1/billing/composite/quote`.\n\n## Conventions\n\n- Money is always an integer number of cents (USD).\n- Endpoints that charge your wallet accept an `idempotency_key`; retrying with the same key never charges twice.\n- Countries are ISO 3166-1 alpha-2 codes (`DE`, `GB`, `US`). `GET /api/v1/billing/countries` lists the codes that are currently available.\n\n## More resources\n\n- Developer guide and MCP server setup: https://papaproxy.net/developers.php\n- Markdown brief for AI agents: https://papaproxy.net/developers.md\n- Interactive “try it” console (requires sign-in): https://papaproxy.net/account_new/docs",
    "contact": {
      "name": "PapaProxy.net support",
      "url": "https://papaproxy.net/account_new/tickets/new",
      "email": "support@papaproxy.net"
    },
    "termsOfService": "https://papaproxy.net/docs/terms_of_use.php"
  },
  "paths": {
    "/api/v1/customers/me/api-keys": {
      "get": {
        "tags": [
          "API keys"
        ],
        "summary": "List API keys",
        "description": "List the customer's API keys.",
        "operationId": "listApiKeys",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ApiKeyResponse"
                  },
                  "type": "array"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "API keys"
        ],
        "summary": "Create an API key",
        "description": "Create a new API key with the given scopes. The secret is returned only once, in this response — store it securely.",
        "operationId": "createApiKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApiKeyCreateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiKeyCreatedResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customers/me/api-keys/{key_id}": {
      "delete": {
        "tags": [
          "API keys"
        ],
        "summary": "Revoke an API key",
        "description": "Revoke one of your API keys. Requests made with it fail immediately afterward.",
        "operationId": "revokeApiKey",
        "parameters": [
          {
            "name": "key_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Key Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/countries": {
      "get": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "List available countries",
        "description": "List countries with their ISO 3166-1 alpha-2 codes, numeric IDs, and the number of IPs currently available.\n\nNo API key required. Pass the `code` straight to `segments[].country` in quote and order requests. Countries are sorted by available IPs, most first. Defaults: `product_kind=proxy_datacenter`, `geo_source=maxmind` (use the same `geo_source` in quote and order requests).",
        "operationId": "listCountries",
        "parameters": [
          {
            "name": "product_kind",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Product kind for live availability: proxy_datacenter or proxy_isp",
              "title": "Product Kind"
            },
            "description": "Product: proxy_datacenter or proxy_isp"
          },
          {
            "name": "geo_source",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "description": "Geo source the country tags are scoped to: maxmind or ripe",
              "title": "Geo Source"
            },
            "description": "Geo source the country tags are scoped to: maxmind or ripe"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CountriesResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/api/v1/billing/composite/pricing-info": {
      "get": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "Get pricing terms",
        "description": "Volume-discount tiers, term discounts, order minimums, included concurrent connections, and add-on prices — everything a calculator needs to show discount thresholds before requesting a quote.\n\nNo API key required. The figures are for display only; quote and order responses are authoritative.",
        "operationId": "getPricingInfo",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompositePricingInfoResponse"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/api/v1/billing/composite/auto-plan": {
      "post": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "Distribute IPs across countries",
        "description": "Spread a total IP count across the countries that are currently in stock (the “Country mix” option). Optionally exclude countries with `excluded_countries` (ISO codes).\n\nNo API key required and no charge. Pass the returned `segments` to the quote endpoint for pricing and to the order endpoint to purchase.",
        "operationId": "autoPlan",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompositeAutoPlanRequestIn"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompositeAutoPlanResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": []
      }
    },
    "/api/v1/billing/composite/quote": {
      "post": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "Get a price quote",
        "description": "Price a set of segments (`[{country, count}]`) for a given product and term. The quote is non-binding (`binding=false`); segments that can't be fulfilled are listed in `errors` without failing the request.\n\nThe API key is optional. With a key from an account that has a partner discount, the response also includes `retail_*` and `partner_discount_*` fields; otherwise those fields are null.\n\nPricing: the per-IP rate depends on the total IP count across all segments (volume tiers); term discounts apply on top. See `GET /api/v1/billing/composite/pricing-info` for the tiers.",
        "operationId": "getQuote",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompositeQuoteRequestIn"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompositeQuoteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "security": [
          {},
          {
            "HTTPBearer": []
          }
        ]
      }
    },
    "/api/v1/billing/composite/order": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Place an order",
        "description": "Buy a proxy package built from one or more segments (`[{country, count}]`). Availability and price are re-checked at order time, and a single service is created with all segments. With `use_balance=true` the order is paid from your wallet balance first; any remainder (`amount_due_cents`) is due through a payment processor. At least one IP in `whitelist_ips` is required.\n\nIdempotent: repeating the same order (same segments, or the same `idempotency_key`) returns the existing service without charging again.",
        "operationId": "createOrder",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompositeOrderRequestIn"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CompositeOrderResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/services/{service_id}/add-ips/quote": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Quote additional IPs",
        "description": "Preview adding IPs to an active service: the prorated charge for the rest of the current term and the new renewal price. No charge and no changes to the service.",
        "operationId": "quoteAddIps",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddIpsQuoteRequestIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddIpsQuoteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/services/{service_id}/add-ips": {
      "post": {
        "tags": [
          "Orders"
        ],
        "summary": "Add IPs to a service",
        "description": "Add IPs to an active service — in the same country or new ones. You're charged the prorated amount for the rest of the current term, and the renewal price increases accordingly. Idempotent on `idempotency_key`.",
        "operationId": "addIps",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddIpsRequestIn"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddIpsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/services/{service_id}/addons/available": {
      "get": {
        "tags": [
          "Add-ons"
        ],
        "summary": "List available add-ons",
        "description": "Add-ons you can buy for this service, with prices and your current wallet balance. Add-ons that are already active are not listed.",
        "operationId": "listAvailableAddons",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddonCatalogResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/services/{service_id}/addons": {
      "post": {
        "tags": [
          "Add-ons"
        ],
        "summary": "Buy an add-on",
        "description": "Buy an add-on (for example UDP, extra whitelist IPs, or extra concurrent connections) and pay from your wallet.\n\n- Send `expected_price_cents` with the total you showed the user. If it doesn't match the current price, the request fails with HTTP 409 and nothing is charged.\n- Insufficient balance returns HTTP 402 with no changes.\n- Idempotent on `idempotency_key`.",
        "operationId": "purchaseAddon",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddonPurchaseRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AddonPurchaseResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Add-ons"
        ],
        "summary": "List active add-ons",
        "description": "Active add-ons on this service: type, status, purchase price, parameters, and activation date. Canceled add-ons are not listed.",
        "operationId": "listActiveAddons",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActiveAddonListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/billing/services/{service_id}/addons/{addon_id}": {
      "delete": {
        "tags": [
          "Add-ons"
        ],
        "summary": "Cancel an add-on",
        "description": "Cancel an active add-on. Unused time may be refunded to your wallet on a prorated basis. Idempotent: canceling an add-on that is already canceled returns success.",
        "operationId": "cancelAddon",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "addon_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Addon Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DisableAddonResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/me": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get your profile",
        "description": "Requires scope `customer:read`.",
        "operationId": "getProfile",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": true,
                  "type": "object"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Account"
        ],
        "summary": "Update your profile",
        "description": "Update your name or phone number. The email address can't be changed. Requires scope `customer:write`.",
        "operationId": "updateProfile",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProfileUpdateRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/wallet/balance": {
      "get": {
        "tags": [
          "Wallet"
        ],
        "summary": "Get wallet balance",
        "description": "Your prepaid wallet balance, calculated from the transaction ledger. Accounts that have never topped up report `balance_cents=0`. Requires scope `wallet:read`.",
        "operationId": "getWalletBalance",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletBalanceResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/wallet/ledger": {
      "get": {
        "tags": [
          "Wallet"
        ],
        "summary": "List wallet transactions",
        "description": "List wallet transactions (paginated, newest first).\n\nEntries linked to a specific service carry its `service_id`.\nRequires scope `wallet:read`.",
        "operationId": "listWalletTransactions",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "title": "Offset"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 200,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LedgerEntryListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/wallet/deposit/init": {
      "post": {
        "tags": [
          "Wallet"
        ],
        "summary": "Top up your wallet",
        "description": "Start a wallet top-up and get a checkout URL. The wallet is credited after the payment processor confirms the payment — check the transaction list to see the credit. Pass `idempotency_key` to make retries safe.\n\nIf the selected payment method requires identity verification that hasn't been completed, the response is HTTP 403 with `detail.error = \"kyc_required\"`.\n\nRequires scope `wallet:deposit`.",
        "operationId": "createDeposit",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositInitRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DepositInitResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/catalog": {
      "get": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "List products",
        "description": "The product catalog with your prices. Requires scope `catalog:read`.",
        "operationId": "listProducts",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "title": "Offset"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/catalog/{product_id}": {
      "get": {
        "tags": [
          "Catalog and pricing"
        ],
        "summary": "Get a product",
        "description": "Product details with your price. Requires scope `catalog:read`.",
        "operationId": "getProduct",
        "parameters": [
          {
            "name": "product_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Product Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "List your services",
        "description": "List your services (paginated).\n\nRequires scope `services:read`.",
        "operationId": "listServices",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0,
              "title": "Offset"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 100,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Buy a service",
        "description": "Buy a catalog product and pay from your wallet balance. Idempotent: repeating the call with the same product and parameters returns the existing service without charging again. For proxy packages built from countries, use `POST /api/v1/billing/composite/order`.\n\nRequires scope `services:write`.",
        "operationId": "createService",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceCreateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Get a service",
        "description": "Get details of one of your services.\n\nRequires scope `services:read`.",
        "operationId": "getService",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/renew": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Renew a service",
        "description": "Renew a service for another term and pay from your wallet balance. Pass `period_months` (1, 3, 6, or 12) to apply the term discount. Requires scope `services:write`.",
        "operationId": "renewService",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ServiceRenewRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceStatusResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/cancel": {
      "post": {
        "tags": [
          "Services"
        ],
        "summary": "Cancel a service",
        "description": "Cancel (terminate) a service. Idempotent.\n\nUnused paid time may be refunded to your wallet on a pro-rata basis.\nRequires scope `services:write`.",
        "operationId": "cancelService",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ServiceStatusResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/invoices/{invoice_id}/pdf": {
      "get": {
        "tags": [
          "Wallet"
        ],
        "summary": "Download an invoice (PDF)",
        "description": "Download the PDF of one of your invoices. Requires scope `wallet:read`.",
        "operationId": "getInvoicePdf",
        "parameters": [
          {
            "name": "invoice_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Invoice Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/ips": {
      "get": {
        "tags": [
          "Proxy access"
        ],
        "summary": "List proxy IPs",
        "description": "List the proxy IP endpoints of one of your services.\n\nRequires scope `services:read`.",
        "operationId": "listProxyIps",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProxyIpListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/auth": {
      "get": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Get proxy credentials",
        "description": "Get the proxy connection credentials for one of your services.\n\nThe password is masked by default; pass `reveal=true` to receive it\nin plain text. Requires scope `services:read`.",
        "operationId": "getProxyCredentials",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "reveal",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false,
              "title": "Reveal"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProxyAuthResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Change proxy credentials",
        "description": "Update proxy credentials — rotate the password or change the login.\n\nIdempotent: a repeated identical payload produces the same state.\nWhen rotating, the new password is returned exactly once in the\nresponse body. Requires scope `services:write`.",
        "operationId": "updateProxyCredentials",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ProxyAuthUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProxyAuthResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/config": {
      "get": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Get rotating gateway settings",
        "description": "Gateway hostnames and ports (HTTP, HTTPS, SOCKS5) of a rotating proxy service. Requires scope `services:read`.",
        "operationId": "getRotatingConfig",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RotatingConfigResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/whitelist": {
      "get": {
        "tags": [
          "Proxy access"
        ],
        "summary": "List whitelisted IPs",
        "description": "List the IP whitelist entries of one of your proxy services.\n\nRequires scope `services:read`.",
        "operationId": "listWhitelist",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhitelistResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Add a whitelisted IP",
        "description": "Add a single IPv4 address to the service's IP whitelist.\n\nOnly single addresses are accepted (no CIDR subnets).\nRequires scope `services:write`.",
        "operationId": "addWhitelistIp",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WhitelistAddRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhitelistResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Remove a whitelisted IP",
        "description": "Remove an IP address from the service's IP whitelist.\n\nRequires scope `services:write`.",
        "operationId": "removeWhitelistIp",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "ip_or_cidr",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "IP address to remove from the whitelist",
              "title": "Ip Or Cidr"
            },
            "description": "IP address to remove from the whitelist"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WhitelistResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/usage": {
      "get": {
        "tags": [
          "Services"
        ],
        "summary": "Get usage statistics",
        "description": "Request and connection statistics for a service over a time window. Requires scope `usage:read`.",
        "operationId": "getServiceUsage",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "start",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "Start of the window (ISO 8601)",
              "title": "Start"
            },
            "description": "Start of the window (ISO 8601)"
          },
          {
            "name": "end",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "date-time",
              "description": "End of the window (ISO 8601)",
              "title": "End"
            },
            "description": "End of the window (ISO 8601)"
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProxyUsageResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/refresh-status": {
      "get": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Check IP refresh cost",
        "description": "Check whether the next IP refresh for this service is free or paid.\n\nRead-only. Requires scope `services:read`.",
        "operationId": "getRefreshStatus",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReallocationStatusResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/refresh": {
      "post": {
        "tags": [
          "Proxy access"
        ],
        "summary": "Refresh proxy IPs",
        "description": "Replace the IPs of a proxy service. Pass `target_ips` to replace only specific addresses, or omit it to refresh the whole list. Scheduled refreshes are free; an off-cycle refresh is charged to your wallet — check `GET …/proxy/refresh-status` first. Pass `idempotency_key` so a retried call can't charge twice.\n\nRequires scope `services:write`.",
        "operationId": "refreshIps",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerRefreshIpsRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReallocationResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/sessions": {
      "get": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "List sticky sessions",
        "description": "List sticky sessions for a rotating proxy service.\n\nRequires scope `services:read`.",
        "operationId": "listStickySessions",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickySessionsResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/sessions/{sid}/rotate": {
      "post": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Rotate a sticky session",
        "description": "Force a new exit IP for one sticky session. Free; this is not an IP list refresh. Requires scope `services:write`.",
        "operationId": "rotateStickySession",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "sid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyRotateResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/sessions/{sid}": {
      "delete": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "End a sticky session",
        "description": "Requires scope `services:write`.",
        "operationId": "deleteStickySession",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          },
          {
            "name": "sid",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Sid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/purge": {
      "post": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "End all sticky sessions",
        "description": "Requires scope `services:write`.",
        "operationId": "purgeStickySessions",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyPurgeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/mode": {
      "get": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Get session mode",
        "description": "Current session mode of a rotating service: `rotating` (new exit IP per request), `sticky`, or `pinned`. Requires scope `services:read`.",
        "operationId": "getStickyMode",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyModeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Set session mode",
        "description": "Switch between `rotating`, `sticky`, and `pinned` modes. `pin` is required for `pinned`. Requires scope `services:write`.",
        "operationId": "setStickyMode",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StickyModeUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyModeResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/services/{service_id}/proxy/sticky/ttl": {
      "get": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Get sticky session duration",
        "description": "Requires scope `services:read`.",
        "operationId": "getStickyTtl",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyTtlResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Set sticky session duration",
        "description": "Set how long a sticky session keeps the same exit IP, in seconds (minimum 30). Requires scope `services:write`.",
        "operationId": "setStickyTtl",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StickyTtlUpdateRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyTtlResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Rotating sessions"
        ],
        "summary": "Reset sticky session duration",
        "description": "Return the sticky session duration to the default. Requires scope `services:write`.",
        "operationId": "resetStickyTtl",
        "parameters": [
          {
            "name": "service_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Service Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StickyTtlResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/tickets": {
      "get": {
        "tags": [
          "Support tickets"
        ],
        "summary": "List support tickets",
        "description": "List your support tickets, newest first.\n\nRequires scope `tickets:read`.",
        "operationId": "listTickets",
        "parameters": [
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 0,
              "title": "Offset"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketListResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Support tickets"
        ],
        "summary": "Open a support ticket",
        "description": "Create a new support ticket.\n\nRequires scope `tickets:write`.",
        "operationId": "createTicket",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketCreateRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/tickets/{ticket_id}": {
      "get": {
        "tags": [
          "Support tickets"
        ],
        "summary": "Get a support ticket",
        "description": "Get a single ticket with its full message history.\n\nRequires scope `tickets:read`.",
        "operationId": "getTicket",
        "parameters": [
          {
            "name": "ticket_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Ticket Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/tickets/{ticket_id}/reply": {
      "post": {
        "tags": [
          "Support tickets"
        ],
        "summary": "Reply to a support ticket",
        "description": "Reply to an existing ticket. Closed tickets cannot receive replies.\n\nRequires scope `tickets:write`.",
        "operationId": "replyTicket",
        "parameters": [
          {
            "name": "ticket_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Ticket Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TicketReplyRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TicketDetailResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/webhooks/events": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook event types",
        "operationId": "listWebhookEventTypes",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEventTypesResponse"
                }
              }
            }
          }
        },
        "description": "Event types you can subscribe a webhook endpoint to."
      }
    },
    "/api/v1/customer/webhooks": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook endpoints",
        "operationId": "listWebhooks",
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/WebhookEndpointResponse"
                  },
                  "type": "array"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook endpoint",
        "operationId": "createWebhook",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointCreate"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointCreatedResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "description": "Register an HTTPS URL to receive event notifications. The signing secret is returned only once, in this response."
      }
    },
    "/api/v1/customer/webhooks/{endpoint_id}": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Get a webhook endpoint",
        "operationId": "getWebhook",
        "parameters": [
          {
            "name": "endpoint_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Endpoint Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Update a webhook endpoint",
        "operationId": "updateWebhook",
        "parameters": [
          {
            "name": "endpoint_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Endpoint Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEndpointUpdate"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook endpoint",
        "operationId": "deleteWebhook",
        "parameters": [
          {
            "name": "endpoint_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Endpoint Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/webhooks/{endpoint_id}/deliveries": {
      "get": {
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook deliveries",
        "operationId": "listWebhookDeliveries",
        "parameters": [
          {
            "name": "endpoint_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Endpoint Id"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 50,
              "minimum": 1,
              "default": 50,
              "title": "Limit"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookDeliveryResponse"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "description": "Recent delivery attempts for this endpoint, with response status codes."
      }
    },
    "/api/v1/customer/webhooks/{endpoint_id}/test": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test event",
        "operationId": "sendWebhookTest",
        "parameters": [
          {
            "name": "endpoint_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Endpoint Id"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "description": "Send a test event to this endpoint to check that it receives and verifies deliveries."
      }
    },
    "/api/v1/customer/webhooks/deliveries/{delivery_id}/redeliver": {
      "post": {
        "tags": [
          "Webhooks"
        ],
        "summary": "Redeliver an event",
        "operationId": "redeliverWebhook",
        "parameters": [
          {
            "name": "delivery_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid",
              "title": "Delivery Id"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryResponse"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        },
        "description": "Send a past delivery again, for example after fixing your endpoint."
      }
    }
  },
  "components": {
    "schemas": {
      "ActiveAddonItem": {
        "properties": {
          "addon_id": {
            "type": "string",
            "format": "uuid",
            "title": "Addon Id"
          },
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "addon_type": {
            "type": "string",
            "title": "Addon Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "price_cents": {
            "type": "integer",
            "title": "Price Cents"
          },
          "nominal_price_cents": {
            "type": "integer",
            "title": "Nominal Price Cents",
            "default": 0
          },
          "params": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Params"
          },
          "activated_at": {
            "type": "string",
            "format": "date-time",
            "title": "Activated At"
          }
        },
        "type": "object",
        "required": [
          "addon_id",
          "service_id",
          "addon_type",
          "status",
          "price_cents",
          "activated_at"
        ],
        "title": "ActiveAddonItem",
        "description": "One active addon currently attached to a service."
      },
      "ActiveAddonListResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "addons": {
            "items": {
              "$ref": "#/components/schemas/ActiveAddonItem"
            },
            "type": "array",
            "title": "Addons"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "addons"
        ],
        "title": "ActiveAddonListResponse",
        "description": "Active addons for a given service."
      },
      "AddIpsQuoteRequestIn": {
        "properties": {
          "segments": {
            "items": {
              "$ref": "#/components/schemas/AddIpsSegmentRequestIn"
            },
            "type": "array",
            "minItems": 1,
            "title": "Segments",
            "description": "One or more segments to add"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "segments"
        ],
        "title": "AddIpsQuoteRequestIn",
        "description": "Request to preview adding IPs to a service."
      },
      "AddIpsQuoteResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeSegmentQuote"
            },
            "type": "array",
            "title": "Segments",
            "description": "Per-segment pricing breakdown for the added IPs"
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/CompositeQuoteError"
            },
            "type": "array",
            "title": "Errors",
            "description": "Segments that can't be fulfilled; ordering them would fail with HTTP 409."
          },
          "added_ip_count": {
            "type": "integer",
            "title": "Added Ip Count",
            "description": "Total IPs across the added segments"
          },
          "monthly_price_added_cents": {
            "type": "integer",
            "title": "Monthly Price Added Cents",
            "description": "Undiscounted full-monthly cost of the added segments"
          },
          "days_remaining": {
            "type": "integer",
            "title": "Days Remaining",
            "description": "Days left in the current term."
          },
          "days_per_month": {
            "type": "integer",
            "title": "Days Per Month",
            "description": "Days per month used for proration.",
            "default": 30
          },
          "prorated_charge_cents": {
            "type": "integer",
            "title": "Prorated Charge Cents",
            "description": "Amount charged now for the remainder of the current period"
          },
          "current_price_cents": {
            "type": "integer",
            "title": "Current Price Cents",
            "description": "Service's current full-period renewal price"
          },
          "new_renewal_price_cents": {
            "type": "integer",
            "title": "New Renewal Price Cents",
            "description": "Renewal price after this top-up (current + added segments' full-period cost)"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "added_ip_count",
          "monthly_price_added_cents",
          "days_remaining",
          "prorated_charge_cents",
          "current_price_cents",
          "new_renewal_price_cents"
        ],
        "title": "AddIpsQuoteResponse",
        "description": "Non-binding preview of an add-ips top-up. No side effects."
      },
      "AddIpsRequestIn": {
        "properties": {
          "segments": {
            "items": {
              "$ref": "#/components/schemas/AddIpsSegmentRequestIn"
            },
            "type": "array",
            "minItems": 1,
            "title": "Segments",
            "description": "One or more segments to add"
          },
          "idempotency_key": {
            "type": "string",
            "minLength": 1,
            "title": "Idempotency Key",
            "description": "Client-supplied idempotency key. Must be unique per intent."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "segments",
          "idempotency_key"
        ],
        "title": "AddIpsRequestIn",
        "description": "Request to add IPs to a service."
      },
      "AddIpsResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "added_ip_count": {
            "type": "integer",
            "title": "Added Ip Count"
          },
          "charged_cents": {
            "type": "integer",
            "title": "Charged Cents",
            "description": "Prorated amount charged to the wallet"
          },
          "ledger_entry_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ledger Entry Id",
            "description": "Wallet transaction for the charge; null when nothing was charged."
          },
          "new_total_ip": {
            "type": "integer",
            "title": "New Total Ip",
            "description": "Total IP count on the service after the top-up"
          },
          "new_price_cents": {
            "type": "integer",
            "title": "New Price Cents",
            "description": "Service's new full-period renewal price"
          },
          "segments": {
            "items": {
              "additionalProperties": true,
              "type": "object"
            },
            "type": "array",
            "title": "Segments",
            "description": "All segments of the service after the top-up."
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "added_ip_count",
          "charged_cents",
          "new_total_ip",
          "new_price_cents"
        ],
        "title": "AddIpsResponse",
        "description": "Result of a successful add-ips top-up."
      },
      "AddIpsSegmentRequestIn": {
        "properties": {
          "country": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "title": "Country",
            "description": "ISO 3166-1 alpha-2 country code (\"DE\", \"GB\"). A numeric country ID from `GET /api/v1/billing/countries` is also accepted."
          },
          "count": {
            "type": "integer",
            "maximum": 10000,
            "minimum": 1,
            "title": "Count",
            "description": "Number of IPs to add (1–10000)"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "country",
          "count"
        ],
        "title": "AddIpsSegmentRequestIn",
        "description": "IPs to add in one country."
      },
      "AddonBreakdownItem": {
        "properties": {
          "addon_type": {
            "type": "string",
            "enum": [
              "extra_whitelist_ip",
              "udp_unlock",
              "extra_connections"
            ],
            "title": "Addon Type",
            "description": "Add-on type."
          },
          "quantity": {
            "type": "integer",
            "minimum": 0,
            "title": "Quantity",
            "description": "Number of units (IPs or connections; 1 for UDP)."
          },
          "unit_price_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Unit Price Cents",
            "description": "Per-unit monthly cents"
          },
          "monthly_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Monthly Cents",
            "description": "Monthly cost: quantity × unit price (UDP is a percentage of the base price)."
          }
        },
        "type": "object",
        "required": [
          "addon_type",
          "quantity",
          "unit_price_cents",
          "monthly_cents"
        ],
        "title": "AddonBreakdownItem",
        "description": "One add-on line in a quote. The sum of `monthly_cents` across items equals `addon_monthly_cents`."
      },
      "AddonCatalogItem": {
        "properties": {
          "addon_type": {
            "type": "string",
            "title": "Addon Type"
          },
          "display_name": {
            "type": "string",
            "title": "Display Name"
          },
          "description": {
            "type": "string",
            "title": "Description"
          },
          "price_cents": {
            "type": "integer",
            "title": "Price Cents"
          },
          "params_schema": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Params Schema"
          }
        },
        "type": "object",
        "required": [
          "addon_type",
          "display_name",
          "description",
          "price_cents"
        ],
        "title": "AddonCatalogItem",
        "description": "One purchasable addon from the catalog."
      },
      "AddonCatalogResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "addons": {
            "items": {
              "$ref": "#/components/schemas/AddonCatalogItem"
            },
            "type": "array",
            "title": "Addons"
          },
          "wallet_balance_cents": {
            "type": "integer",
            "title": "Wallet Balance Cents"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "addons",
          "wallet_balance_cents"
        ],
        "title": "AddonCatalogResponse",
        "description": "Available addons for a given service."
      },
      "AddonPurchaseRequest": {
        "properties": {
          "addon_type": {
            "type": "string",
            "title": "Addon Type"
          },
          "idempotency_key": {
            "type": "string",
            "title": "Idempotency Key"
          },
          "params": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Params"
          },
          "expected_price_cents": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Price Cents",
            "description": "The total charge you showed the user, in cents. If it doesn't match the current price, the request fails with HTTP 409 (PRICE_CONFIRMATION_REQUIRED) and nothing is charged. Always send it."
          }
        },
        "type": "object",
        "required": [
          "addon_type",
          "idempotency_key"
        ],
        "title": "AddonPurchaseRequest",
        "description": "Purchase an addon for a service."
      },
      "AddonPurchaseResponse": {
        "properties": {
          "addon_id": {
            "type": "string",
            "format": "uuid",
            "title": "Addon Id"
          },
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "addon_type": {
            "type": "string",
            "title": "Addon Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "price_cents": {
            "type": "integer",
            "title": "Price Cents"
          },
          "nominal_price_cents": {
            "type": "integer",
            "title": "Nominal Price Cents",
            "default": 0
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "addon_id",
          "service_id",
          "addon_type",
          "status",
          "price_cents",
          "created_at"
        ],
        "title": "AddonPurchaseResponse",
        "description": "Result of addon purchase."
      },
      "ApiKeyCreateRequest": {
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Name"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Scopes",
            "description": "Scopes granted to this key."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "name",
          "scopes"
        ],
        "title": "ApiKeyCreateRequest",
        "description": "Create a new API key."
      },
      "ApiKeyCreatedResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "key_prefix": {
            "type": "string",
            "title": "Key Prefix"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes"
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "last_used_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used Ip"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expires At"
          },
          "api_key": {
            "type": "string",
            "title": "Api Key",
            "description": "Full secret key — shown ONCE, store it now"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "key_prefix",
          "scopes",
          "is_active",
          "created_at",
          "api_key"
        ],
        "title": "ApiKeyCreatedResponse",
        "description": "Returned once on creation — includes the raw key (shown only here)."
      },
      "ApiKeyResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "key_prefix": {
            "type": "string",
            "title": "Key Prefix"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Scopes"
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "last_used_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used At"
          },
          "last_used_ip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used Ip"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expires At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "name",
          "key_prefix",
          "scopes",
          "is_active",
          "created_at"
        ],
        "title": "ApiKeyResponse",
        "description": "API-key metadata."
      },
      "CompositeAutoPlanRequestIn": {
        "properties": {
          "total_ip": {
            "type": "integer",
            "maximum": 1000000,
            "minimum": 1,
            "title": "Total Ip",
            "description": "Desired total IP count to distribute"
          },
          "product_kind": {
            "type": "string",
            "title": "Product Kind",
            "description": "Product: proxy_datacenter, proxy_isp, or proxy_personal.",
            "default": "proxy_datacenter"
          },
          "geo_source": {
            "type": "string",
            "enum": [
              "maxmind",
              "ripe"
            ],
            "title": "Geo Source",
            "description": "Geo source for country lookups",
            "default": "maxmind"
          },
          "excluded_countries": {
            "items": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "string"
                }
              ]
            },
            "type": "array",
            "title": "Excluded Countries",
            "description": "Countries to leave out, as ISO 3166-1 alpha-2 codes."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "total_ip"
        ],
        "title": "CompositeAutoPlanRequestIn",
        "description": "Request to distribute a total IP count across available countries."
      },
      "CompositeAutoPlanResponse": {
        "properties": {
          "snapshot_version": {
            "type": "string",
            "format": "uuid",
            "title": "Snapshot Version",
            "description": "Version of the availability data used for this response."
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeAutoPlanSegment"
            },
            "type": "array",
            "title": "Segments",
            "description": "Proposed per-country distribution, summing to total_ip"
          },
          "total_ip": {
            "type": "integer",
            "title": "Total Ip",
            "description": "Total IP count across all segments (echoes the request)"
          },
          "countries_used": {
            "type": "integer",
            "title": "Countries Used",
            "description": "Number of distinct countries in the plan"
          },
          "subnet_diversity": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Subnet Diversity",
            "description": "Number of distinct /24 subnets in the proposed allocation. Available for ISP proxies only; null for other products."
          }
        },
        "type": "object",
        "required": [
          "snapshot_version",
          "total_ip",
          "countries_used"
        ],
        "title": "CompositeAutoPlanResponse",
        "description": "Proposed distribution of IPs by country."
      },
      "CompositeAutoPlanSegment": {
        "properties": {
          "country": {
            "type": "integer",
            "title": "Country",
            "description": "Numeric country ID."
          },
          "country_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country Code",
            "description": "ISO 3166-1 alpha-2 country code (e.g. \"DE\")."
          },
          "count": {
            "type": "integer",
            "minimum": 1,
            "title": "Count",
            "description": "Number of IPs allocated to this country"
          }
        },
        "type": "object",
        "required": [
          "country",
          "count"
        ],
        "title": "CompositeAutoPlanSegment",
        "description": "One country's share of the auto-distributed mix."
      },
      "CompositeOrderRequestIn": {
        "properties": {
          "product_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Product Id",
            "description": "Optional catalog product to base the order on. When omitted, the product is selected by `product_kind`."
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeSegmentRequestIn"
            },
            "type": "array",
            "minItems": 1,
            "title": "Segments",
            "description": "One or more segments forming the mix"
          },
          "product_kind": {
            "type": "string",
            "title": "Product Kind",
            "description": "Product: proxy_datacenter, proxy_isp, or proxy_personal.",
            "default": "proxy_datacenter"
          },
          "period_months": {
            "type": "integer",
            "title": "Period Months",
            "description": "Term length in months (1, 3, 6, or 12). Longer terms get a discount. Default: 1.",
            "default": 1
          },
          "whitelist_ips": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Whitelist Ips",
            "description": "IPv4 addresses to whitelist at order time. Proxy orders need at least one; without it the request fails with HTTP 422 and nothing is charged."
          },
          "auto_renew": {
            "type": "boolean",
            "title": "Auto Renew",
            "description": "Renew the service automatically when the term ends. Default: true.",
            "default": true
          },
          "use_balance": {
            "type": "boolean",
            "title": "Use Balance",
            "description": "Pay from your wallet balance first. Default: false — the full amount is due through a payment processor (see `amount_due_cents`).",
            "default": false
          },
          "geo_source": {
            "type": "string",
            "enum": [
              "maxmind",
              "ripe"
            ],
            "title": "Geo Source",
            "description": "Geo source for country lookups: maxmind (geolocation) or ripe (RIR allocation). Default maxmind.",
            "default": "maxmind"
          },
          "idempotency_key": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Idempotency Key",
            "description": "Optional client-supplied idempotency key"
          },
          "promo_code": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Promo Code",
            "description": "Optional promo code. The discount applies to the first term only; renewals are charged at the regular price."
          },
          "trial": {
            "type": "boolean",
            "title": "Trial",
            "description": "Order the paid 48-hour trial instead of a full term.",
            "default": false
          },
          "extra_whitelist_count": {
            "type": "integer",
            "maximum": 10000,
            "minimum": 0,
            "title": "Extra Whitelist Count",
            "description": "Paid whitelist IPs beyond the free allowance. Included in the charge.",
            "default": 0
          },
          "udp_unlock": {
            "type": "boolean",
            "title": "Udp Unlock",
            "description": "Add the UDP add-on. Included in the charge.",
            "default": false
          },
          "extra_connections_count": {
            "type": "integer",
            "maximum": 10000,
            "minimum": 0,
            "title": "Extra Connections Count",
            "description": "Paid concurrent connections beyond those included. Included in the charge.",
            "default": 0
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "segments"
        ],
        "title": "CompositeOrderRequestIn",
        "description": "Order request. `segments[].country` accepts ISO 3166-1 alpha-2 codes. Repeating the same segments is treated as the same order (idempotent)."
      },
      "CompositeOrderResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id",
            "description": "Created service ID"
          },
          "status": {
            "type": "string",
            "title": "Status",
            "description": "Service status (active, pending, …)"
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeSegmentQuote"
            },
            "type": "array",
            "title": "Segments",
            "description": "Per-segment breakdown as ordered"
          },
          "total_ip": {
            "type": "integer",
            "title": "Total Ip"
          },
          "total_price_cents": {
            "type": "integer",
            "title": "Total Price Cents",
            "description": "Discounted total charged for the full period in integer cents"
          },
          "period_months": {
            "type": "integer",
            "title": "Period Months",
            "description": "Billing period length in months (1/3/6/12)",
            "default": 1
          },
          "discount_pct": {
            "type": "integer",
            "title": "Discount Pct",
            "description": "Applied period discount as a whole percentage (0/10/15/20)",
            "default": 0
          },
          "monthly_price_cents": {
            "type": "integer",
            "title": "Monthly Price Cents",
            "description": "Undiscounted monthly total (sum of segment prices) in integer cents",
            "default": 0
          },
          "balance_applied_cents": {
            "type": "integer",
            "title": "Balance Applied Cents",
            "description": "Amount paid from your wallet balance, in cents. Zero when `use_balance` is false.",
            "default": 0
          },
          "amount_due_cents": {
            "type": "integer",
            "title": "Amount Due Cents",
            "description": "Amount still due through a payment processor, in cents. Zero when the balance covers the order.",
            "default": 0
          },
          "invoice_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invoice Url"
          },
          "payment_required": {
            "type": "boolean",
            "title": "Payment Required",
            "default": false
          },
          "intent_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Intent Id"
          },
          "promo_code_applied": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Promo Code Applied",
            "description": "Promo code applied to the order, if any."
          },
          "promo_discount_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Promo Discount Cents",
            "description": "Promo discount applied to the order, in cents.",
            "default": 0
          },
          "total_before_promo_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Total Before Promo Cents",
            "description": "Pre-promo total when a promo was applied; null otherwise."
          },
          "trial": {
            "type": "boolean",
            "title": "Trial",
            "description": "True when the service is a paid trial.",
            "default": false
          },
          "trial_period_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Trial Period Days",
            "description": "Trial length in days; null for regular orders."
          },
          "addon_monthly_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Addon Monthly Cents",
            "description": "Monthly cost of add-ons bought with the order, in cents.",
            "default": 0
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "status",
          "total_ip",
          "total_price_cents"
        ],
        "title": "CompositeOrderResponse",
        "description": "Created order."
      },
      "CompositePricingInfoResponse": {
        "properties": {
          "volume_tiers": {
            "items": {
              "$ref": "#/components/schemas/VolumeTierConfig"
            },
            "type": "array",
            "title": "Volume Tiers",
            "description": "Volume-discount tiers, ascending by `min_ips`."
          },
          "period_discounts": {
            "additionalProperties": {
              "type": "integer"
            },
            "type": "object",
            "title": "Period Discounts",
            "description": "Period-months (string key) -> whole-percentage discount"
          },
          "min_ips_per_segment": {
            "type": "integer",
            "minimum": 1,
            "title": "Min Ips Per Segment",
            "description": "Minimum IP count for a single segment to be accepted"
          },
          "min_ips_per_order": {
            "type": "integer",
            "minimum": 1,
            "title": "Min Ips Per Order",
            "description": "Minimum total IP count (summed across segments) for an order"
          },
          "conn_cap_tiers": {
            "items": {
              "$ref": "#/components/schemas/ConnCapTierBreakpoint"
            },
            "type": "array",
            "title": "Conn Cap Tiers",
            "description": "Included concurrent connections by IP count."
          },
          "whitelist_free_quota": {
            "type": "integer",
            "title": "Whitelist Free Quota",
            "description": "Whitelist IPs included free with each service.",
            "default": 0
          },
          "extra_whitelist_ip_price_cents": {
            "type": "integer",
            "title": "Extra Whitelist Ip Price Cents",
            "description": "Monthly price per whitelist IP beyond the free allowance, in cents.",
            "default": 0
          },
          "free_refresh_days": {
            "type": "integer",
            "title": "Free Refresh Days",
            "description": "Interval, in days, between free scheduled IP list refreshes.",
            "default": 0
          },
          "trial": {
            "$ref": "#/components/schemas/TrialSettings",
            "description": "Settings of the paid 48-hour trial: whether it is available, its length, and its price coefficient."
          }
        },
        "type": "object",
        "required": [
          "volume_tiers",
          "period_discounts",
          "min_ips_per_segment",
          "min_ips_per_order"
        ],
        "title": "CompositePricingInfoResponse",
        "description": "Pricing terms for display: volume-discount tiers, term discounts, order minimums, included concurrent connections, and add-on prices. Quote and order responses remain authoritative."
      },
      "CompositeQuoteError": {
        "properties": {
          "country": {
            "type": "integer",
            "title": "Country"
          },
          "message": {
            "type": "string",
            "title": "Message"
          }
        },
        "type": "object",
        "required": [
          "country",
          "message"
        ],
        "title": "CompositeQuoteError",
        "description": "An error for a segment that is unavailable or invalid."
      },
      "CompositeQuoteRequestIn": {
        "properties": {
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeSegmentRequestIn"
            },
            "type": "array",
            "minItems": 1,
            "title": "Segments",
            "description": "One or more segments forming the mix"
          },
          "product_kind": {
            "type": "string",
            "title": "Product Kind",
            "description": "Product: proxy_datacenter, proxy_isp, or proxy_personal.",
            "default": "proxy_datacenter"
          },
          "period_months": {
            "type": "integer",
            "title": "Period Months",
            "description": "Term length in months (1, 3, 6, or 12). Longer terms get a discount. Default: 1.",
            "default": 1
          },
          "geo_source": {
            "type": "string",
            "enum": [
              "maxmind",
              "ripe"
            ],
            "title": "Geo Source",
            "description": "Geo source for country lookups: maxmind (geolocation) or ripe (RIR allocation). Default maxmind.",
            "default": "maxmind"
          },
          "promo_code": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "null"
              }
            ],
            "title": "Promo Code",
            "description": "Optional promo code, applied after volume and term discounts."
          },
          "trial": {
            "type": "boolean",
            "title": "Trial",
            "description": "Price the paid 48-hour trial instead of a full term.",
            "default": false
          },
          "extra_whitelist_count": {
            "type": "integer",
            "maximum": 10000,
            "minimum": 0,
            "title": "Extra Whitelist Count",
            "description": "Paid whitelist IPs beyond the free allowance.",
            "default": 0
          },
          "udp_unlock": {
            "type": "boolean",
            "title": "Udp Unlock",
            "description": "Include the UDP add-on (a percentage of the base price).",
            "default": false
          },
          "extra_connections_count": {
            "type": "integer",
            "maximum": 10000,
            "minimum": 0,
            "title": "Extra Connections Count",
            "description": "Paid concurrent connections beyond those included.",
            "default": 0
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "segments"
        ],
        "title": "CompositeQuoteRequestIn",
        "description": "Quote request. `segments[].country` accepts ISO 3166-1 alpha-2 codes."
      },
      "CompositeQuoteResponse": {
        "properties": {
          "snapshot_version": {
            "type": "string",
            "format": "uuid",
            "title": "Snapshot Version",
            "description": "Version of the availability data used for this quote."
          },
          "built_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Built At",
            "description": "When the availability data was last updated (UTC)."
          },
          "binding": {
            "type": "boolean",
            "title": "Binding",
            "description": "Always false — quotation is non-binding",
            "default": false
          },
          "segments": {
            "items": {
              "$ref": "#/components/schemas/CompositeSegmentQuote"
            },
            "type": "array",
            "title": "Segments",
            "description": "Per-segment pricing breakdown"
          },
          "errors": {
            "items": {
              "$ref": "#/components/schemas/CompositeQuoteError"
            },
            "type": "array",
            "title": "Errors",
            "description": "Errors for unavailable/invalid segments"
          },
          "total_ip": {
            "type": "integer",
            "title": "Total Ip",
            "description": "Total IP count across all valid segments",
            "default": 0
          },
          "total_price_cents": {
            "type": "integer",
            "title": "Total Price Cents",
            "description": "Discounted total charged for the full period in integer cents. Equals monthly_price_cents x period_months x (1 - discount).",
            "default": 0
          },
          "unit_base_cents": {
            "type": "integer",
            "title": "Unit Base Cents",
            "description": "Volume-tier base unit price applied (cents per IP)",
            "default": 0
          },
          "period_months": {
            "type": "integer",
            "title": "Period Months",
            "description": "Billing period length in months (1/3/6/12)",
            "default": 1
          },
          "discount_pct": {
            "type": "integer",
            "title": "Discount Pct",
            "description": "Term discount as a whole percentage. The volume discount is reported in `volume_discount_pct`.",
            "default": 0
          },
          "volume_discount_pct": {
            "type": "integer",
            "title": "Volume Discount Pct",
            "description": "Volume discount as a whole percentage, for display. Term discount is reported separately in `discount_pct`; both are already included in `total_price_cents`.",
            "default": 0
          },
          "monthly_price_cents": {
            "type": "integer",
            "title": "Monthly Price Cents",
            "description": "Undiscounted monthly total (sum of segment prices) in integer cents",
            "default": 0
          },
          "retail_total_price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Retail Total Price Cents",
            "description": "Total before the partner discount, in cents. Null unless a partner discount applies."
          },
          "retail_monthly_price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Retail Monthly Price Cents",
            "description": "Monthly price before the partner discount, in cents. Null unless a partner discount applies."
          },
          "partner_discount_percent": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partner Discount Percent",
            "description": "Partner discount percentage, when it applies."
          },
          "partner_discount_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partner Discount Cents",
            "description": "Partner discount amount in cents, when it applies."
          },
          "promo_code_applied": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Promo Code Applied",
            "description": "Promo code applied to this quote, if any."
          },
          "promo_discount_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Promo Discount Cents",
            "description": "Absolute promo discount in integer cents applied to total_price_cents.",
            "default": 0
          },
          "total_before_promo_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Total Before Promo Cents",
            "description": "Pre-promo total in integer cents when a promo was applied; null when no promo."
          },
          "trial": {
            "type": "boolean",
            "title": "Trial",
            "description": "True when the quote is for the paid trial.",
            "default": false
          },
          "trial_period_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Trial Period Days",
            "description": "Trial length in days; null for regular quotes."
          },
          "trial_coefficient": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Trial Coefficient",
            "description": "Price coefficient of the trial; null for regular quotes."
          },
          "addon_monthly_cents": {
            "type": "integer",
            "minimum": 0,
            "title": "Addon Monthly Cents",
            "description": "Monthly cents from pre-purchase add-ons (whitelist + UDP + connections).",
            "default": 0
          },
          "addon_breakdown": {
            "items": {
              "$ref": "#/components/schemas/AddonBreakdownItem"
            },
            "type": "array",
            "title": "Addon Breakdown",
            "description": "Per-addon monthly line-items. Sum of monthly_cents equals addon_monthly_cents."
          },
          "trial_price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Trial Price Cents",
            "description": "Trial price in cents (before promo); null for regular quotes."
          },
          "extra_whitelist_count": {
            "type": "integer",
            "minimum": 0,
            "title": "Extra Whitelist Count",
            "description": "Paid whitelist slots included in this quote.",
            "default": 0
          },
          "extra_connections_count": {
            "type": "integer",
            "minimum": 0,
            "title": "Extra Connections Count",
            "description": "Pre-purchase extra concurrent connections included in this quote.",
            "default": 0
          },
          "udp_unlock": {
            "type": "boolean",
            "title": "Udp Unlock",
            "description": "Whether UDP unlock was included in this quote.",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "snapshot_version"
        ],
        "title": "CompositeQuoteResponse",
        "description": "Price quote."
      },
      "CompositeSegmentQuote": {
        "properties": {
          "country": {
            "type": "integer",
            "title": "Country"
          },
          "country_code": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country Code",
            "description": "ISO 3166-1 alpha-2 country code (e.g. \"DE\")."
          },
          "count": {
            "type": "integer",
            "title": "Count"
          },
          "unit_base_cents": {
            "type": "integer",
            "title": "Unit Base Cents",
            "description": "Volume-tier base unit price in integer cents per IP"
          },
          "type_multiplier": {
            "type": "number",
            "title": "Type Multiplier",
            "description": "Product multiplier applied to the base rate."
          },
          "geo_multiplier": {
            "type": "number",
            "title": "Geo Multiplier",
            "description": "Country multiplier (default 1.0)."
          },
          "segment_price_cents": {
            "type": "integer",
            "title": "Segment Price Cents",
            "description": "Segment price: count × base rate × product multiplier × country multiplier, rounded up to whole cents."
          },
          "available": {
            "type": "boolean",
            "title": "Available",
            "description": "Whether enough IPs are available for this segment."
          }
        },
        "type": "object",
        "required": [
          "country",
          "count",
          "unit_base_cents",
          "type_multiplier",
          "geo_multiplier",
          "segment_price_cents",
          "available"
        ],
        "title": "CompositeSegmentQuote",
        "description": "Pricing breakdown for one segment."
      },
      "CompositeSegmentRequestIn": {
        "properties": {
          "country": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "string"
              }
            ],
            "title": "Country",
            "description": "ISO 3166-1 alpha-2 country code (\"DE\", \"GB\"). A numeric country ID from `GET /api/v1/billing/countries` is also accepted."
          },
          "count": {
            "type": "integer",
            "maximum": 100000,
            "minimum": 1,
            "title": "Count",
            "description": "Number of IPs for this segment (1–100000)"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "country",
          "count"
        ],
        "title": "CompositeSegmentRequestIn",
        "description": "IPs requested in one country."
      },
      "ConnCapTierBreakpoint": {
        "properties": {
          "min_ips": {
            "type": "integer",
            "minimum": 0,
            "title": "Min Ips",
            "description": "Inclusive lower bound of this bucket's IP range"
          },
          "max_ips": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Max Ips",
            "description": "Exclusive upper bound; null = no upper bound (last bucket)"
          },
          "flat_cap": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Flat Cap",
            "description": "Flat connection cap for this bucket"
          },
          "multiplier": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Multiplier",
            "description": "Per-IP connection multiplier for this bucket"
          }
        },
        "type": "object",
        "required": [
          "min_ips"
        ],
        "title": "ConnCapTierBreakpoint",
        "description": "Included concurrent connections for an IP-count range `[min_ips, max_ips)`. Either `flat_cap` (a fixed number) or `multiplier` (IP count × multiplier) is set."
      },
      "CountriesResponse": {
        "properties": {
          "geo_source": {
            "type": "string",
            "title": "Geo Source",
            "description": "Geo source the country list is scoped to (maxmind/ripe)"
          },
          "product_kind": {
            "type": "string",
            "title": "Product Kind",
            "description": "Product kind the availability counts are computed for"
          },
          "countries": {
            "items": {
              "$ref": "#/components/schemas/CountryRef"
            },
            "type": "array",
            "title": "Countries",
            "description": "Available countries, most stock first"
          }
        },
        "type": "object",
        "required": [
          "geo_source",
          "product_kind"
        ],
        "title": "CountriesResponse",
        "description": "Countries you can order."
      },
      "CountryRef": {
        "properties": {
          "code": {
            "type": "string",
            "title": "Code",
            "description": "ISO 3166-1 alpha-2 code (e.g. 'DE', 'GB')"
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Country name (e.g. 'Germany')"
          },
          "tag_id": {
            "type": "integer",
            "title": "Tag Id",
            "description": "Numeric country ID (the ISO code is accepted everywhere this ID is)."
          },
          "available": {
            "type": "integer",
            "title": "Available",
            "description": "IPs currently available in this country"
          }
        },
        "type": "object",
        "required": [
          "code",
          "name",
          "tag_id",
          "available"
        ],
        "title": "CountryRef",
        "description": "A country you can order, with its code, ID, and current availability."
      },
      "CustomerProfile": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "email": {
            "type": "string",
            "title": "Email"
          },
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "phone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone"
          },
          "is_verified": {
            "type": "boolean",
            "title": "Is Verified"
          },
          "kyc_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Kyc Status"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "locale": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Locale"
          },
          "has_password": {
            "type": "boolean",
            "title": "Has Password",
            "default": true
          },
          "oauth_provider": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Oauth Provider",
            "description": "Sign-in provider used for the account, if any."
          },
          "account_type": {
            "type": "string",
            "title": "Account Type",
            "default": "personal"
          },
          "company_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Company Name"
          },
          "address_line1": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Address Line1"
          },
          "address_line2": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Address Line2"
          },
          "city": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "City"
          },
          "state": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "State"
          },
          "postcode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Postcode"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "tax_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tax Id"
          },
          "partner_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Partner Status",
            "description": "Status of your affiliate partner profile, if any."
          }
        },
        "type": "object",
        "required": [
          "id",
          "email",
          "name",
          "phone",
          "is_verified",
          "kyc_status",
          "created_at"
        ],
        "title": "CustomerProfile",
        "description": "Your account profile."
      },
      "CustomerRefreshIpsRequest": {
        "properties": {
          "idempotency_key": {
            "type": "string",
            "title": "Idempotency Key",
            "description": "Unique key for this refresh intent; retries with the same key return the original result and never charge twice."
          },
          "target_ips": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target Ips",
            "description": "Specific currently-allocated IPs to replace. Omit to refresh the entire allocation."
          }
        },
        "type": "object",
        "required": [
          "idempotency_key"
        ],
        "title": "CustomerRefreshIpsRequest",
        "description": "Request body for refreshing (rotating) the IPs of a proxy service."
      },
      "DepositInitRequest": {
        "properties": {
          "gateway": {
            "type": "string",
            "maxLength": 64,
            "minLength": 1,
            "title": "Gateway",
            "description": "Payment gateway: stripe | heleket | freekassa | onepayment"
          },
          "amount_cents": {
            "type": "integer",
            "exclusiveMinimum": 0,
            "title": "Amount Cents",
            "description": "Amount in integer cents"
          },
          "idempotency_key": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Idempotency Key",
            "description": "Optional client-supplied idempotency key"
          },
          "currency": {
            "type": "string",
            "maxLength": 3,
            "minLength": 3,
            "title": "Currency",
            "default": "USD"
          },
          "order_metadata": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "string"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Order Metadata",
            "description": "Optional order details to attach to the payment."
          },
          "return_url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ],
            "title": "Return Url",
            "description": "Relative path to return to after a canceled or failed payment (for example `/wallet`). Must start with `/`."
          },
          "success_url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048
              },
              {
                "type": "null"
              }
            ],
            "title": "Success Url",
            "description": "Relative path to return to after a successful payment. Must start with `/`."
          },
          "save_card": {
            "type": "boolean",
            "title": "Save Card",
            "description": "Save the card for automatic top-ups (card payments via Stripe only).",
            "default": false
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "gateway",
          "amount_cents"
        ],
        "title": "DepositInitRequest",
        "description": "Initiate a top-up deposit."
      },
      "DepositInitResponse": {
        "properties": {
          "payment_url": {
            "type": "string",
            "title": "Payment Url"
          },
          "our_order_id": {
            "type": "string",
            "title": "Our Order Id"
          },
          "amount_cents": {
            "type": "integer",
            "title": "Amount Cents"
          },
          "currency": {
            "type": "string",
            "title": "Currency",
            "default": "USD"
          },
          "provider_tx_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Tx Id"
          },
          "checkout_kind": {
            "type": "string",
            "title": "Checkout Kind",
            "default": "redirect"
          },
          "allowed_payment_methods": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Allowed Payment Methods",
            "description": "Payment methods allowed for this top-up, when restricted (for example `[\"card\"]`). Null means no restriction."
          },
          "paypal_remaining_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Paypal Remaining Cents",
            "description": "Remaining PayPal limit for this account, in cents. Null when there is no limit."
          }
        },
        "type": "object",
        "required": [
          "payment_url",
          "our_order_id",
          "amount_cents"
        ],
        "title": "DepositInitResponse",
        "description": "Top-up checkout details. When `checkout_kind` is `redirect`, open `payment_url`. When it is `paddle_js`, `payment_url` is empty and the payment is completed in the Paddle.js overlay using `provider_tx_id`."
      },
      "DisableAddonResponse": {
        "properties": {
          "addon_id": {
            "type": "string",
            "format": "uuid",
            "title": "Addon Id"
          },
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "addon_type": {
            "type": "string",
            "title": "Addon Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "refund_cents": {
            "type": "integer",
            "title": "Refund Cents",
            "description": "Prorated refund credited to the wallet for the unused portion of the current billing period (0 when nothing was refunded).",
            "default": 0
          }
        },
        "type": "object",
        "required": [
          "addon_id",
          "service_id",
          "addon_type",
          "status",
          "message"
        ],
        "title": "DisableAddonResponse",
        "description": "Result of disabling (cancelling) an addon."
      },
      "FormatHints": {
        "properties": {
          "host_port": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Host Port"
          },
          "auth_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Auth Url"
          }
        },
        "type": "object",
        "title": "FormatHints",
        "description": "Display hints for proxy IP list rendering."
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "LedgerEntryListResponse": {
        "properties": {
          "entries": {
            "items": {
              "$ref": "#/components/schemas/LedgerEntryResponse"
            },
            "type": "array",
            "title": "Entries"
          },
          "total": {
            "type": "integer",
            "title": "Total"
          },
          "offset": {
            "type": "integer",
            "title": "Offset",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "default": 50
          }
        },
        "type": "object",
        "required": [
          "entries",
          "total"
        ],
        "title": "LedgerEntryListResponse",
        "description": "Paginated list of ledger entries."
      },
      "LedgerEntryResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "wallet_id": {
            "type": "string",
            "format": "uuid",
            "title": "Wallet Id"
          },
          "idempotency_key": {
            "type": "string",
            "title": "Idempotency Key"
          },
          "provider": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider",
            "description": "Payment processor or source of the transaction."
          },
          "provider_tx_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Provider Tx Id",
            "description": "Transaction ID at the payment processor."
          },
          "amount_cents": {
            "type": "integer",
            "title": "Amount Cents",
            "description": "Amount in integer cents"
          },
          "balance_after_cents": {
            "type": "integer",
            "title": "Balance After Cents",
            "description": "Running balance after this entry"
          },
          "entry_type": {
            "type": "string",
            "title": "Entry Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "service_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Service Id"
          },
          "usage_requests": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Usage Requests"
          },
          "usage_bytes": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Usage Bytes"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "wallet_id",
          "idempotency_key",
          "provider",
          "provider_tx_id",
          "amount_cents",
          "balance_after_cents",
          "entry_type",
          "status",
          "description",
          "service_id",
          "usage_requests",
          "usage_bytes",
          "created_at"
        ],
        "title": "LedgerEntryResponse",
        "description": "One wallet transaction."
      },
      "MeResponse": {
        "properties": {
          "customer": {
            "$ref": "#/components/schemas/CustomerProfile"
          }
        },
        "type": "object",
        "required": [
          "customer"
        ],
        "title": "MeResponse",
        "description": "Full profile of the currently authenticated customer."
      },
      "MessageResponse": {
        "properties": {
          "message": {
            "type": "string",
            "title": "Message"
          }
        },
        "type": "object",
        "required": [
          "message"
        ],
        "title": "MessageResponse",
        "description": "Generic message response."
      },
      "ProductListResponse": {
        "properties": {
          "products": {
            "items": {
              "$ref": "#/components/schemas/ProductResponse"
            },
            "type": "array",
            "title": "Products"
          },
          "total": {
            "type": "integer",
            "title": "Total"
          },
          "offset": {
            "type": "integer",
            "title": "Offset",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "default": 50
          },
          "price_book_kind": {
            "type": "string",
            "enum": [
              "retail",
              "wholesale"
            ],
            "title": "Price Book Kind",
            "default": "retail"
          }
        },
        "type": "object",
        "required": [
          "products",
          "total"
        ],
        "title": "ProductListResponse",
        "description": "Paginated product list."
      },
      "ProductParams": {
        "properties": {
          "ip_count": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ip Count"
          },
          "geo": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Geo"
          },
          "protocol": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Protocol"
          },
          "rate_limit_rps": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rate Limit Rps"
          },
          "sticky": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sticky"
          },
          "data_limit_bytes": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Data Limit Bytes",
            "description": "Data allowance in bytes, for products with a data allowance."
          },
          "traffic_gb": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Traffic Gb",
            "description": "Data allowance in GB, for products with a data allowance."
          },
          "pool_class": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "datacenter",
                  "isp"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Pool Class",
            "description": "IP pool type of the product."
          },
          "devices": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Devices"
          },
          "period_days": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period Days"
          },
          "request_package_size": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Request Package Size",
            "description": "Prepaid request count for rotating proxies (for example 2,500,000)."
          }
        },
        "type": "object",
        "title": "ProductParams",
        "description": "Product parameters; they vary by product type (for example IP count, locations, term, request allowance, or session settings)."
      },
      "ProductResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "kind": {
            "type": "string",
            "title": "Kind"
          },
          "billing_model": {
            "type": "string",
            "title": "Billing Model"
          },
          "name": {
            "type": "string",
            "title": "Name"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "params": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ProductParams"
              },
              {
                "type": "null"
              }
            ]
          },
          "price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Cents",
            "description": "Resolved retail price in cents; null if none"
          },
          "price_unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Unit"
          },
          "price_book_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Book Id",
            "description": "ID of the price list the price comes from."
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          },
          "features": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Features",
            "description": "Product features."
          }
        },
        "type": "object",
        "required": [
          "id",
          "kind",
          "billing_model",
          "name",
          "description",
          "params",
          "is_active"
        ],
        "title": "ProductResponse",
        "description": "A catalog product."
      },
      "ProfileUpdateRequest": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          },
          "phone": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 30
              },
              {
                "type": "null"
              }
            ],
            "title": "Phone"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "ProfileUpdateRequest",
        "description": "Update editable profile fields."
      },
      "ProxyAuthResponse": {
        "properties": {
          "username": {
            "type": "string",
            "title": "Username"
          },
          "password": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Password"
          },
          "protocols": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Protocols"
          },
          "endpoints": {
            "items": {
              "$ref": "#/components/schemas/ProxyEndpoint"
            },
            "type": "array",
            "title": "Endpoints"
          },
          "whitelist_ips": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Whitelist Ips"
          },
          "password_set": {
            "type": "boolean",
            "title": "Password Set",
            "default": false
          },
          "udp_enabled": {
            "type": "boolean",
            "title": "Udp Enabled",
            "default": false
          },
          "conn_cap": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conn Cap"
          },
          "whitelist_conn_limits": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "integer"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Whitelist Conn Limits"
          },
          "rotating_gateway": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/RotatingGatewayInfo"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "type": "object",
        "required": [
          "username"
        ],
        "title": "ProxyAuthResponse",
        "description": "Current proxy auth status."
      },
      "ProxyAuthUpdateRequest": {
        "properties": {
          "rotate_password": {
            "type": "boolean",
            "title": "Rotate Password",
            "default": false
          },
          "udp_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Udp Enabled"
          },
          "new_username": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 32,
                "minLength": 3,
                "pattern": "^[a-zA-Z0-9_.-]+$"
              },
              {
                "type": "null"
              }
            ],
            "title": "New Username",
            "description": "New proxy login. Must not be taken by another account."
          },
          "whitelist_ips": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Whitelist Ips",
            "deprecated": true
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "ProxyAuthUpdateRequest",
        "description": "Change proxy credentials: rotate the password or change the login. Manage the IP whitelist with the `/proxy/whitelist` endpoints."
      },
      "ProxyEndpoint": {
        "properties": {
          "protocol": {
            "type": "string",
            "title": "Protocol"
          },
          "label": {
            "type": "string",
            "title": "Label"
          },
          "scheme": {
            "type": "string",
            "title": "Scheme"
          },
          "port": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Port"
          },
          "port_whitelist": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Port Whitelist"
          },
          "http2": {
            "type": "boolean",
            "title": "Http2",
            "default": false
          },
          "udp": {
            "type": "boolean",
            "title": "Udp",
            "default": false
          },
          "noauth_only": {
            "type": "boolean",
            "title": "Noauth Only",
            "default": false
          },
          "hostname_template": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hostname Template"
          }
        },
        "type": "object",
        "required": [
          "protocol",
          "label",
          "scheme"
        ],
        "title": "ProxyEndpoint",
        "description": "Connection endpoint for one protocol. `port` accepts username/password authentication; `port_whitelist` accepts connections from whitelisted IPs without credentials. Endpoints with `noauth_only=true` work with IP whitelisting only (`port` is null). For HTTPS, `hostname_template` gives the hostname to connect to (replace `{ip_dashed}` with the IP, dots replaced by hyphens)."
      },
      "ProxyIpEntry": {
        "properties": {
          "ip": {
            "type": "string",
            "title": "Ip",
            "description": "IPv4 or IPv6 address"
          },
          "port": {
            "anyOf": [
              {
                "type": "integer",
                "maximum": 65535,
                "minimum": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Port"
          },
          "country": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Country"
          },
          "type": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Type"
          }
        },
        "type": "object",
        "required": [
          "ip"
        ],
        "title": "ProxyIpEntry",
        "description": "A single proxy IP in a service."
      },
      "ProxyIpListResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "ips": {
            "items": {
              "$ref": "#/components/schemas/ProxyIpEntry"
            },
            "type": "array",
            "title": "Ips"
          },
          "format_hints": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FormatHints"
              },
              {
                "type": "null"
              }
            ]
          },
          "geo_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Geo Source"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "ips"
        ],
        "title": "ProxyIpListResponse",
        "description": "List of proxy IPs for a service."
      },
      "ProxyUsageResponse": {
        "properties": {
          "connections": {
            "type": "integer",
            "title": "Connections",
            "default": 0
          },
          "bytes_used": {
            "type": "integer",
            "title": "Bytes Used",
            "default": 0
          },
          "window": {
            "$ref": "#/components/schemas/ProxyUsageWindow"
          }
        },
        "type": "object",
        "required": [
          "window"
        ],
        "title": "ProxyUsageResponse",
        "description": "Usage stats for a proxy service."
      },
      "ProxyUsageWindow": {
        "properties": {
          "start": {
            "type": "string",
            "format": "date-time",
            "title": "Start"
          },
          "end": {
            "type": "string",
            "format": "date-time",
            "title": "End"
          }
        },
        "type": "object",
        "required": [
          "start",
          "end"
        ],
        "title": "ProxyUsageWindow",
        "description": "Time window for usage stats."
      },
      "ReallocationResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "ip_count": {
            "type": "integer",
            "title": "Ip Count"
          },
          "charged_cents": {
            "type": "integer",
            "title": "Charged Cents"
          },
          "ledger_entry_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ledger Entry Id"
          },
          "new_ips": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "New Ips"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "ip_count",
          "charged_cents",
          "ledger_entry_id"
        ],
        "title": "ReallocationResponse",
        "description": "Result of a successful IP reallocation."
      },
      "ReallocationStatusResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "is_free": {
            "type": "boolean",
            "title": "Is Free"
          },
          "free_window_days": {
            "type": "integer",
            "title": "Free Window Days"
          },
          "days_since_start": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Days Since Start"
          },
          "next_free_refresh_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Free Refresh At"
          },
          "price_cents": {
            "type": "integer",
            "title": "Price Cents"
          },
          "is_pool_service": {
            "type": "boolean",
            "title": "Is Pool Service",
            "description": "Whether the service uses a shared IP pool."
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "is_free",
          "free_window_days",
          "days_since_start",
          "price_cents",
          "is_pool_service"
        ],
        "title": "ReallocationStatusResponse",
        "description": "Status of the next IP reallocation for a service."
      },
      "RotatingConfigResponse": {
        "properties": {
          "endpoint": {
            "type": "string",
            "title": "Endpoint"
          },
          "endpoints": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Endpoints"
          },
          "https_endpoints": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Https Endpoints"
          },
          "port": {
            "type": "integer",
            "title": "Port"
          },
          "http_ports": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Http Ports"
          },
          "socks_ports": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Socks Ports"
          },
          "sticky_http": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sticky Http"
          },
          "sticky_socks5": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sticky Socks5"
          },
          "sticky_https": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sticky Https"
          },
          "session_format": {
            "type": "string",
            "title": "Session Format",
            "default": "ip:port:username:password"
          },
          "mode": {
            "type": "string",
            "title": "Mode",
            "default": "rotating"
          },
          "sample_connection_string": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Sample Connection String"
          },
          "sample_connection_strings": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Sample Connection Strings"
          }
        },
        "type": "object",
        "required": [
          "endpoint",
          "port"
        ],
        "title": "RotatingConfigResponse",
        "description": "Connection settings of a rotating proxy service. `endpoint` and `port` are the primary HTTP gateway; the list fields contain every hostname and port for HTTP, HTTPS, and SOCKS5."
      },
      "RotatingGatewayInfo": {
        "properties": {
          "entry_hosts": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Entry Hosts"
          },
          "https_hosts": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Https Hosts"
          },
          "sticky_hosts": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Sticky Hosts"
          },
          "entry_host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Entry Host"
          },
          "https_host": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Https Host"
          },
          "http_ports": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Http Ports"
          },
          "socks_ports": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Socks Ports"
          },
          "sticky_http": {
            "type": "integer",
            "title": "Sticky Http",
            "default": 5080
          },
          "sticky_socks5": {
            "type": "integer",
            "title": "Sticky Socks5",
            "default": 4080
          },
          "sticky_https": {
            "type": "integer",
            "title": "Sticky Https",
            "default": 4443
          }
        },
        "type": "object",
        "title": "RotatingGatewayInfo",
        "description": "Rotating gateway hostnames and ports for this service. The list fields are authoritative; `entry_host` and `https_host` are the first entries. Lists are empty when a gateway type isn't available for the service."
      },
      "ServiceCreateRequest": {
        "properties": {
          "product_id": {
            "type": "string",
            "format": "uuid",
            "title": "Product Id"
          },
          "params": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Params"
          },
          "auto_renew": {
            "type": "boolean",
            "title": "Auto Renew",
            "default": true
          },
          "expected_price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expected Price Cents",
            "description": "The total charge you showed the user, in cents. Required for some products; if it's missing or doesn't match the current price, the request fails with HTTP 409 and nothing is charged."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "product_id"
        ],
        "title": "ServiceCreateRequest",
        "description": "Purchase a new service."
      },
      "ServiceCreateResponse": {
        "properties": {
          "service": {
            "$ref": "#/components/schemas/ServiceResponse"
          },
          "invoice_url": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Invoice Url"
          }
        },
        "type": "object",
        "required": [
          "service"
        ],
        "title": "ServiceCreateResponse",
        "description": "Result of service creation."
      },
      "ServiceListResponse": {
        "properties": {
          "services": {
            "items": {
              "$ref": "#/components/schemas/ServiceResponse"
            },
            "type": "array",
            "title": "Services"
          },
          "total": {
            "type": "integer",
            "title": "Total"
          },
          "offset": {
            "type": "integer",
            "title": "Offset",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "default": 50
          }
        },
        "type": "object",
        "required": [
          "services",
          "total"
        ],
        "title": "ServiceListResponse",
        "description": "Paginated service list."
      },
      "ServiceRenewRequest": {
        "properties": {
          "period_count": {
            "type": "integer",
            "maximum": 12,
            "minimum": 1,
            "title": "Period Count",
            "default": 1
          },
          "period_months": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period Months",
            "description": "Renewal term in months (1, 3, 6, or 12). Overrides `period_count` and applies the term discount."
          },
          "idempotency_key": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 128,
                "minLength": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Idempotency Key",
            "description": "Idempotency key; retries with the same key never charge twice. Can also be sent in the `Idempotency-Key` header."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "title": "ServiceRenewRequest",
        "description": "Renew a service for another term. Prefer `period_months` (1, 3, 6, or 12), which applies the term discount."
      },
      "ServiceResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "owner_type": {
            "type": "string",
            "title": "Owner Type"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "title": "Owner Id"
          },
          "product_id": {
            "type": "string",
            "format": "uuid",
            "title": "Product Id"
          },
          "product_name": {
            "type": "string",
            "title": "Product Name",
            "default": ""
          },
          "product_kind": {
            "type": "string",
            "title": "Product Kind",
            "default": ""
          },
          "product_display_name": {
            "type": "string",
            "title": "Product Display Name",
            "default": ""
          },
          "display_name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Display Name"
          },
          "owner_email": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Owner Email"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "provisioner": {
            "type": "string",
            "title": "Provisioner"
          },
          "ext_service_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ext Service Id"
          },
          "params": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Params"
          },
          "started_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Started At"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expires At"
          },
          "grace_until": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Grace Until"
          },
          "cancelled_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Cancelled At"
          },
          "usage_requests_cur": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Usage Requests Cur"
          },
          "usage_bytes_cur": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Usage Bytes Cur"
          },
          "is_trial": {
            "type": "boolean",
            "title": "Is Trial",
            "default": false
          },
          "is_auto_renew": {
            "type": "boolean",
            "title": "Is Auto Renew"
          },
          "customer_note": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customer Note"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Cents"
          },
          "price_unit": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Price Unit"
          },
          "active_addon_types": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Active Addon Types"
          },
          "renewal_price_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Renewal Price Cents",
            "description": "Forecast charge at the next auto-renewal (base price + active add-ons), same resolution as the real renewal charge. None when not applicable (see renewal_coverage)."
          },
          "renewal_coverage": {
            "type": "string",
            "title": "Renewal Coverage",
            "description": "Whether the next renewal is covered: `covered_by_balance`, `covered_by_card` (an automatic top-up will charge the saved card), `not_covered`, or `not_applicable`.",
            "default": "not_applicable"
          },
          "suspend_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Suspend Reason",
            "description": "Why the service is suspended: `quota_exhausted`, `expired`, or `other`. Null when it isn't suspended."
          },
          "next_quota_grant_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Quota Grant At",
            "description": "When the next monthly request allowance is added (rotating services), if it falls within the paid term."
          },
          "renew_allowed": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Renew Allowed",
            "description": "Whether the service can be renewed right now."
          }
        },
        "type": "object",
        "required": [
          "id",
          "owner_type",
          "owner_id",
          "product_id",
          "status",
          "provisioner",
          "ext_service_id",
          "params",
          "started_at",
          "expires_at",
          "cancelled_at",
          "usage_requests_cur",
          "usage_bytes_cur",
          "is_auto_renew",
          "created_at"
        ],
        "title": "ServiceResponse",
        "description": "A purchased service / subscription."
      },
      "ServiceStatusResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "refund_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Refund Cents"
          },
          "new_expires_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "New Expires At"
          },
          "charged_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Charged Cents"
          },
          "funding_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Funding Source"
          },
          "refund_base_cents": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Refund Base Cents"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "status",
          "message"
        ],
        "title": "ServiceStatusResponse",
        "description": "Simple status update response."
      },
      "StickyModeResponse": {
        "properties": {
          "mode": {
            "type": "string",
            "title": "Mode"
          },
          "pin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pin"
          }
        },
        "type": "object",
        "required": [
          "mode"
        ],
        "title": "StickyModeResponse",
        "description": "Session mode: `rotating`, `sticky`, or `pinned`."
      },
      "StickyModeUpdateRequest": {
        "properties": {
          "mode": {
            "type": "string",
            "enum": [
              "sticky",
              "rotating",
              "pinned"
            ],
            "title": "Mode",
            "description": "sticky | rotating | pinned"
          },
          "pin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pin",
            "description": "Exit IP:port to keep when `mode` is `pinned`."
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "mode"
        ],
        "title": "StickyModeUpdateRequest",
        "description": "New session mode. `pin` is required when `mode` is `pinned`."
      },
      "StickyPurgeResponse": {
        "properties": {
          "deleted": {
            "type": "integer",
            "title": "Deleted"
          }
        },
        "type": "object",
        "required": [
          "deleted"
        ],
        "title": "StickyPurgeResponse",
        "description": "Result of ending all sticky sessions."
      },
      "StickyRotateResponse": {
        "properties": {
          "sid": {
            "type": "string",
            "title": "Sid"
          },
          "exit": {
            "type": "string",
            "title": "Exit"
          },
          "exit_addr": {
            "type": "string",
            "title": "Exit Addr"
          },
          "status": {
            "type": "string",
            "title": "Status",
            "default": "rotated"
          }
        },
        "type": "object",
        "required": [
          "sid",
          "exit",
          "exit_addr"
        ],
        "title": "StickyRotateResponse",
        "description": "Result of moving one sticky session to a new exit IP."
      },
      "StickySession": {
        "properties": {
          "sid": {
            "type": "string",
            "title": "Sid"
          },
          "session_id": {
            "type": "string",
            "title": "Session Id"
          },
          "server": {
            "type": "string",
            "title": "Server"
          },
          "exit": {
            "type": "string",
            "title": "Exit"
          },
          "exit_addr": {
            "type": "string",
            "title": "Exit Addr"
          },
          "is_default": {
            "type": "boolean",
            "title": "Is Default",
            "default": false
          },
          "created": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created"
          },
          "last_used": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Used"
          },
          "ttl_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ttl Seconds"
          },
          "expires_at": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Expires At"
          },
          "mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Mode"
          }
        },
        "type": "object",
        "required": [
          "sid",
          "session_id",
          "server",
          "exit",
          "exit_addr"
        ],
        "title": "StickySession",
        "description": "One sticky session of a rotating proxy service."
      },
      "StickySessionsResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "username": {
            "type": "string",
            "title": "Username"
          },
          "sessions": {
            "items": {
              "$ref": "#/components/schemas/StickySession"
            },
            "type": "array",
            "title": "Sessions"
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "username",
          "sessions"
        ],
        "title": "StickySessionsResponse",
        "description": "Active sticky sessions for a rotating service."
      },
      "StickyTtlResponse": {
        "properties": {
          "ttl_seconds": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ttl Seconds"
          },
          "is_custom": {
            "type": "boolean",
            "title": "Is Custom",
            "default": false
          },
          "global_default_ttl": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Global Default Ttl"
          },
          "ttl_human": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ttl Human"
          }
        },
        "type": "object",
        "title": "StickyTtlResponse",
        "description": "Sticky session duration, in seconds."
      },
      "StickyTtlUpdateRequest": {
        "properties": {
          "seconds": {
            "type": "integer",
            "minimum": 30,
            "title": "Seconds",
            "description": "TTL override in seconds (minimum 30)"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "seconds"
        ],
        "title": "StickyTtlUpdateRequest",
        "description": "New sticky session duration, in seconds (minimum 30)."
      },
      "TicketAttachmentIn": {
        "properties": {
          "filename": {
            "type": "string",
            "maxLength": 255,
            "minLength": 1,
            "title": "Filename"
          },
          "content_type": {
            "type": "string",
            "maxLength": 127,
            "minLength": 1,
            "title": "Content Type"
          },
          "data_base64": {
            "type": "string",
            "maxLength": 28000000,
            "minLength": 1,
            "title": "Data Base64"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "filename",
          "content_type",
          "data_base64"
        ],
        "title": "TicketAttachmentIn",
        "description": "File attached to a ticket message. `data_base64` contains the file encoded in Base64; the file type is validated on upload."
      },
      "TicketAttachmentResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "message_id": {
            "type": "string",
            "format": "uuid",
            "title": "Message Id"
          },
          "uploader_type": {
            "type": "string",
            "title": "Uploader Type"
          },
          "filename": {
            "type": "string",
            "title": "Filename"
          },
          "content_type": {
            "type": "string",
            "title": "Content Type"
          },
          "size": {
            "type": "integer",
            "title": "Size"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "message_id",
          "uploader_type",
          "filename",
          "content_type",
          "size",
          "created_at"
        ],
        "title": "TicketAttachmentResponse",
        "description": "Metadata for a ticket message attachment (no binary payload)."
      },
      "TicketCreateRequest": {
        "properties": {
          "subject": {
            "type": "string",
            "maxLength": 500,
            "minLength": 1,
            "title": "Subject"
          },
          "message": {
            "type": "string",
            "maxLength": 10000,
            "minLength": 1,
            "title": "Message"
          },
          "service_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Service Id"
          },
          "attachments": {
            "items": {
              "$ref": "#/components/schemas/TicketAttachmentIn"
            },
            "type": "array",
            "maxItems": 5,
            "title": "Attachments"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "subject",
          "message"
        ],
        "title": "TicketCreateRequest",
        "description": "Create a new support ticket."
      },
      "TicketDetailResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customer Id"
          },
          "subject": {
            "type": "string",
            "title": "Subject"
          },
          "status": {
            "$ref": "#/components/schemas/TicketStatus"
          },
          "service_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Service Id"
          },
          "last_message_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Message At"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          },
          "messages": {
            "items": {
              "$ref": "#/components/schemas/TicketMessageResponse"
            },
            "type": "array",
            "title": "Messages"
          }
        },
        "type": "object",
        "required": [
          "id",
          "customer_id",
          "subject",
          "status",
          "service_id",
          "last_message_at",
          "created_at",
          "updated_at",
          "messages"
        ],
        "title": "TicketDetailResponse",
        "description": "Ticket with full message history."
      },
      "TicketListResponse": {
        "properties": {
          "tickets": {
            "items": {
              "$ref": "#/components/schemas/TicketResponse"
            },
            "type": "array",
            "title": "Tickets"
          },
          "total": {
            "type": "integer",
            "title": "Total"
          },
          "offset": {
            "type": "integer",
            "title": "Offset",
            "default": 0
          },
          "limit": {
            "type": "integer",
            "title": "Limit",
            "default": 50
          }
        },
        "type": "object",
        "required": [
          "tickets",
          "total"
        ],
        "title": "TicketListResponse",
        "description": "Paginated ticket list."
      },
      "TicketMessageResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "ticket_id": {
            "type": "string",
            "format": "uuid",
            "title": "Ticket Id"
          },
          "author_kind": {
            "type": "string",
            "title": "Author Kind"
          },
          "author_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Author Id"
          },
          "message": {
            "type": "string",
            "title": "Message"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "attachments": {
            "items": {
              "$ref": "#/components/schemas/TicketAttachmentResponse"
            },
            "type": "array",
            "title": "Attachments"
          },
          "detected_lang": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Detected Lang"
          },
          "translated_body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Translated Body"
          },
          "translation_target": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Translation Target"
          }
        },
        "type": "object",
        "required": [
          "id",
          "ticket_id",
          "author_kind",
          "author_id",
          "message",
          "created_at"
        ],
        "title": "TicketMessageResponse",
        "description": "A single message in a ticket thread."
      },
      "TicketReplyRequest": {
        "properties": {
          "message": {
            "type": "string",
            "maxLength": 10000,
            "minLength": 1,
            "title": "Message"
          },
          "attachments": {
            "items": {
              "$ref": "#/components/schemas/TicketAttachmentIn"
            },
            "type": "array",
            "maxItems": 5,
            "title": "Attachments"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "message"
        ],
        "title": "TicketReplyRequest",
        "description": "Reply to an existing ticket."
      },
      "TicketResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "customer_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Customer Id"
          },
          "subject": {
            "type": "string",
            "title": "Subject"
          },
          "status": {
            "$ref": "#/components/schemas/TicketStatus"
          },
          "service_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Service Id"
          },
          "last_message_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Message At"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "title": "Created At"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "customer_id",
          "subject",
          "status",
          "service_id",
          "last_message_at",
          "created_at",
          "updated_at"
        ],
        "title": "TicketResponse",
        "description": "A support ticket in list view."
      },
      "TicketStatus": {
        "type": "string",
        "enum": [
          "open",
          "in_progress",
          "waiting",
          "customer_replied",
          "closed"
        ],
        "title": "TicketStatus",
        "description": "Ticket status."
      },
      "TrialSettings": {
        "properties": {
          "enabled": {
            "type": "boolean",
            "title": "Enabled",
            "default": true
          },
          "period_days": {
            "type": "integer",
            "minimum": 1,
            "title": "Period Days",
            "default": 2
          },
          "tariff_coefficient": {
            "type": "number",
            "exclusiveMinimum": 0,
            "title": "Tariff Coefficient",
            "default": 2
          },
          "registration_window_enabled": {
            "type": "boolean",
            "title": "Registration Window Enabled",
            "default": false
          },
          "registration_window_days": {
            "type": "integer",
            "minimum": 1,
            "title": "Registration Window Days",
            "default": 30
          },
          "max_per_month": {
            "type": "integer",
            "minimum": 0,
            "title": "Max Per Month",
            "default": 3
          }
        },
        "type": "object",
        "title": "TrialSettings",
        "description": "Paid 48-hour trial settings: availability, length in days, and price coefficient."
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "VolumeTierConfig": {
        "properties": {
          "min_ips": {
            "type": "integer",
            "minimum": 0,
            "title": "Min Ips",
            "description": "Total-IP threshold at which this tier applies"
          },
          "price_millicents_per_ip": {
            "type": "integer",
            "minimum": 0,
            "title": "Price Millicents Per Ip",
            "description": "Per-IP price in millicents (1/1000 of a cent)"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label",
            "description": "Human-readable tier label."
          }
        },
        "type": "object",
        "required": [
          "min_ips",
          "price_millicents_per_ip"
        ],
        "title": "VolumeTierConfig",
        "description": "One volume-discount tier. `price_millicents_per_ip` is the monthly price per IP in thousandths of a cent."
      },
      "WalletBalanceResponse": {
        "properties": {
          "wallet_id": {
            "anyOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "null"
              }
            ],
            "title": "Wallet Id"
          },
          "owner_type": {
            "type": "string",
            "title": "Owner Type"
          },
          "owner_id": {
            "type": "string",
            "format": "uuid",
            "title": "Owner Id"
          },
          "balance_cents": {
            "type": "integer",
            "title": "Balance Cents",
            "description": "Available balance in integer cents"
          },
          "currency": {
            "type": "string",
            "maxLength": 3,
            "minLength": 3,
            "title": "Currency",
            "default": "USD"
          },
          "has_wallet": {
            "type": "boolean",
            "title": "Has Wallet",
            "description": "False if the account has never topped up; `balance_cents` is 0 in that case.",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "owner_type",
          "owner_id",
          "balance_cents"
        ],
        "title": "WalletBalanceResponse",
        "description": "Current wallet balance. Accounts that have never topped up have `has_wallet=false` and `balance_cents=0`."
      },
      "WebhookDeliveryResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "event_id": {
            "type": "string",
            "format": "uuid",
            "title": "Event Id"
          },
          "endpoint_id": {
            "type": "string",
            "format": "uuid",
            "title": "Endpoint Id"
          },
          "event_type": {
            "type": "string",
            "title": "Event Type"
          },
          "status": {
            "type": "string",
            "title": "Status"
          },
          "attempts": {
            "type": "integer",
            "title": "Attempts"
          },
          "next_attempt_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Next Attempt At"
          },
          "last_response_code": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Response Code"
          },
          "last_response_body": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Response Body"
          },
          "last_error": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Last Error"
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "event_id",
          "endpoint_id",
          "event_type",
          "status",
          "attempts"
        ],
        "title": "WebhookDeliveryResponse"
      },
      "WebhookEndpointCreate": {
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048,
            "minLength": 8,
            "title": "Url"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "minItems": 1,
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          }
        },
        "type": "object",
        "required": [
          "url",
          "events"
        ],
        "title": "WebhookEndpointCreate"
      },
      "WebhookEndpointCreatedResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "secret_prefix": {
            "type": "string",
            "title": "Secret Prefix"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          },
          "disabled_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabled Reason"
          },
          "consecutive_failures": {
            "type": "integer",
            "title": "Consecutive Failures",
            "default": 0
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          },
          "secret": {
            "type": "string",
            "title": "Secret"
          }
        },
        "type": "object",
        "required": [
          "id",
          "url",
          "secret_prefix",
          "events",
          "is_active",
          "secret"
        ],
        "title": "WebhookEndpointCreatedResponse",
        "description": "Create response — includes the raw secret exactly once."
      },
      "WebhookEndpointResponse": {
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid",
            "title": "Id"
          },
          "url": {
            "type": "string",
            "title": "Url"
          },
          "secret_prefix": {
            "type": "string",
            "title": "Secret Prefix"
          },
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "is_active": {
            "type": "boolean",
            "title": "Is Active"
          },
          "disabled_reason": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Disabled Reason"
          },
          "consecutive_failures": {
            "type": "integer",
            "title": "Consecutive Failures",
            "default": 0
          },
          "created_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Created At"
          },
          "updated_at": {
            "anyOf": [
              {
                "type": "string",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ],
            "title": "Updated At"
          }
        },
        "type": "object",
        "required": [
          "id",
          "url",
          "secret_prefix",
          "events",
          "is_active"
        ],
        "title": "WebhookEndpointResponse"
      },
      "WebhookEndpointUpdate": {
        "properties": {
          "url": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 2048,
                "minLength": 8
              },
              {
                "type": "null"
              }
            ],
            "title": "Url"
          },
          "events": {
            "anyOf": [
              {
                "items": {
                  "type": "string"
                },
                "type": "array",
                "minItems": 1
              },
              {
                "type": "null"
              }
            ],
            "title": "Events"
          },
          "description": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 255
              },
              {
                "type": "null"
              }
            ],
            "title": "Description"
          },
          "is_active": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Is Active"
          }
        },
        "type": "object",
        "title": "WebhookEndpointUpdate"
      },
      "WebhookEventTypesResponse": {
        "properties": {
          "events": {
            "items": {
              "type": "string"
            },
            "type": "array",
            "title": "Events"
          }
        },
        "type": "object",
        "required": [
          "events"
        ],
        "title": "WebhookEventTypesResponse"
      },
      "WhitelistAddRequest": {
        "properties": {
          "ip_or_cidr": {
            "type": "string",
            "title": "Ip Or Cidr",
            "description": "Single IPv4 address (CIDR subnets are not supported)"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "conn_limit": {
            "anyOf": [
              {
                "type": "integer",
                "minimum": 0
              },
              {
                "type": "null"
              }
            ],
            "title": "Conn Limit"
          }
        },
        "additionalProperties": false,
        "type": "object",
        "required": [
          "ip_or_cidr"
        ],
        "title": "WhitelistAddRequest",
        "description": "Add one IPv4 address to the whitelist. The field is named `ip_or_cidr`, but only single IPv4 addresses (or `/32`) are accepted."
      },
      "WhitelistEntry": {
        "properties": {
          "ip_or_cidr": {
            "type": "string",
            "title": "Ip Or Cidr"
          },
          "label": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Label"
          },
          "conn_limit": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Conn Limit"
          },
          "is_paid": {
            "type": "boolean",
            "title": "Is Paid",
            "default": false
          }
        },
        "type": "object",
        "required": [
          "ip_or_cidr"
        ],
        "title": "WhitelistEntry",
        "description": "One whitelisted IP, with an optional per-IP connection limit."
      },
      "WhitelistResponse": {
        "properties": {
          "service_id": {
            "type": "string",
            "format": "uuid",
            "title": "Service Id"
          },
          "entries": {
            "items": {
              "$ref": "#/components/schemas/WhitelistEntry"
            },
            "type": "array",
            "title": "Entries"
          },
          "conn_cap": {
            "type": "integer",
            "title": "Conn Cap"
          },
          "capacity": {
            "type": "integer",
            "title": "Capacity",
            "default": 0
          },
          "free_quota": {
            "type": "integer",
            "title": "Free Quota",
            "default": 0
          },
          "used": {
            "type": "integer",
            "title": "Used",
            "default": 0
          },
          "paid_slots": {
            "type": "integer",
            "title": "Paid Slots",
            "default": 0
          }
        },
        "type": "object",
        "required": [
          "service_id",
          "entries",
          "conn_cap"
        ],
        "title": "WhitelistResponse",
        "description": "Whitelisted IPs and the service's concurrent connection limit. `capacity`, `free_quota`, `used`, and `paid_slots` show how many more IPs you can add before extra whitelist IPs are charged."
      }
    },
    "securitySchemes": {
      "HTTPBearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key created in the Dashboard (Settings → API keys)."
      }
    }
  },
  "tags": [
    {
      "name": "Catalog and pricing"
    },
    {
      "name": "Orders"
    },
    {
      "name": "Services"
    },
    {
      "name": "Proxy access"
    },
    {
      "name": "Rotating sessions"
    },
    {
      "name": "Add-ons"
    },
    {
      "name": "Wallet"
    },
    {
      "name": "Account"
    },
    {
      "name": "API keys"
    },
    {
      "name": "Support tickets"
    },
    {
      "name": "Webhooks"
    }
  ],
  "servers": [
    {
      "url": "https://papaproxy.net/account_new",
      "description": "Production"
    }
  ],
  "security": [
    {
      "HTTPBearer": []
    }
  ],
  "externalDocs": {
    "description": "Developer guide",
    "url": "https://papaproxy.net/developers.php"
  }
}
