{
 "openapi": "3.1.0",
 "info": {
  "title": "Hell World Personal API",
  "version": "1.0.0",
  "summary": "Generate proxy strings for your own Hell World products and read usage, balance and locations.",
  "description": "Authenticate with your personal key (hwp_live_...) in Authorization: Bearer or X-API-Key. Keys in the URL are rejected. Generated lines contain your proxy username and password.",
  "contact": {
   "name": "Hell World",
   "url": "https://hellworld.io/developers"
  }
 },
 "servers": [
  {
   "url": "https://hellworld.io/hellworld/papi/v1"
  }
 ],
 "security": [
  {
   "bearerAuth": []
  },
  {
   "apiKeyHeader": []
  }
 ],
 "tags": [
  {
   "name": "account"
  },
  {
   "name": "products"
  },
  {
   "name": "proxies"
  },
  {
   "name": "meta"
  }
 ],
 "paths": {
  "/me": {
   "get": {
    "operationId": "getMe",
    "tags": [
     "account"
    ],
    "summary": "Key, account and limits",
    "description": "Returns the key prefix, masked email, your client IP as seen by the API, server time and rate limits.",
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Me"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/products": {
   "get": {
    "operationId": "listProducts",
    "tags": [
     "products"
    ],
    "summary": "List your products",
    "description": "Your active and inactive products with status, usage and generation capabilities. No credentials.",
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/ProductList"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/products/{product}": {
   "get": {
    "operationId": "getProduct",
    "tags": [
     "products"
    ],
    "summary": "Get one product",
    "description": "By id or code. A code shared by several of your products returns 409 PRODUCT_AMBIGUOUS with candidate ids.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Product"
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Product"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/products/{product}/locations/{kind}": {
   "get": {
    "operationId": "listLocations",
    "tags": [
     "products"
    ],
    "summary": "Locations for targeting",
    "description": "Location codes accepted by generate for this product. ET-Hearth lists are live (source fresh or stale); others are static.",
    "parameters": [
     {
      "$ref": "#/components/parameters/Product"
     },
     {
      "$ref": "#/components/parameters/Kind"
     },
     {
      "name": "country",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Required for states, cities, isps and asns."
     },
     {
      "name": "state",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Required for cities and isps (ET-Hearth)."
     },
     {
      "name": "city",
      "in": "query",
      "schema": {
       "type": "string"
      },
      "description": "Required for isps (ET-Hearth)."
     }
    ],
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/LocationList"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/proxies/generate": {
   "post": {
    "operationId": "generateProxies",
    "tags": [
     "proxies"
    ],
    "summary": "Generate proxy lines",
    "description": "Creates or changes nothing at the proxy provider. ET-Hearth targeting checks location codes against live provider data and may return 503 LOCATIONS_UNAVAILABLE. Unsupported targeting returns 400 UNSUPPORTED_PARAMETER and never widens to a broader proxy.",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/GenerateRequest"
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       },
       "X-Budget-Lines-Remaining": {
        "$ref": "#/components/headers/X-Budget-Lines-Remaining"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/GenerateResponse"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/proxies/export": {
   "get": {
    "operationId": "exportProxies",
    "tags": [
     "proxies"
    ],
    "summary": "Export proxy lines as plain text",
    "description": "Same as generate but returns text/plain, one line per proxy ending in a newline. Each parameter may appear once; json format is not available here.",
    "parameters": [
     {
      "name": "product",
      "in": "query",
      "required": true,
      "schema": {
       "type": "string",
       "pattern": "^([0-9a-f]{32}|[a-z0-9-]{2,40})$"
      },
      "description": "Product id or code."
     },
     {
      "name": "count",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 1000,
       "default": 1
      }
     },
     {
      "name": "country",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "pattern": "^[A-Za-z]{2,3}$"
      }
     },
     {
      "name": "state",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "city",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "isp",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "asn",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "zip",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "os",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "session",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "rotating",
        "sticky"
       ],
       "default": "rotating"
      }
     },
     {
      "name": "session_minutes",
      "in": "query",
      "required": false,
      "schema": {
       "type": "integer"
      }
     },
     {
      "name": "session_seed",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "pattern": "^[A-Za-z0-9_-]{1,64}$"
      }
     },
     {
      "name": "server",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string"
      }
     },
     {
      "name": "protocol",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "http",
        "socks5"
       ],
       "default": "http"
      }
     },
     {
      "name": "format",
      "in": "query",
      "required": false,
      "schema": {
       "type": "string",
       "enum": [
        "host:port:user:pass",
        "user:pass@host:port",
        "user:pass:host:port",
        "url"
       ],
       "default": "host:port:user:pass"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Proxy lines",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       },
       "X-Budget-Lines-Remaining": {
        "$ref": "#/components/headers/X-Budget-Lines-Remaining"
       }
      },
      "content": {
       "text/plain": {
        "schema": {
         "type": "string"
        }
       }
      }
     },
     "409": {
      "$ref": "#/components/responses/Conflict"
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/usage": {
   "get": {
    "operationId": "getUsage",
    "tags": [
     "account"
    ],
    "summary": "Usage per product and total",
    "description": "Usage per product with its source (upstream, cached, local or unknown); traffic_total sums only products with trusted traffic data.",
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/UsageReport"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/balance": {
   "get": {
    "operationId": "getBalance",
    "tags": [
     "account"
    ],
    "summary": "Account balance",
    "description": "Read-only balance in USD with a link to top up on the website.",
    "responses": {
     "200": {
      "description": "OK",
      "headers": {
       "X-Request-Id": {
        "$ref": "#/components/headers/X-Request-Id"
       },
       "X-RateLimit-Limit": {
        "$ref": "#/components/headers/X-RateLimit-Limit"
       },
       "X-RateLimit-Remaining": {
        "$ref": "#/components/headers/X-RateLimit-Remaining"
       },
       "X-RateLimit-Reset": {
        "$ref": "#/components/headers/X-RateLimit-Reset"
       }
      },
      "content": {
       "application/json": {
        "schema": {
         "$ref": "#/components/schemas/Balance"
        }
       }
      }
     },
     "400": {
      "$ref": "#/components/responses/BadRequest"
     },
     "401": {
      "$ref": "#/components/responses/Unauthorized"
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  },
  "/openapi.json": {
   "get": {
    "operationId": "getOpenApi",
    "tags": [
     "meta"
    ],
    "summary": "This document",
    "security": [],
    "description": "The OpenAPI 3.1 description of this API. No key needed.",
    "responses": {
     "200": {
      "description": "OpenAPI document",
      "content": {
       "application/json": {
        "schema": {
         "type": "object"
        }
       }
      }
     },
     "403": {
      "$ref": "#/components/responses/Forbidden"
     },
     "404": {
      "$ref": "#/components/responses/NotFound"
     },
     "405": {
      "$ref": "#/components/responses/MethodNotAllowed"
     },
     "429": {
      "$ref": "#/components/responses/TooManyRequests"
     },
     "500": {
      "$ref": "#/components/responses/InternalError"
     },
     "503": {
      "$ref": "#/components/responses/ServiceUnavailable"
     },
     "default": {
      "$ref": "#/components/responses/OtherError"
     }
    }
   }
  }
 },
 "components": {
  "securitySchemes": {
   "bearerAuth": {
    "type": "http",
    "scheme": "bearer",
    "description": "Authorization: Bearer hwp_live_<keyId>.<secret>"
   },
   "apiKeyHeader": {
    "type": "apiKey",
    "in": "header",
    "name": "X-API-Key",
    "description": "Alternative to the Authorization header; both must match if both are sent."
   }
  },
  "parameters": {
   "Product": {
    "name": "product",
    "in": "path",
    "required": true,
    "schema": {
     "type": "string",
     "pattern": "^([0-9a-f]{32}|[a-z0-9-]{2,40})$"
    },
    "description": "Product id (32 hex characters) or product code, e.g. oxylab."
   },
   "Kind": {
    "name": "kind",
    "in": "path",
    "required": true,
    "schema": {
     "type": "string",
     "enum": [
      "countries",
      "states",
      "cities",
      "asns",
      "isps"
     ]
    }
   }
  },
  "headers": {
   "X-Request-Id": {
    "schema": {
     "type": "string"
    },
    "description": "Include it when contacting support."
   },
   "X-RateLimit-Limit": {
    "schema": {
     "type": "integer"
    },
    "description": "Requests allowed per minute for this key and request class."
   },
   "X-RateLimit-Remaining": {
    "schema": {
     "type": "integer"
    }
   },
   "X-RateLimit-Reset": {
    "schema": {
     "type": "integer"
    },
    "description": "Unix seconds when the current window ends."
   },
   "X-Budget-Lines-Remaining": {
    "schema": {
     "type": "integer"
    },
    "description": "Generation lines left for your account in this minute."
   },
   "Retry-After": {
    "schema": {
     "type": "integer"
    },
    "description": "Seconds to wait before retrying."
   }
  },
  "responses": {
   "BadRequest": {
    "description": "Invalid request or parameter (INVALID_PARAMETER, UNSUPPORTED_PARAMETER, FORMAT_UNSAFE, INVALID_REQUEST).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Unauthorized": {
    "description": "Missing or invalid key (UNAUTHENTICATED, KEY_INVALID).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Forbidden": {
    "description": "Account suspended or browser Origin present (ACCOUNT_SUSPENDED, CORS_NOT_ALLOWED).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "NotFound": {
    "description": "No such product in your account (PRODUCT_NOT_FOUND), or the API is not enabled / no such path (NOT_FOUND).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "MethodNotAllowed": {
    "description": "HTTP method not supported on this path (METHOD_NOT_ALLOWED).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "OtherError": {
    "description": "Other request rejections (NOT_ACCEPTABLE, PAYLOAD_TOO_LARGE, UNSUPPORTED_MEDIA_TYPE, INVALID_REQUEST, INTERNAL_ERROR).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "Conflict": {
    "description": "Product state prevents the request (PRODUCT_AMBIGUOUS, PRODUCT_PROVISIONING, PRODUCT_INACTIVE, PRODUCT_DATA_INVALID).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "TooManyRequests": {
    "description": "Rate limit or generation budget exceeded (RATE_LIMITED).",
    "headers": {
     "Retry-After": {
      "$ref": "#/components/headers/Retry-After"
     },
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "InternalError": {
    "description": "GENERATOR_OUTPUT_TOO_LARGE or INTERNAL_ERROR.",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   },
   "ServiceUnavailable": {
    "description": "Temporarily unavailable; retry shortly (AUTH_STATUS_UNAVAILABLE, AUTH_STATUS_INVALID, RATE_LIMIT_UNAVAILABLE, GENERATOR_UNAVAILABLE, LOCATIONS_UNAVAILABLE).",
    "headers": {
     "X-Request-Id": {
      "$ref": "#/components/headers/X-Request-Id"
     },
     "Retry-After": {
      "$ref": "#/components/headers/Retry-After"
     }
    },
    "content": {
     "application/json": {
      "schema": {
       "$ref": "#/components/schemas/Error"
      }
     }
    }
   }
  },
  "schemas": {
   "ErrorCode": {
    "type": "string",
    "enum": [
     "ACCOUNT_SUSPENDED",
     "AUTH_STATUS_INVALID",
     "AUTH_STATUS_UNAVAILABLE",
     "CORS_NOT_ALLOWED",
     "FORMAT_UNSAFE",
     "GENERATOR_OUTPUT_TOO_LARGE",
     "GENERATOR_UNAVAILABLE",
     "INTERNAL_ERROR",
     "INVALID_PARAMETER",
     "INVALID_REQUEST",
     "KEY_INVALID",
     "LOCATIONS_UNAVAILABLE",
     "METHOD_NOT_ALLOWED",
     "NOT_ACCEPTABLE",
     "NOT_FOUND",
     "PAYLOAD_TOO_LARGE",
     "PRODUCT_AMBIGUOUS",
     "PRODUCT_DATA_INVALID",
     "PRODUCT_INACTIVE",
     "PRODUCT_NOT_FOUND",
     "PRODUCT_PROVISIONING",
     "RATE_LIMITED",
     "RATE_LIMIT_UNAVAILABLE",
     "UNAUTHENTICATED",
     "UNSUPPORTED_MEDIA_TYPE",
     "UNSUPPORTED_PARAMETER"
    ]
   },
   "Error": {
    "type": "object",
    "required": [
     "error",
     "request_id"
    ],
    "properties": {
     "error": {
      "type": "object",
      "required": [
       "code",
       "message",
       "docs_url"
      ],
      "properties": {
       "code": {
        "$ref": "#/components/schemas/ErrorCode"
       },
       "message": {
        "type": "string"
       },
       "param": {
        "type": "string",
        "description": "The parameter that caused the error, when known."
       },
       "hint": {
        "type": "string"
       },
       "docs_url": {
        "type": "string",
        "format": "uri"
       },
       "allowed": {
        "description": "Accepted values for param, when useful."
       },
       "candidates": {
        "type": "array",
        "items": {
         "$ref": "#/components/schemas/Candidate"
        },
        "description": "With PRODUCT_AMBIGUOUS: your products sharing the code."
       },
       "limit_dimension": {
        "type": "string",
        "description": "With RATE_LIMITED: which limit was hit."
       }
      }
     },
     "request_id": {
      "type": "string"
     }
    }
   },
   "Candidate": {
    "type": "object",
    "properties": {
     "id": {
      "type": "string"
     },
     "code": {
      "type": "string"
     },
     "category": {
      "type": "string"
     },
     "status": {
      "$ref": "#/components/schemas/ProductStatus"
     }
    }
   },
   "ProductStatus": {
    "type": "string",
    "description": "A display classification based on Hell World's local records. It is not permission to generate and not a live guarantee from the provider; whether a product can generate is decided by the eligibility check of that generate request.",
    "enum": [
     "active",
     "expired",
     "exhausted",
     "inactive",
     "provisioning",
     "unknown"
    ]
   },
   "Usage": {
    "type": "object",
    "required": [
     "type",
     "source"
    ],
    "properties": {
     "type": {
      "type": "string",
      "enum": [
       "traffic",
       "time",
       "static",
       "unknown"
      ]
     },
     "unit": {
      "type": "string",
      "enum": [
       "GB"
      ]
     },
     "limit": {
      "type": [
       "number",
       "null"
      ]
     },
     "used": {
      "type": [
       "number",
       "null"
      ]
     },
     "remaining": {
      "type": [
       "number",
       "null"
      ]
     },
     "ip_count": {
      "type": [
       "integer",
       "null"
      ],
      "description": "Static ISP only; null when the count cannot be trusted."
     },
     "source": {
      "type": "string",
      "enum": [
       "upstream",
       "cached",
       "local",
       "unknown"
      ],
      "description": "upstream: read from the provider during this request. cached: read from the provider within the last 10 minutes. local: recorded by Hell World, not read from the provider. unknown: not enough evidence. upstream and cached may lag behind a top-up that just completed; their limit, used and remaining are the provider's current figures for the product."
     },
     "synced_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time",
      "description": "When the provider read succeeded (UTC). Null for local and unknown."
     }
    }
   },
   "StickyMinutes": {
    "oneOf": [
     {
      "type": "array",
      "items": {
       "type": "integer"
      }
     },
     {
      "type": "object",
      "properties": {
       "min": {
        "type": "integer"
       },
       "max": {
        "type": "integer"
       },
       "except": {
        "type": "array",
        "items": {
         "type": "integer"
        }
       }
      }
     },
     {
      "type": "null"
     }
    ]
   },
   "Capabilities": {
    "type": "object",
    "properties": {
     "targeting": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "session": {
      "type": "object",
      "properties": {
       "rotating": {
        "type": "boolean"
       },
       "sticky": {
        "type": "boolean"
       },
       "sticky_minutes": {
        "$ref": "#/components/schemas/StickyMinutes"
       }
      }
     },
     "servers": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "protocols": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "http",
        "socks5"
       ]
      }
     },
     "os": {
      "type": "array",
      "items": {
       "type": "string"
      }
     },
     "max_count": {
      "type": [
       "integer",
       "null"
      ],
      "description": "null for static ISP (full list)."
     },
     "formats": {
      "type": "array",
      "items": {
       "type": "string",
       "enum": [
        "host:port:user:pass",
        "user:pass@host:port",
        "user:pass:host:port",
        "url",
        "json"
       ]
      }
     }
    }
   },
   "Product": {
    "type": "object",
    "required": [
     "id",
     "code",
     "name",
     "category",
     "status",
     "usage"
    ],
    "properties": {
     "id": {
      "type": "string"
     },
     "code": {
      "type": "string"
     },
     "name": {
      "type": "string"
     },
     "category": {
      "type": "string"
     },
     "status": {
      "$ref": "#/components/schemas/ProductStatus"
     },
     "usage": {
      "$ref": "#/components/schemas/Usage"
     },
     "expires_at": {
      "type": [
       "string",
       "null"
      ],
      "format": "date-time"
     },
     "capabilities": {
      "$ref": "#/components/schemas/Capabilities"
     }
    }
   },
   "ProductList": {
    "type": "object",
    "required": [
     "products"
    ],
    "properties": {
     "products": {
      "type": "array",
      "items": {
       "$ref": "#/components/schemas/Product"
      }
     }
    }
   },
   "UsageReport": {
    "type": "object",
    "required": [
     "products",
     "traffic_total"
    ],
    "properties": {
     "products": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "id": {
         "type": "string"
        },
        "code": {
         "type": "string"
        },
        "name": {
         "type": "string"
        },
        "status": {
         "$ref": "#/components/schemas/ProductStatus"
        },
        "usage": {
         "$ref": "#/components/schemas/Usage"
        },
        "expires_at": {
         "type": [
          "string",
          "null"
         ],
         "format": "date-time"
        }
       }
      }
     },
     "traffic_total": {
      "type": "object",
      "properties": {
       "unit": {
        "type": "string"
       },
       "limit": {
        "type": "number"
       },
       "used": {
        "type": "number"
       },
       "remaining": {
        "type": "number"
       }
      }
     }
    }
   },
   "Balance": {
    "type": "object",
    "required": [
     "balance",
     "currency",
     "top_up_url"
    ],
    "properties": {
     "balance": {
      "type": "number"
     },
     "currency": {
      "type": "string",
      "enum": [
       "USD"
      ]
     },
     "top_up_url": {
      "type": "string",
      "format": "uri"
     }
    }
   },
   "Me": {
    "type": "object",
    "properties": {
     "account": {
      "type": "object",
      "properties": {
       "email": {
        "type": [
         "string",
         "null"
        ],
        "description": "Masked."
       }
      }
     },
     "key": {
      "type": "object",
      "properties": {
       "prefix": {
        "type": "string"
       },
       "last4": {
        "type": "string"
       },
       "created_at": {
        "type": "string",
        "format": "date-time"
       },
       "expires_at": {
        "type": "string",
        "format": "date-time"
       }
      }
     },
     "client_ip": {
      "type": "string"
     },
     "server_time": {
      "type": "string",
      "format": "date-time"
     },
     "limits": {
      "type": "object",
      "additionalProperties": {
       "type": "integer"
      }
     }
    }
   },
   "GenerateRequest": {
    "type": "object",
    "required": [
     "product"
    ],
    "additionalProperties": false,
    "properties": {
     "product": {
      "type": "string",
      "pattern": "^([0-9a-f]{32}|[a-z0-9-]{2,40})$",
      "description": "Product id or code."
     },
     "count": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000,
      "default": 1,
      "description": "Number of lines (1-1000; MCP calls 1-100). Ignored for static ISP products, which return their full list."
     },
     "country": {
      "type": "string",
      "pattern": "^[A-Za-z]{2,3}$",
      "description": "Country code, e.g. US. Omit for a random location."
     },
     "state": {
      "type": "string",
      "description": "State or region code; see /products/{product}/locations/states."
     },
     "city": {
      "type": "string",
      "description": "City code; see /products/{product}/locations/cities."
     },
     "isp": {
      "type": "string",
      "description": "ISP code (ET-Hearth only); see /products/{product}/locations/isps."
     },
     "asn": {
      "type": [
       "string",
       "integer"
      ],
      "description": "ASN (1-4294967295); cannot be combined with state, city or zip."
     },
     "zip": {
      "type": "string",
      "description": "ZIP code (only where the product's capabilities list zip)."
     },
     "os": {
      "type": "string",
      "description": "OS fingerprint value from the product's capabilities."
     },
     "session": {
      "type": "string",
      "enum": [
       "rotating",
       "sticky"
      ],
      "default": "rotating"
     },
     "session_minutes": {
      "type": "integer",
      "description": "Sticky session length; allowed values are in capabilities.session.sticky_minutes."
     },
     "session_seed": {
      "type": "string",
      "pattern": "^[A-Za-z0-9_-]{1,64}$",
      "description": "Only with session=sticky. Same seed, product and parameters give the same session IDs. Does not promise the same exit IP."
     },
     "server": {
      "type": "string",
      "description": "Gateway region from capabilities.servers."
     },
     "protocol": {
      "type": "string",
      "enum": [
       "http",
       "socks5"
      ],
      "default": "http"
     },
     "format": {
      "type": "string",
      "enum": [
       "host:port:user:pass",
       "user:pass@host:port",
       "user:pass:host:port",
       "url",
       "json"
      ],
      "default": "host:port:user:pass",
      "description": "Colon/at formats reject credentials containing ':', '@', whitespace or newlines (FORMAT_UNSAFE); use json or url."
     }
    }
   },
   "GenerateResponse": {
    "type": "object",
    "required": [
     "product",
     "count",
     "format",
     "protocol",
     "proxies"
    ],
    "properties": {
     "product": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "code": {
        "type": "string"
       }
      }
     },
     "count": {
      "type": "integer"
     },
     "format": {
      "type": "string",
      "enum": [
       "host:port:user:pass",
       "user:pass@host:port",
       "user:pass:host:port",
       "url",
       "json"
      ]
     },
     "protocol": {
      "type": "string",
      "enum": [
       "http",
       "socks5"
      ]
     },
     "proxies": {
      "type": "array",
      "description": "Strings for text formats; objects {host, port, username, password} for json.",
      "items": {
       "oneOf": [
        {
         "type": "string"
        },
        {
         "$ref": "#/components/schemas/ProxyObject"
        }
       ]
      }
     },
     "usage": {
      "$ref": "#/components/schemas/Usage"
     }
    }
   },
   "ProxyObject": {
    "type": "object",
    "required": [
     "host",
     "port",
     "username",
     "password"
    ],
    "properties": {
     "host": {
      "type": "string"
     },
     "port": {
      "type": "integer",
      "minimum": 1,
      "maximum": 65535
     },
     "username": {
      "type": "string"
     },
     "password": {
      "type": "string"
     }
    }
   },
   "LocationList": {
    "type": "object",
    "required": [
     "product",
     "kind",
     "items",
     "source"
    ],
    "properties": {
     "product": {
      "type": "object",
      "properties": {
       "id": {
        "type": "string"
       },
       "code": {
        "type": "string"
       }
      }
     },
     "kind": {
      "type": "string"
     },
     "items": {
      "type": "array",
      "items": {
       "type": "object",
       "properties": {
        "code": {},
        "name": {
         "type": "string"
        }
       }
      }
     },
     "source": {
      "type": "string",
      "enum": [
       "fresh",
       "stale",
       "static"
      ]
     },
     "free_input": {
      "type": "boolean",
      "description": "true when values outside the list are also accepted."
     }
    }
   }
  }
 }
}
