{
  "openapi": "3.1.0",
  "info": {
    "title": "VirtualSMS | Account verification platform for developers and AI agents",
    "version": "1.2.0",
    "description": "VirtualSMS is an account verification platform for developers and AI agents. It combines one-time SMS verification, dedicated number rentals, matching-country proxies, and private cloud browser sessions (beta) behind one API, one MCP server, and one prepaid balance. Receive OTP codes on carrier-issued mobile numbers, backed by real physical SIM cards (not VoIP), across 2500+ services and 145+ countries from $0.05 per code, with a 95%+ success rate and auto-refund if no code arrives. Rent dedicated numbers from $0.25/day, buy matching-country proxies across 190+ countries from $1.10/GB, and drive it all through the REST API, official SDKs, or the hosted MCP server (40 tools).\n\n### Drop-in compatibility for sms-activate-style code\n\n```diff\n- BASE_URL = \"https://[your-old-provider]/stubs/handler_api.php\"\n+ BASE_URL = \"https://virtualsms.io/stubs/handler_api.php\"\n```\n\nAll action names, response formats, error codes, and parameter names match the widely-used sms-activate API protocol.\nYour existing `getNumber`, `getStatus`, `setStatus` code requires **zero modification**.\n\n### Two API Styles\n\n| Style | Best For |\n|-------|----------|\n| **sms-activate Compatibility** (`/stubs/handler_api.php`) | Existing bots, legacy migrations, automation tools |\n| **Modern REST API** (`/api/v1/`) | New integrations, webhooks, real-time WebSocket |\n\n### Authentication\n\nAll endpoints require an API key. Generate yours at **Settings -> API Keys**.\n\nKeys look like: `vsms_a3f8b2c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1`\n",
    "contact": {
      "name": "VirtualSMS Support",
      "url": "https://virtualsms.io",
      "email": "support@virtualsms.io"
    },
    "x-guidance": "AI agents: prefer the Modern REST API (/api/v1/) with an X-API-Key header for\nnew integrations. For pay-per-call use with no account/API key, use the x402\nendpoint under Agent Payments (x402) — see the x-payment-info block on\nPOST /api/v1/x402/sms-verify and the live discovery manifest at\nhttps://agents.virtualsms.io/.well-known/x402.json.\n"
  },
  "servers": [
    {
      "url": "https://virtualsms.io",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "ApiKeyQuery": []
    }
  ],
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key from virtualsms.io dashboard (Settings -> API tab). Prefix: vsms_"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key in request header. Use for Modern REST API endpoints."
      },
      "ApiKeyQuery": {
        "type": "apiKey",
        "in": "query",
        "name": "api_key",
        "description": "API key as query parameter. Use for sms-activate compatibility endpoints."
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "example": "NO_NUMBERS"
          },
          "message": {
            "type": "string",
            "example": "No numbers available for WhatsApp in US"
          },
          "service": {
            "type": "string",
            "example": "whatsapp"
          },
          "country": {
            "type": "string",
            "example": "US"
          }
        }
      },
      "BalanceResponse": {
        "type": "object",
        "properties": {
          "balance": {
            "type": "number",
            "format": "float",
            "example": 50.3
          },
          "currency": {
            "type": "string",
            "example": "USD"
          }
        }
      },
      "RentalResponse": {
        "type": "object",
        "properties": {
          "rental_id": {
            "type": "integer",
            "example": 12345
          },
          "phone": {
            "type": "string",
            "example": "+13476711222"
          },
          "service": {
            "type": "string",
            "example": "whatsapp"
          },
          "country": {
            "type": "string",
            "example": "US"
          },
          "price_charged": {
            "type": "number",
            "format": "float",
            "example": 0.6
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-03-03T15:00:00Z"
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "received",
              "done",
              "cancelled"
            ],
            "example": "waiting"
          }
        }
      },
      "RentalStatus": {
        "type": "object",
        "properties": {
          "rental_id": {
            "type": "integer",
            "example": 12345
          },
          "status": {
            "type": "string",
            "enum": [
              "waiting",
              "received",
              "done",
              "cancelled"
            ],
            "example": "received"
          },
          "sms_code": {
            "type": "string",
            "nullable": true,
            "example": "438271"
          },
          "sms_text": {
            "type": "string",
            "nullable": true,
            "example": "Your WhatsApp code is 438271. Don't share this code."
          },
          "received_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "example": "2026-03-03T14:22:11Z"
          }
        }
      },
      "ServiceItem": {
        "type": "object",
        "properties": {
          "service_id": {
            "type": "string",
            "example": "whatsapp"
          },
          "service_code": {
            "type": "string",
            "description": "sms-activate compatible service code",
            "example": "wa"
          },
          "name": {
            "type": "string",
            "example": "WhatsApp"
          },
          "price": {
            "type": "number",
            "format": "float",
            "example": 0.5
          },
          "available": {
            "type": "integer",
            "description": "Stock count (capped at 100)",
            "example": 87
          },
          "countries": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "US",
              "GB",
              "DE",
              "FR",
              "HR"
            ]
          }
        }
      },
      "WebhookCreate": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/sms-callback"
          },
          "secret": {
            "type": "string",
            "description": "Optional HMAC signing secret. If set, requests will include X-VirtualSMS-Signature header.",
            "example": "my-secret-key-123"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Event filter. Default is all events.",
            "example": [
              "sms.received"
            ]
          }
        }
      },
      "WebhookResponse": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "wh_abc123"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/sms-callback"
          },
          "active": {
            "type": "boolean",
            "example": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-03-03T12:00:00Z"
          },
          "last_triggered": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "example": "2026-03-03T14:22:11Z"
          },
          "success_rate": {
            "type": "number",
            "format": "float",
            "example": 0.98
          }
        }
      },
      "AuthRegisterRequest": {
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "example": "user@example.com"
          },
          "password": {
            "type": "string",
            "minLength": 8,
            "example": "secure123"
          }
        }
      },
      "AuthLoginRequest": {
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "example": "user@example.com"
          },
          "password": {
            "type": "string",
            "example": "secure123"
          }
        }
      },
      "AuthResponse": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "JWT bearer token",
            "example": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
          },
          "user_id": {
            "type": "string",
            "format": "uuid",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "example": "2026-03-04T12:00:00Z"
          }
        }
      },
      "RentRequest": {
        "type": "object",
        "required": [
          "service"
        ],
        "properties": {
          "service": {
            "type": "string",
            "description": "Service name (whatsapp, telegram, google...) or sms-activate code (wa, tg, go...)",
            "example": "whatsapp"
          },
          "country": {
            "type": "string",
            "description": "ISO 3166-1 alpha-2 country code",
            "example": "US",
            "default": "US"
          },
          "max_price": {
            "type": "number",
            "format": "float",
            "description": "Maximum price you're willing to pay. Request rejected if actual price exceeds this.",
            "example": 0.75
          },
          "areas": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Area code filter (Phase 2). +20% price premium. Example: [\"212\", \"718\"]",
            "example": [
              "212",
              "718"
            ]
          },
          "carriers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Carrier filter (Phase 2). +20% price premium. Values: tmo (T-Mobile), vz (Verizon), att (AT&T)",
            "example": [
              "tmo"
            ]
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "sms-activate Compatibility",
      "description": "## sms-activate-Style Legacy Endpoints\n\nThese endpoints replicate the widely-used sms-activate API format exactly.\nAll responses are **plain text** (not JSON), returned with HTTP 200 even on errors.\n\n**Base URL:** `https://virtualsms.io/stubs/handler_api.php`\n\n**Usage:** Append `?action=<action>&api_key=<key>` to the base URL.\n\n**Error handling:** Check the response body text - errors are strings like `BAD_KEY`, `NO_NUMBERS`.\n\n### Common Error Codes\n| Code | Meaning |\n|------|---------|\n| `BAD_KEY` | Invalid or missing API key |\n| `NO_NUMBERS` | No stock for service/country |\n| `NO_MONEY` | Insufficient balance |\n| `MAX_PRICE_EXCEEDED` | Actual price > max_price param |\n| `TOO_MANY_ACTIVE_RENTALS` | Hit 20-rental concurrent limit |\n| `NO_ACTIVATION` | Invalid rental ID |\n| `BAD_SERVICE` | Unknown service code |\n| `BAD_COUNTRY` | Unknown country code |\n"
    },
    {
      "name": "Authentication",
      "description": "Register, login, and manage your account.\n\nAfter login, use the JWT token as `Authorization: Bearer <token>` or generate an API key\nfor use with `X-API-Key` header.\n"
    },
    {
      "name": "Numbers",
      "description": "Rent phone numbers and wait for SMS verification codes.\n\n**Flow:**\n1. `POST /api/v1/numbers/rent` -> get rental_id and phone number\n2. Poll `GET /api/v1/numbers/:id/status` every 3-5 seconds (or use WebSocket / webhooks)\n3. When `status=received`, read `sms_code`\n4. `POST /api/v1/numbers/:id/done` to free your slot\n"
    },
    {
      "name": "Services",
      "description": "Browse available services, countries, and current prices."
    },
    {
      "name": "Webhooks",
      "description": "Register a URL to receive instant push notifications when SMS arrives.\nMuch better than polling - no delay, no wasted requests.\n\n**Payload example:**\n```json\n{\n  \"activationId\": 12345,\n  \"service\": \"wa\",\n  \"code\": \"438271\",\n  \"text\": \"Your WhatsApp code is 438271. Don't share this code.\",\n  \"country\": 187,\n  \"receivedAt\": \"2026-03-03 14:22:11\"\n}\n```\n\n**Retry policy:** Up to 8 retries, 15-second intervals, 3-second timeout per attempt.\n\n**HMAC signature:** If you set a `secret`, each request includes `X-VirtualSMS-Signature: sha256=<hmac>`.\n"
    },
    {
      "name": "Customer API",
      "description": "## Modern Customer API\n\nClean REST endpoints for purchasing SMS verification numbers.\nAll endpoints use **X-API-Key** header authentication.\n\n**Base URL:** `https://virtualsms.io/api/v1/`\n\n**Numbers:** By default, only **physical SIM card numbers** are returned (no VoIP).\nAdd `include_voip=true` to include VoIP numbers where available.\n\n**Order flow:**\n1. `GET /api/v1/customer/balance` - Check your balance\n2. `GET /api/v1/customer/services` - Find available services\n3. `GET /api/v1/customer/countries?service=tg` - Find countries for a service\n4. `GET /api/v1/price?service=tg&country=ID` - Check price\n5. `POST /api/v1/customer/purchase` - Buy a number\n6. `GET /api/v1/customer/order/{orderId}` - Poll for SMS (or use WebSocket)\n7. `POST /api/v1/customer/cancel/{orderId}` - Cancel if needed (after 2-minute hold)\n8. `POST /api/v1/customer/swap/{orderId}` - Swap for a different number (after 2-minute hold)\n"
    },
    {
      "name": "WebSocket",
      "description": "Connect via WebSocket for real-time SMS delivery - no polling required.\n\n**Endpoint:** `wss://virtualsms.io/ws/orders`\n\n**Message types:**\n- `sms` - SMS received with verification code\n- `expired` - Rental time window expired\n"
    },
    {
      "name": "Dedicated Rentals",
      "description": "## Dedicated number rentals (two tiers)\n\nUnlike a one-time activation, a rental gives you a dedicated number you keep for the\nduration you choose, with unlimited inbound SMS during that window.\n\n**Full Access** — from local inventory, usable for any service, longer durations (1/7/30/90 days),\nno cancellation refund window (you own the number for the full term).\n\n**Platform** — sourced via our global supplier network, locked to the one service chosen\nat purchase, shorter durations, with an early-cancel refund window if you cancel quickly\nafter purchase.\n\n**Flow:** `GET /api/v1/rentals/available` (browse, public) -> `GET /api/v1/rentals/pricing`\nor `/api/v1/rentals/price` (confirm price) -> `POST /api/v1/rentals` (create, authed) ->\npoll or WebSocket for SMS -> `POST /api/v1/rentals/{id}/extend` or `/cancel` or `/release`.\n"
    },
    {
      "name": "Proxies",
      "description": "## Country-matched proxies\n\nBuy bandwidth (GB) in a specific pool type and country, get back an HTTP/SOCKS5 proxy\nendpoint. Designed to pair with a VirtualSMS number so the IP and the phone number's\ncountry match for the same verification/signup session.\n\nThree pool types: **residential**, **mobile**, **datacenter** — prices vary by pool and\ncountry. Feature-flagged in production (`FEATURE_PROXIES`); `GET /api/v1/proxies/catalog`\nand `GET /api/v1/proxies/locations` are always public so agents can check current\navailability before authenticating.\n\n**Flow:** `GET /api/v1/proxies/catalog` (browse pools/countries/pricing, public) ->\n`POST /api/v1/proxies` (buy GB, authed) -> use the returned host/port/login/password ->\n`POST /api/v1/proxies/{id}/rotate` for a new IP (30s cooldown) -> `GET /api/v1/proxies/{id}/usage`\nto track remaining GB.\n"
    },
    {
      "name": "Agent Payments (x402)",
      "description": "## Pay-per-call SMS verification over x402 (HTTP 402)\n\nLets an AI agent pay for a single SMS verification with an onchain stablecoin payment —\nno account signup, no API key, no session. One HTTP request, inline settlement, the OTP\ncomes back in the same response.\n\n**Status:** LIVE on Base USDC, Solana USDC/USDT, and BNB Chain USDC/USDT (Permit2).\nDiscovery manifest (accepted networks/assets, current status): `https://agents.virtualsms.io/.well-known/x402.json`.\n\nCall the endpoint without payment first — it returns HTTP 402 with the accepted-payment\nmanifest; retry with an `X-PAYMENT` header carrying a valid payment matching one of the\naccepted schemes.\n"
    }
  ],
  "paths": {
    "/stubs/handler_api.php#getBalance": {
      "get": {
        "operationId": "compat_getBalance",
        "summary": "getBalance - Check account balance",
        "description": "Returns your current account balance.\n\n**Response format:** `ACCESS_BALANCE:{amount}` (e.g., `ACCESS_BALANCE:50.30`)\n\n**Error:** `BAD_KEY` (invalid API key)\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getBalance"
              ]
            },
            "example": "getBalance"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your VirtualSMS API key",
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          }
        ],
        "responses": {
          "200": {
            "description": "Always HTTP 200. Check body for success or error.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "success": {
                    "summary": "Balance returned",
                    "value": "ACCESS_BALANCE:50.30"
                  },
                  "bad_key": {
                    "summary": "Invalid API key",
                    "value": "BAD_KEY"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#getNumber": {
      "get": {
        "operationId": "compat_getNumber",
        "summary": "getNumber - Rent a phone number",
        "description": "Rents a phone number for the specified service. Immediately deducts cost from balance.\n\n**Response format:** `ACCESS_NUMBER:{rental_id}:{phone}` (e.g., `ACCESS_NUMBER:12345:13476711222`)\n\n**Response header:** `X-Price: 0.75` - actual price charged\n\n**Service codes:** `wa` (WhatsApp), `tg` (Telegram), `go` (Google), `ds` (Discord), `ig` (Instagram), `fb` (Facebook), `tw` (Twitter/X), `mm` (Microsoft), `am` (Amazon), `oi` (OpenAI), `ub` (Uber), `pp` (PayPal), `bn` (Binance), `lf` (TikTok), and [many more](https://virtualsms.io/api).\n\n**Country codes:** `187` (USA), `22` (UK), `180` (France), `116` (Croatia), `122` (Poland), `118` (Slovenia), `119` (Czech Republic), `145` (Spain), `179` (Germany), `1` (Ukraine).\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumber"
              ]
            },
            "example": "getNumber"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "service",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "sms-activate service code",
            "example": "wa"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Numeric country code (default 187 = USA)",
            "example": 187
          },
          {
            "name": "max_price",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "float"
            },
            "description": "Maximum price to pay. Returns MAX_PRICE_EXCEEDED if actual price is higher.",
            "example": 0.75
          },
          {
            "name": "maxPrice",
            "in": "query",
            "required": false,
            "schema": {
              "type": "number",
              "format": "float"
            },
            "description": "Alias for max_price",
            "example": 0.75
          }
        ],
        "responses": {
          "200": {
            "description": "Always HTTP 200. Check body for success or error.",
            "headers": {
              "X-Price": {
                "description": "Actual price charged for this rental (on success)",
                "schema": {
                  "type": "string"
                },
                "example": "0.50"
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "success": {
                    "summary": "Number rented successfully",
                    "value": "ACCESS_NUMBER:12345:13476711222"
                  },
                  "no_numbers": {
                    "summary": "Out of stock",
                    "value": "NO_NUMBERS"
                  },
                  "no_money": {
                    "summary": "Insufficient balance",
                    "value": "NO_MONEY"
                  },
                  "max_price": {
                    "summary": "Price exceeds max_price",
                    "value": "MAX_PRICE_EXCEEDED"
                  },
                  "too_many": {
                    "summary": "20 concurrent rental limit hit",
                    "value": "TOO_MANY_ACTIVE_RENTALS"
                  },
                  "bad_service": {
                    "summary": "Unknown service code",
                    "value": "BAD_SERVICE"
                  },
                  "bad_country": {
                    "summary": "Unknown country code",
                    "value": "BAD_COUNTRY"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#getStatus": {
      "get": {
        "operationId": "compat_getStatus",
        "summary": "getStatus - Poll for SMS code",
        "description": "Polls the status of a rental. Call every 3-5 seconds until you get `STATUS_OK` or `STATUS_CANCEL`.\n\n**Tip:** Use WebSocket (`wss://virtualsms.io/ws/orders`) for instant delivery instead of polling.\n\n**Responses:**\n- `STATUS_WAIT_CODE` - Waiting, no SMS yet\n- `STATUS_OK:{code}` - SMS received, code extracted (e.g., `STATUS_OK:438271`)\n- `STATUS_CANCEL` - Rental was cancelled\n- `NO_ACTIVATION` - Invalid rental ID\n\nWhen `text=1`: Response header `X-Text` contains the full SMS body.\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getStatus"
              ]
            },
            "example": "getStatus"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID from getNumber response",
            "example": 12345
          },
          {
            "name": "text",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "enum": [
                0,
                1
              ]
            },
            "description": "Set to 1 to get full SMS body in X-Text response header",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "Always HTTP 200. Check body for status.",
            "headers": {
              "X-Text": {
                "description": "Full SMS body (only when text=1 and SMS received)",
                "schema": {
                  "type": "string"
                },
                "example": "Your WhatsApp code is 438271. Don't share this code."
              }
            },
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "waiting": {
                    "summary": "Waiting for SMS",
                    "value": "STATUS_WAIT_CODE"
                  },
                  "received": {
                    "summary": "SMS received with code",
                    "value": "STATUS_OK:438271"
                  },
                  "cancelled": {
                    "summary": "Rental cancelled",
                    "value": "STATUS_CANCEL"
                  },
                  "not_found": {
                    "summary": "Invalid rental ID",
                    "value": "NO_ACTIVATION"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#setStatusDone": {
      "get": {
        "operationId": "compat_setStatusDone",
        "summary": "setStatus (status=6) - Mark rental as done",
        "description": "Signal that you've successfully used the SMS code. Frees your active rental slot.\n\n**Always call this after you're done** - otherwise you'll hit the 20-concurrent-rental limit.\n\n**Response:** `ACCESS_ACTIVATION` (success) or `NO_ACTIVATION` (invalid ID)\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "setStatus"
              ]
            },
            "example": "setStatus"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID to mark as done",
            "example": 12345
          },
          {
            "name": "status",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                6
              ]
            },
            "description": "Use status=6 to mark as done",
            "example": 6
          }
        ],
        "responses": {
          "200": {
            "description": "Always HTTP 200.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "success": {
                    "summary": "Marked as done",
                    "value": "ACCESS_ACTIVATION"
                  },
                  "not_found": {
                    "summary": "Invalid ID",
                    "value": "NO_ACTIVATION"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#setStatusCancel": {
      "get": {
        "operationId": "compat_setStatusCancel",
        "summary": "setStatus (status=8) - Cancel rental & refund",
        "description": "Cancels a rental before SMS is received. Full balance refund.\n\n**Cannot cancel after SMS arrives** - returns `ACCESS_READY` instead.\n\n**Responses:**\n- `ACCESS_CANCEL` - Cancelled, balance refunded\n- `ACCESS_READY` - Too late, SMS already received (cannot cancel)\n- `NO_ACTIVATION` - Invalid rental ID\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "setStatus"
              ]
            },
            "example": "setStatus"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID to cancel",
            "example": 12345
          },
          {
            "name": "status",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                8
              ]
            },
            "description": "Use status=8 to cancel",
            "example": 8
          }
        ],
        "responses": {
          "200": {
            "description": "Always HTTP 200.",
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                },
                "examples": {
                  "cancelled": {
                    "summary": "Cancelled and refunded",
                    "value": "ACCESS_CANCEL"
                  },
                  "already_received": {
                    "summary": "Cannot cancel - SMS already received",
                    "value": "ACCESS_READY"
                  },
                  "not_found": {
                    "summary": "Invalid ID",
                    "value": "NO_ACTIVATION"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#getPrices": {
      "get": {
        "operationId": "compat_getPrices",
        "summary": "getPrices - Get all prices (country -> service)",
        "description": "Returns pricing and stock availability for all countries and services.\n\n**Note:** This is the one compat endpoint that returns JSON (not plain text). This matches sms-activate behavior.\n\n**Response structure:** `{ \"country_code\": { \"service_code\": { \"cost\": \"0.50\", \"count\": 87 } } }`\n\nStock counts are capped at 100 to prevent inventory intelligence gathering.\n\nFilter by `service` or `country` to get a subset.\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getPrices"
              ]
            },
            "example": "getPrices"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter to specific service code",
            "example": "wa"
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Filter to specific numeric country code",
            "example": 187
          }
        ],
        "responses": {
          "200": {
            "description": "JSON price matrix",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "object",
                      "properties": {
                        "cost": {
                          "type": "string",
                          "example": "0.50"
                        },
                        "count": {
                          "type": "integer",
                          "example": 87
                        }
                      }
                    }
                  }
                },
                "example": {
                  "22": {
                    "wa": {
                      "cost": "0.80",
                      "count": 26
                    },
                    "tg": {
                      "cost": "0.75",
                      "count": 19
                    }
                  },
                  "187": {
                    "wa": {
                      "cost": "0.50",
                      "count": 100
                    },
                    "tg": {
                      "cost": "0.45",
                      "count": 87
                    },
                    "go": {
                      "cost": "2.00",
                      "count": 12
                    },
                    "ds": {
                      "cost": "0.40",
                      "count": 45
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#getPricesVerification": {
      "get": {
        "operationId": "compat_getPricesVerification",
        "summary": "getPricesVerification - Get prices (service -> country)",
        "description": "Same data as getPrices but with the nesting order transposed:\nservice -> country -> pricing data.\n\n**Response structure:** `{ \"service_code\": { \"country_code\": { \"cost\": \"0.50\", \"count\": 87 } } }`\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getPricesVerification"
              ]
            },
            "example": "getPricesVerification"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          }
        ],
        "responses": {
          "200": {
            "description": "JSON price matrix (transposed)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "object",
                      "properties": {
                        "cost": {
                          "type": "string"
                        },
                        "count": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                },
                "example": {
                  "wa": {
                    "22": {
                      "cost": "0.80",
                      "count": 26
                    },
                    "187": {
                      "cost": "0.50",
                      "count": 100
                    }
                  },
                  "tg": {
                    "22": {
                      "cost": "0.75",
                      "count": 19
                    },
                    "187": {
                      "cost": "0.45",
                      "count": 87
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/stubs/handler_api.php#getNumbersStatus": {
      "get": {
        "operationId": "compat_getNumbersStatus",
        "summary": "getNumbersStatus - Stock by service for a country",
        "description": "Returns available number counts per service for a given country.\n\n**Response:** JSON object mapping service code to available count. Counts capped at 100.\n",
        "tags": [
          "sms-activate Compatibility"
        ],
        "security": [],
        "parameters": [
          {
            "name": "action",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "getNumbersStatus"
              ]
            },
            "example": "getNumbersStatus"
          },
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "country",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Numeric country code",
            "example": 187
          }
        ],
        "responses": {
          "200": {
            "description": "JSON map of service -> available count",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": {
                    "type": "integer"
                  }
                },
                "example": {
                  "wa": 100,
                  "tg": 87,
                  "go": 12,
                  "ds": 45,
                  "fb": 23,
                  "ig": 31,
                  "oi": 8
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/register": {
      "post": {
        "operationId": "auth_register",
        "summary": "Register a new account",
        "description": "Create a new VirtualSMS account. After registration, generate an API key in Settings to use the API.\n\nAlternatively, use Google OAuth or Telegram Login available on the web dashboard.\n",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthRegisterRequest"
              },
              "example": {
                "email": "user@example.com",
                "password": "secure123"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created successfully",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/AuthResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "example": "user@example.com"
                        }
                      }
                    }
                  ]
                },
                "example": {
                  "user_id": "550e8400-e29b-41d4-a716-446655440000",
                  "email": "user@example.com",
                  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
                }
              }
            }
          },
          "400": {
            "description": "Invalid parameters",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "INVALID_PARAMS",
                  "message": "Email already in use"
                }
              }
            }
          },
          "422": {
            "description": "Validation error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/auth/login": {
      "post": {
        "operationId": "auth_login",
        "summary": "Login to your account",
        "description": "Authenticate and receive a JWT token. Use the token as `Authorization: Bearer <token>` for subsequent requests,\nor generate a persistent API key in Settings.\n",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthLoginRequest"
              },
              "example": {
                "email": "user@example.com",
                "password": "secure123"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Login successful",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                },
                "example": {
                  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                  "user_id": "550e8400-e29b-41d4-a716-446655440000",
                  "expires_at": "2026-03-04T12:00:00Z"
                }
              }
            }
          },
          "401": {
            "description": "Invalid credentials",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "UNAUTHORIZED",
                  "message": "Invalid email or password"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/balance": {
      "get": {
        "operationId": "balance_get",
        "summary": "Get account balance",
        "description": "Returns your current USD balance.",
        "tags": [
          "Numbers"
        ],
        "responses": {
          "200": {
            "description": "Balance returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceResponse"
                },
                "example": {
                  "balance": 50.3,
                  "currency": "USD"
                }
              }
            }
          },
          "401": {
            "description": "Unauthorized",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/services": {
      "get": {
        "operationId": "services_list",
        "summary": "List available services and prices",
        "description": "Returns all available SMS verification services with current prices and stock levels.\n\nFilter by country to see which services are available in a specific region.\n",
        "tags": [
          "Services"
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by ISO 3166-1 alpha-2 country code",
            "example": "US"
          }
        ],
        "responses": {
          "200": {
            "description": "List of available services",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/ServiceItem"
                  }
                },
                "example": [
                  {
                    "service_id": "whatsapp",
                    "service_code": "wa",
                    "name": "WhatsApp",
                    "price": 0.5,
                    "available": 100,
                    "countries": [
                      "US",
                      "GB",
                      "DE",
                      "FR",
                      "HR",
                      "PL"
                    ]
                  },
                  {
                    "service_id": "telegram",
                    "service_code": "tg",
                    "name": "Telegram",
                    "price": 0.45,
                    "available": 87,
                    "countries": [
                      "US",
                      "GB",
                      "DE",
                      "FR",
                      "HR"
                    ]
                  },
                  {
                    "service_id": "google",
                    "service_code": "go",
                    "name": "Google",
                    "price": 2,
                    "available": 12,
                    "countries": [
                      "US",
                      "GB"
                    ]
                  },
                  {
                    "service_id": "discord",
                    "service_code": "ds",
                    "name": "Discord",
                    "price": 0.4,
                    "available": 45,
                    "countries": [
                      "US",
                      "GB",
                      "FR"
                    ]
                  },
                  {
                    "service_id": "instagram",
                    "service_code": "ig",
                    "name": "Instagram",
                    "price": 0.6,
                    "available": 31,
                    "countries": [
                      "US",
                      "GB",
                      "DE"
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/numbers/rent": {
      "post": {
        "operationId": "numbers_rent",
        "summary": "Rent a phone number",
        "description": "Rent a phone number for SMS verification. Returns immediately with the assigned phone number.\n\n**After renting:**\n- Poll `GET /api/v1/numbers/{id}/status` every 3-5 seconds, OR\n- Use WebSocket `wss://virtualsms.io/ws/orders?api_key=...&order_id={id}` for instant delivery, OR\n- Register a webhook at `POST /api/v1/webhooks` to receive push notifications\n\n**Always** call `/done` or `/cancel` when finished to free your slot.\nDefault concurrent limit: 20 active rentals per account.\n",
        "tags": [
          "Numbers"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RentRequest"
              },
              "examples": {
                "basic": {
                  "summary": "Basic WhatsApp rental (US)",
                  "value": {
                    "service": "whatsapp",
                    "country": "US",
                    "max_price": 0.75
                  }
                },
                "with_area_code": {
                  "summary": "With area code filter (Phase 2)",
                  "value": {
                    "service": "whatsapp",
                    "country": "US",
                    "max_price": 1,
                    "areas": [
                      "212",
                      "718",
                      "646"
                    ]
                  }
                },
                "uk_telegram": {
                  "summary": "UK Telegram number",
                  "value": {
                    "service": "telegram",
                    "country": "GB",
                    "max_price": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Number rented successfully",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RentalResponse"
                },
                "example": {
                  "rental_id": 12345,
                  "phone": "+13476711222",
                  "service": "whatsapp",
                  "country": "US",
                  "price_charged": 0.5,
                  "expires_at": "2026-03-03T15:00:00Z",
                  "status": "waiting"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "INSUFFICIENT_BALANCE",
                  "message": "Your balance ($0.30) is less than the rental price ($0.50)"
                }
              }
            }
          },
          "422": {
            "description": "Cannot fulfill request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "examples": {
                  "no_numbers": {
                    "summary": "Out of stock",
                    "value": {
                      "error": "NO_NUMBERS",
                      "message": "No numbers available for WhatsApp in US",
                      "service": "whatsapp",
                      "country": "US"
                    }
                  },
                  "max_price": {
                    "summary": "Price too high",
                    "value": {
                      "error": "MAX_PRICE_EXCEEDED",
                      "message": "Current price ($0.80) exceeds your max_price ($0.75)"
                    }
                  },
                  "too_many": {
                    "summary": "Concurrent limit",
                    "value": {
                      "error": "TOO_MANY_RENTALS",
                      "message": "You have 20 active rentals. Mark some as done before renting more."
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/numbers/{id}/status": {
      "get": {
        "operationId": "numbers_status",
        "summary": "Get rental status and SMS code",
        "description": "Poll the status of a rental. Returns `waiting` until SMS arrives, then `received` with the extracted code.\n\n**Poll interval:** Minimum 3 seconds between polls. Better: use WebSocket or webhooks.\n\n**Status values:**\n- `waiting` - No SMS yet, keep polling\n- `received` - SMS arrived! Read `sms_code` and `sms_text`\n- `done` - You called /done\n- `cancelled` - Cancelled (via /cancel or automatic timeout)\n",
        "tags": [
          "Numbers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID from the rent response",
            "example": 12345
          }
        ],
        "responses": {
          "200": {
            "description": "Rental status",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RentalStatus"
                },
                "examples": {
                  "waiting": {
                    "summary": "Still waiting",
                    "value": {
                      "rental_id": 12345,
                      "status": "waiting",
                      "sms_code": null,
                      "sms_text": null,
                      "received_at": null
                    }
                  },
                  "received": {
                    "summary": "SMS received",
                    "value": {
                      "rental_id": 12345,
                      "status": "received",
                      "sms_code": "438271",
                      "sms_text": "Your WhatsApp code is 438271. Don't share this code.",
                      "received_at": "2026-03-03T14:22:11Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Rental not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "NOT_FOUND",
                  "message": "Rental 12345 not found"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/numbers/{id}/done": {
      "post": {
        "operationId": "numbers_done",
        "summary": "Mark rental as done",
        "description": "Signal that you've successfully used the verification code.\nFrees your active rental slot for the next rental.\n\n**Always call this** after you're done - otherwise you'll quickly hit the 20-concurrent-rental limit.\n",
        "tags": [
          "Numbers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID to mark as done",
            "example": 12345
          }
        ],
        "responses": {
          "200": {
            "description": "Rental marked as done",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rental_id": {
                      "type": "integer",
                      "example": 12345
                    },
                    "status": {
                      "type": "string",
                      "example": "done"
                    }
                  }
                },
                "example": {
                  "rental_id": 12345,
                  "status": "done"
                }
              }
            }
          },
          "404": {
            "description": "Rental not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/numbers/{id}/cancel": {
      "post": {
        "operationId": "numbers_cancel",
        "summary": "Cancel rental and refund",
        "description": "Cancels a rental and refunds the full amount to your balance.\n\n**Only works if no SMS has been received yet.** If SMS already arrived, returns 409 Conflict.\n",
        "tags": [
          "Numbers"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID to cancel",
            "example": 12345
          }
        ],
        "responses": {
          "200": {
            "description": "Rental cancelled and balance refunded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rental_id": {
                      "type": "integer",
                      "example": 12345
                    },
                    "status": {
                      "type": "string",
                      "example": "cancelled"
                    },
                    "refunded": {
                      "type": "number",
                      "format": "float",
                      "example": 0.5
                    }
                  }
                },
                "example": {
                  "rental_id": 12345,
                  "status": "cancelled",
                  "refunded": 0.5
                }
              }
            }
          },
          "404": {
            "description": "Rental not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          },
          "409": {
            "description": "Cannot cancel - SMS already received",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                },
                "example": {
                  "error": "ALREADY_RECEIVED",
                  "message": "Cannot cancel after SMS received. Call /done instead."
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rentals": {
      "get": {
        "operationId": "rentals_list",
        "summary": "List rental history",
        "description": "Returns paginated rental history with optional filters.",
        "tags": [
          "Numbers"
        ],
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            },
            "example": 1
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 50,
              "maximum": 100
            },
            "example": 50
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by service name",
            "example": "whatsapp"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "waiting",
                "received",
                "done",
                "cancelled"
              ]
            },
            "description": "Filter by status",
            "example": "done"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of rentals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rentals": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/RentalStatus"
                      }
                    },
                    "total": {
                      "type": "integer",
                      "example": 142
                    },
                    "page": {
                      "type": "integer",
                      "example": 1
                    },
                    "limit": {
                      "type": "integer",
                      "example": 50
                    }
                  }
                },
                "example": {
                  "rentals": [
                    {
                      "rental_id": 12345,
                      "status": "done",
                      "sms_code": "438271",
                      "sms_text": "Your WhatsApp code is 438271.",
                      "received_at": "2026-03-03T14:22:11Z"
                    },
                    {
                      "rental_id": 12344,
                      "status": "cancelled",
                      "sms_code": null,
                      "sms_text": null,
                      "received_at": null
                    }
                  ],
                  "total": 142,
                  "page": 1,
                  "limit": 50
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "rentals_create",
        "summary": "Create a dedicated rental (Full Access or Platform tier)",
        "description": "Creates a Full Access or Platform-tier dedicated rental (distinct from the one-time\n`/api/v1/numbers/rent` activation above). `rental_type=full` uses local inventory and\nworks for any service for the whole duration; `rental_type=service` (Platform tier)\nlocks the number to one `service`, sourced via our global supplier network, for the\nchosen duration — with an early-cancel refund window right after purchase.\n\nBrowse availability first at `GET /api/v1/rentals/available` (public, no auth) and\nconfirm price at `GET /api/v1/rentals/price` or `/api/v1/rentals/pricing`.\n",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "country",
                  "rental_type",
                  "duration_hours"
                ],
                "properties": {
                  "country": {
                    "type": "string",
                    "example": "US"
                  },
                  "service": {
                    "type": "string",
                    "description": "Required when rental_type=service (Platform tier)",
                    "example": "whatsapp"
                  },
                  "rental_type": {
                    "type": "string",
                    "enum": [
                      "full",
                      "service"
                    ],
                    "example": "full"
                  },
                  "duration_hours": {
                    "type": "integer",
                    "enum": [
                      24,
                      168,
                      720,
                      2160
                    ],
                    "description": "24=1 day, 168=7 days, 720=30 days, 2160=90 days",
                    "example": 24
                  },
                  "auto_renew": {
                    "type": "boolean",
                    "default": false
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Rental created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance"
          }
        }
      }
    },
    "/api/v1/rentals/{id}/cancel": {
      "post": {
        "operationId": "rentals_cancel",
        "summary": "Cancel a dedicated rental",
        "description": "Platform-tier rentals have an early-cancel refund window right after purchase.\nFull Access rentals are not refunded once created (you hold the number for the term).\n",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled (refund amount depends on tier + timing)"
          }
        }
      }
    },
    "/api/v1/rentals/{id}/extend": {
      "post": {
        "operationId": "rentals_extend",
        "summary": "Extend an active dedicated rental",
        "description": "Extends the current rental by an additional supported duration. No fixed cap on renewals — extend anytime the rental is still active.",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "duration_hours": {
                    "type": "integer",
                    "enum": [
                      24,
                      168,
                      720,
                      2160
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rental extended"
          }
        }
      }
    },
    "/api/v1/rentals/{id}/release": {
      "post": {
        "operationId": "rentals_release",
        "summary": "Release a dedicated rental early",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rental released"
          }
        }
      }
    },
    "/api/v1/webhooks": {
      "post": {
        "operationId": "webhooks_create",
        "summary": "Create webhook",
        "description": "Register a URL to receive instant push notifications when SMS arrives.\n\n**Payload your server will receive:**\n```json\n{\n  \"activationId\": 12345,\n  \"service\": \"wa\",\n  \"code\": \"438271\",\n  \"text\": \"Your WhatsApp code is 438271. Don't share this code.\",\n  \"country\": 187,\n  \"receivedAt\": \"2026-03-03 14:22:11\"\n}\n```\n\nIf `secret` is provided, each request includes `X-VirtualSMS-Signature: sha256=<hmac>` for verification.\n\n**Retry policy:** 8 retries, 15-second intervals, 3-second timeout per attempt.\n",
        "tags": [
          "Webhooks"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookCreate"
              },
              "example": {
                "url": "https://your-server.com/sms-callback",
                "secret": "my-signing-secret",
                "events": [
                  "sms.received"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Webhook created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookResponse"
                },
                "example": {
                  "id": "wh_abc123",
                  "url": "https://your-server.com/sms-callback",
                  "active": true,
                  "created_at": "2026-03-03T12:00:00Z",
                  "last_triggered": null,
                  "success_rate": 1
                }
              }
            }
          },
          "400": {
            "description": "Invalid webhook URL",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "webhooks_list",
        "summary": "List webhooks",
        "description": "Returns all registered webhooks for your account.",
        "tags": [
          "Webhooks"
        ],
        "responses": {
          "200": {
            "description": "List of webhooks",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/WebhookResponse"
                  }
                },
                "example": [
                  {
                    "id": "wh_abc123",
                    "url": "https://your-server.com/sms-callback",
                    "active": true,
                    "created_at": "2026-03-03T12:00:00Z",
                    "last_triggered": "2026-03-03T14:22:11Z",
                    "success_rate": 0.98
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/{id}": {
      "delete": {
        "operationId": "webhooks_delete",
        "summary": "Delete webhook",
        "description": "Removes a webhook. Push notifications for this URL will stop immediately.",
        "tags": [
          "Webhooks"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Webhook ID",
            "example": "wh_abc123"
          }
        ],
        "responses": {
          "204": {
            "description": "Webhook deleted successfully"
          },
          "404": {
            "description": "Webhook not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/ws/orders": {
      "get": {
        "operationId": "ws_orders",
        "summary": "WebSocket - Real-time SMS delivery",
        "description": "## WebSocket Connection\n\nConnect via WebSocket for instant SMS delivery - zero polling delay.\n\n**Endpoint:** `wss://virtualsms.io/ws/orders`\n\n**Query parameters:**\n- `api_key` - Your VirtualSMS API key (required)\n- `order_id` - Specific rental ID to subscribe to (required)\n\n**Example connection:**\n```javascript\nconst ws = new WebSocket(\n  `wss://virtualsms.io/ws/orders?api_key=${API_KEY}&order_id=${rentalId}`\n);\n\nws.onmessage = (event) => {\n  const data = JSON.parse(event.data);\n  \n  if (data.type === 'sms') {\n    console.log('Code:', data.code);\n    console.log('Full SMS:', data.text);\n    console.log('Received at:', data.ts);\n  } else if (data.type === 'expired') {\n    console.log('Rental expired');\n  }\n};\n```\n\n**Message types:**\n\n**SMS received:**\n```json\n{\n  \"type\": \"sms\",\n  \"rental_id\": 12345,\n  \"code\": \"438271\",\n  \"text\": \"Your WhatsApp code is 438271. Don't share this code.\",\n  \"ts\": \"2026-03-03T14:22:11Z\"\n}\n```\n\n**Rental expired:**\n```json\n{\n  \"type\": \"expired\",\n  \"rental_id\": 12345,\n  \"ts\": \"2026-03-03T14:35:00Z\"\n}\n```\n\n**Advantage over polling:** Instant delivery, no wasted requests, no 3-second delay.\nThis is our competitive advantage over legacy sms-activate style polling.\n",
        "tags": [
          "WebSocket"
        ],
        "parameters": [
          {
            "name": "api_key",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Your VirtualSMS API key",
            "example": "vsms_a3f8b2c1d4e5f6a7b8c9..."
          },
          {
            "name": "order_id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Rental ID to subscribe to",
            "example": 12345
          }
        ],
        "responses": {
          "101": {
            "description": "Switching Protocols - WebSocket connection established"
          },
          "401": {
            "description": "Invalid API key"
          }
        }
      }
    },
    "/api/v1/customer/balance": {
      "get": {
        "operationId": "customer_balance",
        "summary": "Get account balance",
        "description": "Returns your current USD balance.",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Balance returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "balance": {
                      "type": "number",
                      "format": "float",
                      "example": 34.46
                    }
                  }
                },
                "example": {
                  "success": true,
                  "balance": 34.46
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/customer/services": {
      "get": {
        "operationId": "customer_services",
        "summary": "List available services",
        "description": "Returns all SMS verification services available for purchase.\nBy default, only services with **physical SIM card** numbers are returned.\nAdd `include_voip=true` to also include VoIP-backed numbers.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "include_voip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include VoIP numbers in results (default false - physical SIM only)",
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "List of available services",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "services": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "service_id": {
                            "type": "string",
                            "example": "tg"
                          },
                          "service_name": {
                            "type": "string",
                            "example": "Telegram"
                          },
                          "base_price": {
                            "type": "number",
                            "format": "float",
                            "example": 0.2
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "success": true,
                  "services": [
                    {
                      "service_id": "tg",
                      "service_name": "Telegram",
                      "base_price": 0.2
                    },
                    {
                      "service_id": "wa",
                      "service_name": "WhatsApp",
                      "base_price": 0.5
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/customer/countries": {
      "get": {
        "operationId": "customer_countries",
        "summary": "List available countries",
        "description": "Returns countries where numbers are available.\n- **Without `service` filter:** Returns all countries with available numbers, including which services are available per country.\n- **With `service` filter:** Returns countries for that specific service with exact pricing.\n\nBy default, only **physical SIM card** numbers are included. Add `include_voip=true` for VoIP numbers.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Filter by service code (e.g. tg, wa, ig). Returns per-service pricing when set.",
            "example": "tg"
          },
          {
            "name": "include_voip",
            "in": "query",
            "required": false,
            "schema": {
              "type": "boolean",
              "default": false
            },
            "description": "Include VoIP numbers (default false - physical SIM only)",
            "example": false
          }
        ],
        "responses": {
          "200": {
            "description": "List of countries",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "countries": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                },
                "examples": {
                  "without_service_filter": {
                    "summary": "All countries (no service filter)",
                    "value": {
                      "success": true,
                      "countries": [
                        {
                          "country_id": "ID",
                          "country_name": "Indonesia",
                          "min_price": 0.05,
                          "services": "tg,wa,ig"
                        },
                        {
                          "country_id": "PH",
                          "country_name": "Philippines",
                          "min_price": 0.1,
                          "services": "tg,wa"
                        }
                      ]
                    }
                  },
                  "with_service_filter": {
                    "summary": "Countries for a specific service",
                    "value": {
                      "success": true,
                      "countries": [
                        {
                          "country_id": "ID",
                          "country_name": "Indonesia",
                          "price": 0.4,
                          "service_id": "tg"
                        },
                        {
                          "country_id": "PH",
                          "country_name": "Philippines",
                          "price": 0.35,
                          "service_id": "tg"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/price": {
      "get": {
        "operationId": "price_get",
        "summary": "Get price for service/country combination",
        "description": "Public endpoint - no authentication required.\nReturns the current price for a specific service and country combination.\n",
        "tags": [
          "Customer API"
        ],
        "security": [],
        "parameters": [
          {
            "name": "service",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Service code (e.g. tg, wa, ig)",
            "example": "tg"
          },
          {
            "name": "country",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "ISO country code (e.g. ID, PH, US)",
            "example": "ID"
          }
        ],
        "responses": {
          "200": {
            "description": "Price returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "price": {
                      "type": "number",
                      "format": "float",
                      "example": 0.4
                    },
                    "service": {
                      "type": "string",
                      "example": "tg"
                    },
                    "country": {
                      "type": "string",
                      "example": "ID"
                    },
                    "service_name": {
                      "type": "string",
                      "example": "Telegram"
                    },
                    "country_name": {
                      "type": "string",
                      "example": "Indonesia"
                    },
                    "estimated": {
                      "type": "boolean",
                      "example": false
                    }
                  }
                },
                "example": {
                  "success": true,
                  "price": 0.4,
                  "service": "tg",
                  "country": "ID",
                  "service_name": "Telegram",
                  "country_name": "Indonesia",
                  "estimated": false
                }
              }
            }
          },
          "404": {
            "description": "Service/country combination not available",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": false
                    },
                    "error": {
                      "type": "string",
                      "example": "Service/country combination not available"
                    }
                  }
                },
                "example": {
                  "success": false,
                  "error": "Service/country combination not available"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/profile": {
      "get": {
        "operationId": "customer_profile",
        "summary": "Get account profile",
        "description": "Returns account metadata including email, Telegram link status, lifetime stats, and active API key count.",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Profile returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "format": "uuid",
                      "example": "550e8400-e29b-41d4-a716-446655440000"
                    },
                    "email": {
                      "type": "string",
                      "format": "email",
                      "example": "user@example.com"
                    },
                    "telegram_linked": {
                      "type": "boolean",
                      "example": true
                    },
                    "telegram_username": {
                      "type": "string",
                      "example": "myhandle"
                    },
                    "balance_usd": {
                      "type": "number",
                      "format": "float",
                      "example": 25.5
                    },
                    "total_spent_usd": {
                      "type": "number",
                      "format": "float",
                      "example": 120
                    },
                    "total_credits_usd": {
                      "type": "number",
                      "format": "float",
                      "example": 5
                    },
                    "total_orders": {
                      "type": "integer",
                      "example": 47
                    },
                    "active_api_keys": {
                      "type": "integer",
                      "example": 2
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time",
                      "example": "2024-01-15T10:00:00Z"
                    }
                  }
                },
                "example": {
                  "id": "550e8400-e29b-41d4-a716-446655440000",
                  "email": "user@example.com",
                  "telegram_linked": true,
                  "telegram_username": "myhandle",
                  "balance_usd": 25.5,
                  "total_spent_usd": 120,
                  "total_credits_usd": 5,
                  "total_orders": 47,
                  "active_api_keys": 2,
                  "created_at": "2024-01-15T10:00:00Z"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/customer/transactions": {
      "get": {
        "operationId": "customer_transactions",
        "summary": "List transaction history",
        "description": "Returns a paginated list of account transactions — every balance movement (deposits, purchases, refunds, credits).\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "deposit",
                "purchase",
                "refund",
                "credit"
              ]
            },
            "description": "Filter by transaction type",
            "example": "purchase"
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "ISO 8601 timestamp — earliest transaction to include",
            "example": "2024-01-01T00:00:00Z"
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "ISO 8601 timestamp — latest transaction to include",
            "example": "2024-12-31T23:59:59Z"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 50
            },
            "description": "Results per page (max 100, default 50)",
            "example": 20
          },
          {
            "name": "offset",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 0,
              "default": 0
            },
            "description": "Pagination offset (default 0)",
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "Transaction list returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer",
                      "description": "Total matching transactions across all pages",
                      "example": 142
                    },
                    "limit": {
                      "type": "integer",
                      "example": 20
                    },
                    "offset": {
                      "type": "integer",
                      "example": 0
                    },
                    "transactions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "txn_abc123"
                          },
                          "amount": {
                            "type": "number",
                            "format": "float",
                            "description": "Negative for debits, positive for credits",
                            "example": -0.5
                          },
                          "type": {
                            "type": "string",
                            "enum": [
                              "deposit",
                              "purchase",
                              "refund",
                              "credit"
                            ],
                            "example": "purchase"
                          },
                          "description": {
                            "type": "string",
                            "example": "Purchase: Telegram ID number"
                          },
                          "order_id": {
                            "type": "string",
                            "format": "uuid",
                            "nullable": true,
                            "example": "550e8400-e29b-41d4-a716-446655440000"
                          },
                          "balance_before": {
                            "type": "number",
                            "format": "float",
                            "example": 26
                          },
                          "balance_after": {
                            "type": "number",
                            "format": "float",
                            "example": 25.5
                          },
                          "created_at": {
                            "type": "string",
                            "format": "date-time",
                            "example": "2024-02-24T12:05:00Z"
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "count": 142,
                  "limit": 20,
                  "offset": 0,
                  "transactions": [
                    {
                      "id": "txn_abc123",
                      "amount": -0.4,
                      "type": "purchase",
                      "description": "Purchase: Telegram ID number",
                      "order_id": "550e8400-e29b-41d4-a716-446655440000",
                      "balance_before": 26,
                      "balance_after": 25.6,
                      "created_at": "2024-02-24T12:05:00Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/customer/purchase": {
      "post": {
        "operationId": "customer_purchase",
        "summary": "Purchase a phone number",
        "description": "Purchase an SMS verification number. Balance is deducted immediately.\n\nAfter purchase, poll `GET /api/v1/customer/order/{orderId}` every 3-5 seconds for SMS,\nor connect to `wss://virtualsms.io/ws/orders` for real-time delivery.\n\n**Cancel/swap policy:** Orders can be cancelled or swapped after a **2-minute hold period**\nfrom the time of purchase. This prevents abuse.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "service",
                  "country"
                ],
                "properties": {
                  "service": {
                    "type": "string",
                    "description": "Service code (e.g. tg, wa, ig)",
                    "example": "tg"
                  },
                  "country": {
                    "type": "string",
                    "description": "ISO country code (e.g. ID, PH, US)",
                    "example": "ID"
                  }
                }
              },
              "example": {
                "service": "tg",
                "country": "ID"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Number purchased successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "order_id": {
                      "type": "string",
                      "format": "uuid",
                      "example": "550e8400-e29b-41d4-a716-446655440000"
                    },
                    "phone_number": {
                      "type": "string",
                      "example": "628123456789"
                    },
                    "service": {
                      "type": "string",
                      "example": "tg"
                    },
                    "country": {
                      "type": "string",
                      "example": "ID"
                    },
                    "price": {
                      "type": "number",
                      "format": "float",
                      "example": 0.4
                    },
                    "status": {
                      "type": "string",
                      "example": "waiting"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time",
                      "example": "2026-03-14T16:00:00+08:00"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "order_id": "550e8400-e29b-41d4-a716-446655440000",
                  "phone_number": "628123456789",
                  "service": "tg",
                  "country": "ID",
                  "price": 0.4,
                  "status": "waiting",
                  "expires_at": "2026-03-14T16:00:00+08:00"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          },
          "402": {
            "description": "Insufficient balance",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Insufficient balance"
                    },
                    "required": {
                      "type": "number",
                      "format": "float",
                      "example": 0.4
                    },
                    "current": {
                      "type": "number",
                      "format": "float",
                      "example": 0.1
                    }
                  }
                },
                "example": {
                  "error": "Insufficient balance",
                  "required": 0.4,
                  "current": 0.1
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/order/{orderId}": {
      "get": {
        "operationId": "customer_order_get",
        "summary": "Get order status",
        "description": "Get the current status of an order. Poll every 3-5 seconds until SMS arrives,\nor use WebSocket for real-time delivery.\n\nThe `messages` array will be empty while waiting, and populated once SMS is received.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Order ID from the purchase response",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        ],
        "responses": {
          "200": {
            "description": "Order status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean"
                    },
                    "order_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "phone_number": {
                      "type": "string"
                    },
                    "service": {
                      "type": "string"
                    },
                    "country": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "waiting",
                        "completed",
                        "cancelled",
                        "expired"
                      ]
                    },
                    "price": {
                      "type": "number",
                      "format": "float"
                    },
                    "sms_received": {
                      "type": "boolean"
                    },
                    "created_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "messages": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sender": {
                            "type": "string"
                          },
                          "content": {
                            "type": "string"
                          },
                          "received_at": {
                            "type": "string",
                            "format": "date-time"
                          }
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "waiting": {
                    "summary": "Waiting for SMS",
                    "value": {
                      "success": true,
                      "order_id": "550e8400-e29b-41d4-a716-446655440000",
                      "phone_number": "628123456789",
                      "service": "tg",
                      "country": "ID",
                      "status": "waiting",
                      "price": 0.4,
                      "sms_received": false,
                      "created_at": "2026-03-14T15:00:00+08:00",
                      "expires_at": "2026-03-14T16:00:00+08:00",
                      "messages": []
                    }
                  },
                  "received": {
                    "summary": "SMS received",
                    "value": {
                      "success": true,
                      "order_id": "550e8400-e29b-41d4-a716-446655440000",
                      "phone_number": "628123456789",
                      "service": "tg",
                      "country": "ID",
                      "status": "completed",
                      "price": 0.4,
                      "sms_received": true,
                      "created_at": "2026-03-14T15:00:00+08:00",
                      "expires_at": "2026-03-14T16:00:00+08:00",
                      "messages": [
                        {
                          "sender": "Telegram",
                          "content": "Your code is 12345",
                          "received_at": "2026-03-14T15:05:30+08:00"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          },
          "404": {
            "description": "Order not found"
          }
        }
      }
    },
    "/api/v1/customer/cancel/{orderId}": {
      "post": {
        "operationId": "customer_cancel",
        "summary": "Cancel an order",
        "description": "Cancel a pending order and receive a full refund.\n\n**2-minute hold:** Orders cannot be cancelled within the first 2 minutes of purchase.\nThis is to prevent abuse. If you try to cancel too early, you'll get a 425 response\ntelling you how many seconds to wait.\n\nCancellation is only possible while the order is in `waiting` status (no SMS received).\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Order ID to cancel",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        ],
        "responses": {
          "200": {
            "description": "Order cancelled and refunded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "order_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "status": {
                      "type": "string",
                      "example": "cancelled"
                    },
                    "refund_amount": {
                      "type": "number",
                      "format": "float",
                      "example": 0.4
                    }
                  }
                },
                "example": {
                  "success": true,
                  "order_id": "550e8400-e29b-41d4-a716-446655440000",
                  "status": "cancelled",
                  "refund_amount": 0.4
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          },
          "404": {
            "description": "Order not found"
          },
          "425": {
            "description": "Too early to cancel - 2-minute hold period active",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Cannot cancel within 2 minutes of purchase. Please wait 82 seconds."
                    },
                    "seconds_remaining": {
                      "type": "integer",
                      "example": 82
                    }
                  }
                },
                "example": {
                  "error": "Cannot cancel within 2 minutes of purchase. Please wait 82 seconds.",
                  "seconds_remaining": 82
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/swap/{orderId}": {
      "post": {
        "operationId": "customer_swap",
        "summary": "Swap for a different number",
        "description": "Swap the current number for a different one with the same service and country.\nThe old order is cancelled (refunded) and a new order is created automatically.\n\n**2-minute hold:** Same as cancel - swaps cannot be initiated within the first 2 minutes\nof purchase. The 425 response tells you exactly how many seconds to wait.\n\nUse swap when the number isn't receiving SMS - it gives you a fresh number without\nleaving your app and re-purchasing manually.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "orderId",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "Order ID to swap",
            "example": "550e8400-e29b-41d4-a716-446655440000"
          }
        ],
        "responses": {
          "200": {
            "description": "Number swapped successfully",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "old_order_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "new_order_id": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "phone_number": {
                      "type": "string",
                      "example": "628987654321"
                    },
                    "service": {
                      "type": "string",
                      "example": "tg"
                    },
                    "country": {
                      "type": "string",
                      "example": "ID"
                    },
                    "price": {
                      "type": "number",
                      "format": "float",
                      "example": 0.4
                    },
                    "status": {
                      "type": "string",
                      "example": "waiting"
                    },
                    "expires_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "old_order_id": "550e8400-e29b-41d4-a716-446655440000",
                  "new_order_id": "661f9500-f3ac-52e5-b827-557766551111",
                  "phone_number": "628987654321",
                  "service": "tg",
                  "country": "ID",
                  "price": 0.4,
                  "status": "waiting",
                  "expires_at": "2026-03-14T16:30:00+08:00"
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          },
          "404": {
            "description": "Order not found"
          },
          "425": {
            "description": "Too early to swap - 2-minute hold period active",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "Cannot cancel within 2 minutes of purchase. Please wait 82 seconds."
                    },
                    "seconds_remaining": {
                      "type": "integer",
                      "example": 82
                    }
                  }
                },
                "example": {
                  "error": "Cannot cancel within 2 minutes of purchase. Please wait 82 seconds.",
                  "seconds_remaining": 82
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/customer/orders": {
      "get": {
        "operationId": "customer_orders_list",
        "summary": "List orders",
        "description": "Returns your order history. Optionally filter by status.\n",
        "tags": [
          "Customer API"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "waiting",
                "cancelled",
                "completed",
                "expired"
              ]
            },
            "description": "Filter by order status",
            "example": "waiting"
          }
        ],
        "responses": {
          "200": {
            "description": "List of orders",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "example": true
                    },
                    "orders": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "count": {
                      "type": "integer",
                      "example": 50
                    }
                  }
                },
                "example": {
                  "success": true,
                  "orders": [
                    {
                      "order_id": "550e8400-e29b-41d4-a716-446655440000",
                      "phone_number": "628123456789",
                      "service": "tg",
                      "country": "ID",
                      "status": "completed",
                      "price": 0.4,
                      "sms_received": true,
                      "created_at": "2026-03-14T15:00:00+08:00",
                      "expires_at": "2026-03-14T16:00:00+08:00"
                    }
                  ],
                  "count": 50
                }
              }
            }
          },
          "401": {
            "description": "Invalid or missing API key"
          }
        }
      }
    },
    "/api/v1/rentals/available": {
      "get": {
        "operationId": "rentals_available",
        "summary": "Browse available rentals (public)",
        "description": "No authentication required. Merges live slot inventory with catalog pricing so you can\nbrowse both Full Access and Platform rentals by country before creating an account.\n",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO 3166-1 alpha-2 country code filter",
            "example": "US"
          }
        ],
        "responses": {
          "200": {
            "description": "Available rentals for the given country (or all countries if omitted)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "countries": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "total_available": {
                      "type": "integer"
                    }
                  }
                },
                "example": {
                  "countries": [
                    {
                      "country_code": "US",
                      "country_name": "United States",
                      "full": {
                        "available": 12,
                        "price_1d": 4.99
                      },
                      "platform": {
                        "available": 40,
                        "price_1d": 2
                      }
                    }
                  ],
                  "total_available": 52
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rentals/pricing": {
      "get": {
        "operationId": "rentals_pricing",
        "summary": "Full rental pricing catalog",
        "description": "Returns the complete Full Access rental pricing matrix (country x duration).",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Pricing rows",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "base_price": {
                        "type": "number",
                        "format": "float"
                      },
                      "country_code": {
                        "type": "string"
                      },
                      "duration_hours": {
                        "type": "integer",
                        "enum": [
                          24,
                          168,
                          720,
                          2160
                        ]
                      },
                      "duration_label": {
                        "type": "string"
                      },
                      "rental_type": {
                        "type": "string",
                        "enum": [
                          "full",
                          "service"
                        ]
                      }
                    }
                  }
                },
                "example": [
                  {
                    "base_price": 4.99,
                    "country_code": "US",
                    "duration_hours": 24,
                    "duration_label": "1 Day",
                    "rental_type": "full"
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/rentals/services": {
      "get": {
        "operationId": "rentals_services",
        "summary": "Platform-tier rental catalog (service-locked)",
        "description": "Returns services available for a Platform-tier rental (locked to one service for the\nrental duration) in a given country, with per-service pricing and live stock.\n",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [],
        "parameters": [
          {
            "name": "country_code",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "GR"
          },
          {
            "name": "duration",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer"
            },
            "description": "Duration in hours",
            "example": 24
          }
        ],
        "responses": {
          "200": {
            "description": "List of rentable services for the country",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "service_id": {
                        "type": "string"
                      },
                      "service_name": {
                        "type": "string"
                      },
                      "our_price": {
                        "type": "number",
                        "format": "float"
                      },
                      "popular": {
                        "type": "boolean"
                      },
                      "icon_url": {
                        "type": "string"
                      }
                    }
                  }
                },
                "example": [
                  {
                    "service_id": "abc",
                    "service_name": "WhatsApp",
                    "our_price": 2,
                    "popular": true,
                    "icon_url": "https://virtualsms.io/icons/whatsapp.png"
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/v1/rentals/price": {
      "get": {
        "operationId": "rentals_price",
        "summary": "Confirm price for a specific rental",
        "description": "Confirms current price before creating a rental. Both parameters required.",
        "tags": [
          "Dedicated Rentals"
        ],
        "security": [],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "example": "US"
          },
          {
            "name": "service",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Required for Platform-tier (service-locked) pricing; omit for Full Access.",
            "example": "whatsapp"
          },
          {
            "name": "days",
            "in": "query",
            "required": true,
            "schema": {
              "type": "integer",
              "enum": [
                1,
                7,
                30,
                90
              ]
            },
            "example": 7
          }
        ],
        "responses": {
          "200": {
            "description": "Confirmed price",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "price": {
                      "type": "number",
                      "format": "float"
                    },
                    "country": {
                      "type": "string"
                    },
                    "days": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": {
                      "type": "string",
                      "example": "service and duration are required"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/proxies/catalog": {
      "get": {
        "operationId": "proxies_catalog",
        "summary": "Browse proxy pools, countries and pricing (public)",
        "description": "No authentication required, ~10 minute cache. Returns each pool type (residential,\nmobile, datacenter) with price-per-GB and per-country availability + IP counts.\n",
        "tags": [
          "Proxies"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Proxy catalog",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "pool_types": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "residential"
                          },
                          "label": {
                            "type": "string",
                            "example": "Residential"
                          },
                          "price_per_gb": {
                            "type": "number",
                            "format": "float",
                            "example": 3.49
                          },
                          "countries": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "code": {
                                  "type": "string",
                                  "example": "us"
                                },
                                "name": {
                                  "type": "string",
                                  "example": "United States"
                                },
                                "available": {
                                  "type": "boolean"
                                },
                                "ip_count": {
                                  "type": "integer",
                                  "example": 117986
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Proxies feature not enabled"
          }
        }
      }
    },
    "/api/v1/proxies/locations": {
      "get": {
        "operationId": "proxies_locations",
        "summary": "List cities/ASNs for a pool + country (public)",
        "description": "No authentication required, 6h cache. Always active regardless of the proxies feature flag.",
        "tags": [
          "Proxies"
        ],
        "security": [],
        "parameters": [
          {
            "name": "pool_type",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "residential",
                "mobile",
                "datacenter"
              ]
            }
          },
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "ISO-2 lowercase country code",
            "example": "us"
          }
        ],
        "responses": {
          "200": {
            "description": "Cities/states/ASNs available for targeting",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid pool_type"
          }
        }
      }
    },
    "/api/v1/proxies": {
      "get": {
        "operationId": "proxies_list",
        "summary": "List your purchased proxies",
        "tags": [
          "Proxies"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Your proxies",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "proxy_id": {
                        "type": "string"
                      },
                      "pool_type": {
                        "type": "string"
                      },
                      "country_code": {
                        "type": "string"
                      },
                      "country_name": {
                        "type": "string"
                      },
                      "gb_total": {
                        "type": "number"
                      },
                      "gb_used": {
                        "type": "number"
                      },
                      "gb_remaining": {
                        "type": "number"
                      },
                      "proxy_host": {
                        "type": "string"
                      },
                      "proxy_port": {
                        "type": "integer"
                      },
                      "proxy_login": {
                        "type": "string"
                      },
                      "proxy_password": {
                        "type": "string"
                      },
                      "created_at": {
                        "type": "string",
                        "format": "date-time"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "proxies_buy",
        "summary": "Buy a proxy (GB pack in a pool + country)",
        "tags": [
          "Proxies"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "pool_type",
                  "gb"
                ],
                "properties": {
                  "pool_type": {
                    "type": "string",
                    "enum": [
                      "residential",
                      "mobile",
                      "datacenter"
                    ]
                  },
                  "gb": {
                    "type": "number",
                    "format": "float",
                    "example": 1
                  },
                  "country_code": {
                    "type": "string",
                    "description": "Optional preferred country for sticky sessions",
                    "example": "us"
                  },
                  "idempotency_key": {
                    "type": "string",
                    "description": "Optional; derived from request fields if omitted"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Proxy purchased — connection details returned once, store them",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "proxy_id": {
                      "type": "string"
                    },
                    "proxy_host": {
                      "type": "string"
                    },
                    "proxy_port": {
                      "type": "integer"
                    },
                    "proxy_login": {
                      "type": "string"
                    },
                    "proxy_password": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "402": {
            "description": "Insufficient balance"
          }
        }
      }
    },
    "/api/v1/proxies/{id}/usage": {
      "get": {
        "operationId": "proxies_usage",
        "summary": "Get cached GB usage for a proxy",
        "tags": [
          "Proxies"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Usage snapshot",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "gb_used": {
                      "type": "number"
                    },
                    "gb_remaining": {
                      "type": "number"
                    },
                    "requests": {
                      "type": "integer"
                    },
                    "updated_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/proxies/{id}/rotate": {
      "post": {
        "operationId": "proxies_rotate",
        "summary": "Rotate to a new exit IP",
        "description": "30-second cooldown between rotations on the same proxy.",
        "tags": [
          "Proxies"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "port": {
                    "type": "integer",
                    "description": "0 = default HTTP rotating port (823)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Rotated to a new IP"
          },
          "429": {
            "description": "Rotation cooldown active (30s)"
          }
        }
      }
    },
    "/api/v1/proxies/{id}/test": {
      "post": {
        "operationId": "proxies_test",
        "summary": "Test a proxy's exit IP + country",
        "tags": [
          "Proxies"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "country"
                ],
                "properties": {
                  "country": {
                    "type": "string",
                    "description": "ISO-2 lowercase, e.g. \"us\""
                  },
                  "session": {
                    "type": "string",
                    "enum": [
                      "rotating",
                      "sticky"
                    ],
                    "default": "rotating"
                  },
                  "protocol": {
                    "type": "string",
                    "enum": [
                      "http",
                      "socks5"
                    ],
                    "default": "http"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Exit IP details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ip": {
                      "type": "string"
                    },
                    "country": {
                      "type": "string"
                    },
                    "city": {
                      "type": "string"
                    },
                    "region": {
                      "type": "string"
                    },
                    "org": {
                      "type": "string",
                      "example": "AS7922 Comcast Cable Communications, LLC"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/x402/sms-verify": {
      "post": {
        "operationId": "x402_sms_verify",
        "summary": "Pay-per-call SMS verification via x402 (no account needed)",
        "description": "LIVE. Call without payment to receive the HTTP 402 payment manifest (accepted\nnetworks/assets/prices); retry with a valid `X-PAYMENT` header to settle inline and\nreceive the OTP in the same response.\n\nCanonical discovery manifest (always up to date on accepted networks + status):\n`https://agents.virtualsms.io/.well-known/x402.json`\n\nAccepted payment rails at time of writing: Base USDC, Solana USDC, Solana USDT,\nBNB Chain USDC, BNB Chain USDT. Price ceiling per call: $0.05–$5 (default $0.10),\nset via the optional `max_price_usdc` field.\n\n**Note:** `/api/v1/x402/topup` and a standalone `/api/v1/x402/facilitator` endpoint\nare NOT deployed (roadmap only) — do not call them, they 404. Settlement for\nsms-verify happens inline in this handler; there is no separate facilitator call.\n",
        "tags": [
          "Agent Payments (x402)"
        ],
        "x-payment-info": {
          "price": {
            "mode": "dynamic",
            "currency": "USD",
            "min": "0.05",
            "max": "5"
          },
          "protocols": [
            {
              "x402": {}
            }
          ]
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "service",
                  "country"
                ],
                "properties": {
                  "service": {
                    "type": "string",
                    "example": "telegram"
                  },
                  "country": {
                    "type": "string",
                    "description": "2-letter country code",
                    "example": "US"
                  },
                  "max_price_usdc": {
                    "type": "number",
                    "description": "Optional server-side price ceiling, default 0.10, max 5.00",
                    "example": 0.1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment settled — verification code returned",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "phone_number": {
                      "type": "string"
                    },
                    "code": {
                      "type": "string"
                    },
                    "sms_content": {
                      "type": "string"
                    },
                    "service": {
                      "type": "string"
                    },
                    "country": {
                      "type": "string"
                    },
                    "x402_settlement": {
                      "type": "object",
                      "properties": {
                        "tx_hash": {
                          "type": "string"
                        },
                        "amount_paid_usdc": {
                          "type": "number"
                        },
                        "network": {
                          "type": "string"
                        },
                        "token": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing required parameters"
          },
          "402": {
            "description": "Payment Required"
          }
        }
      }
    }
  }
}
