{
  "openapi": "3.1.0",
  "info": {
    "title": "Telenumerus Verification API",
    "description": "SMS verification API with 33 platforms, intelligent routing, auto-retry, and real-time delivery. Self-service registration. Webhook push delivery. Automatic refunds on failure.",
    "version": "1.0.0",
    "contact": {
      "name": "Telenumerus Support",
      "email": "support@telenumerus.com"
    }
  },
  "servers": [
    {
      "url": "/api/v1",
      "description": "Telenumerus API v1"
    }
  ],
  "security": [
    { "BearerAuth": [] },
    { "ApiKeyHeader": [] }
  ],
  "tags": [
    { "name": "Auth", "description": "Registration and authentication" },
    { "name": "Orders", "description": "Phone number ordering and verification" },
    { "name": "Account", "description": "Account info, usage, and webhooks" },
    { "name": "Discovery", "description": "Platform listing, availability, and health" },
    { "name": "Deposits", "description": "Crypto deposit addresses and verification" }
  ],
  "components": {
    "securitySchemes": {
      "BearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Authorization: Bearer <api_key>"
      },
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": ["error", "error_code", "retryable"],
        "properties": {
          "service": { "type": "string", "example": "Telenumerus" },
          "error": { "type": "string" },
          "error_code": {
            "type": "string",
            "enum": ["RATE_LIMITED", "INVALID_API_KEY", "ACCOUNT_SUSPENDED", "INSUFFICIENT_BALANCE", "UNKNOWN_PLATFORM", "ORDER_IN_PROGRESS", "PROVIDER_UNAVAILABLE", "ORDER_NOT_FOUND", "INVALID_REQUEST", "INTERNAL_ERROR"]
          },
          "retryable": { "type": "boolean" },
          "retry_after_seconds": { "type": ["integer", "null"] }
        }
      },
      "OrderCreated": {
        "type": "object",
        "required": ["status", "order_id", "phone", "platform", "price"],
        "properties": {
          "service": { "type": "string" },
          "status": { "type": "string", "example": "ok" },
          "order_id": { "type": "string" },
          "phone": { "type": "string", "example": "+12025551234" },
          "platform": { "type": "string" },
          "price": { "type": "number" },
          "tier": { "type": "string" },
          "expires_in": { "type": "integer", "description": "Seconds until order expires" },
          "is_trial": { "type": "boolean" },
          "check_status": { "type": "string", "description": "URL to poll for status" },
          "stream": { "type": "string", "description": "URL for SSE real-time stream" }
        }
      },
      "OrderStatus": {
        "type": "object",
        "required": ["status", "order_id", "phone", "platform"],
        "properties": {
          "service": { "type": "string" },
          "status": { "type": "string", "enum": ["active", "completed", "failed"] },
          "order_id": { "type": "string" },
          "phone": { "type": "string" },
          "platform": { "type": "string" },
          "price": { "type": "number" },
          "code": { "type": ["string", "null"], "description": "SMS verification code (null if not yet received)" },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "VerifyResult": {
        "type": "object",
        "required": ["status", "order_id", "phone", "code", "platform", "price", "delivery_seconds"],
        "properties": {
          "service": { "type": "string" },
          "status": { "type": "string", "example": "ok" },
          "order_id": { "type": "string" },
          "phone": { "type": "string" },
          "code": { "type": "string", "description": "The extracted verification code" },
          "platform": { "type": "string" },
          "price": { "type": "number" },
          "delivery_seconds": { "type": "integer" }
        }
      },
      "AgentResponse": {
        "type": "object",
        "required": ["understood"],
        "properties": {
          "service": { "type": "string" },
          "understood": { "type": "boolean", "description": "Whether the query was parsed into a valid order" },
          "parsed": {
            "type": "object",
            "properties": {
              "platform": { "type": "string" },
              "country": { "type": "string" }
            }
          },
          "order_id": { "type": "string" },
          "phone": { "type": "string" },
          "price": { "type": "number" },
          "next_step": { "type": "string" },
          "check_status": { "type": "string" },
          "message": { "type": "string", "description": "Explanation when understood=false" },
          "available_platforms": {
            "type": "array",
            "items": { "type": "string" }
          },
          "example_queries": {
            "type": "array",
            "items": { "type": "string" }
          }
        }
      }
    }
  },
  "paths": {
    "/register": {
      "post": {
        "operationId": "registerAccount",
        "tags": ["Auth"],
        "summary": "Create a new API account (self-service, no human needed)",
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "webhook_url": { "type": "string", "description": "Optional webhook URL for push notifications" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Account created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["api_key", "webhook_secret"],
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string" },
                    "api_key": { "type": "string", "description": "Save this -- cannot be recovered" },
                    "webhook_secret": { "type": "string" },
                    "message": { "type": "string" },
                    "next_steps": {
                      "type": "object",
                      "properties": {
                        "deposit": { "type": "string" },
                        "browse_services": { "type": "string" },
                        "place_order": { "type": "string" },
                        "set_webhook": { "type": "string" },
                        "check_account": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          },
          "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/services": {
      "get": {
        "operationId": "listServices",
        "tags": ["Discovery"],
        "summary": "List all platforms and live prices",
        "security": [],
        "parameters": [
          { "name": "country", "in": "query", "schema": { "type": "string", "default": "US" } }
        ],
        "responses": {
          "200": {
            "description": "Platform list with prices",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["services", "total_platforms"],
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string" },
                    "country": { "type": "string" },
                    "currency": { "type": "string" },
                    "services": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": ["platform", "price", "available"],
                        "properties": {
                          "platform": { "type": "string" },
                          "price": { "type": "number" },
                          "available": { "type": "boolean" },
                          "avg_delivery_seconds": { "type": ["integer", "null"] }
                        }
                      }
                    },
                    "total_platforms": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/availability": {
      "get": {
        "operationId": "getAvailability",
        "tags": ["Discovery"],
        "summary": "Platform success rates, stock levels, and delivery times",
        "description": "Returns real success rates from the last 24 hours, average delivery time, and stock level per platform. Use this to pick the best platform before ordering.",
        "security": [],
        "parameters": [
          { "name": "country", "in": "query", "schema": { "type": "string", "default": "US" } }
        ],
        "responses": {
          "200": {
            "description": "Platform availability data",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["platforms"],
                  "properties": {
                    "service": { "type": "string" },
                    "country": { "type": "string" },
                    "total": { "type": "integer" },
                    "platforms": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": ["platform", "price", "stock"],
                        "properties": {
                          "platform": { "type": "string" },
                          "price": { "type": "number" },
                          "success_rate": { "type": ["number", "null"] },
                          "avg_delivery_seconds": { "type": ["integer", "null"] },
                          "stock": { "type": "string", "enum": ["high", "medium", "low", "unknown"] },
                          "hints": {
                            "type": "object",
                            "properties": {
                              "expect_code_length": { "type": "integer" },
                              "code_format": { "type": "string" },
                              "typical_delivery_seconds": { "type": "integer" }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/order": {
      "post": {
        "operationId": "createOrder",
        "tags": ["Orders"],
        "summary": "Request a phone number for SMS verification",
        "description": "Returns a phone number immediately. Poll GET /order/{id}, use SSE /order/{id}/stream, or set up webhooks for the code.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["platform"],
                "properties": {
                  "platform": { "type": "string", "description": "Platform name (google, whatsapp, etc.)" },
                  "country": { "type": "string", "default": "US" },
                  "idempotency_key": { "type": "string", "description": "Unique key (1-128 chars) for safe retries. Same key returns cached result." }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Order created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderCreated" } } } },
          "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "402": { "description": "Insufficient balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Account suspended", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limited or order in progress", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "503": { "description": "Provider unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/verify": {
      "post": {
        "operationId": "verifyOneShot",
        "tags": ["Orders"],
        "summary": "One-shot: order + wait + return SMS code in a single call",
        "description": "Long-polls the provider until the SMS code arrives or timeout. Returns the extracted code directly. Auto-refunds on timeout. Best for AI agents that want the code in one call. Max 2 concurrent per account.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["platform"],
                "properties": {
                  "platform": { "type": "string" },
                  "country": { "type": "string", "default": "US" },
                  "timeout_seconds": { "type": "integer", "minimum": 30, "maximum": 300, "default": 120 },
                  "idempotency_key": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Verification completed with code", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/VerifyResult" } } } },
          "400": { "description": "Invalid request", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "402": { "description": "Insufficient balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "403": { "description": "Account suspended", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Rate limited", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "503": { "description": "Provider unavailable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "504": { "description": "Timeout -- auto-refunded", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/order/{orderId}": {
      "get": {
        "operationId": "getOrderStatus",
        "tags": ["Orders"],
        "summary": "Check order status and get SMS code",
        "parameters": [
          { "name": "orderId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Order status", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrderStatus" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "404": { "description": "Order not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/order/{orderId}/cancel": {
      "post": {
        "operationId": "cancelOrder",
        "tags": ["Orders"],
        "summary": "Cancel active order and get refund",
        "parameters": [
          { "name": "orderId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Order cancelled and refunded",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status", "order_id", "refunded"],
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string", "example": "ok" },
                    "order_id": { "type": "string" },
                    "refunded": { "type": "number" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Order not cancellable", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "404": { "description": "Order not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/order/{orderId}/stream": {
      "get": {
        "operationId": "streamOrderStatus",
        "tags": ["Orders"],
        "summary": "Real-time SSE stream -- code pushed the instant it arrives",
        "description": "Opens a Server-Sent Events connection. Sends 'waiting' heartbeats every 2 seconds and a 'code' event when the SMS arrives. Zero polling overhead. Max 5 minutes.",
        "parameters": [
          { "name": "orderId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "SSE event stream",
            "content": {
              "text/event-stream": {
                "schema": { "type": "string", "description": "Events: waiting (heartbeat), code (SMS arrived), failed (order failed), timeout (expired)" }
              }
            }
          },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "404": { "description": "Order not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/agent": {
      "post": {
        "operationId": "naturalLanguageOrder",
        "tags": ["Orders"],
        "summary": "Natural language ordering for AI agents",
        "description": "Describe what you need in plain English. The API parses platform and country from your query and places the order.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["query"],
                "properties": {
                  "query": { "type": "string", "example": "I need a Google verification number for UK" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Order created or platform not recognized", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentResponse" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "402": { "description": "Insufficient balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/batch": {
      "post": {
        "operationId": "batchOrder",
        "tags": ["Orders"],
        "summary": "Order up to 20 numbers in one request",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["orders"],
                "properties": {
                  "orders": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "object",
                      "required": ["platform"],
                      "properties": {
                        "platform": { "type": "string" },
                        "country": { "type": "string", "default": "US" }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["batch_size", "succeeded", "failed", "orders"],
                  "properties": {
                    "service": { "type": "string" },
                    "batch_size": { "type": "integer" },
                    "succeeded": { "type": "integer" },
                    "failed": { "type": "integer" },
                    "orders": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "platform": { "type": "string" },
                          "order_id": { "type": "string" },
                          "phone": { "type": "string" },
                          "price": { "type": "number" },
                          "status": { "type": "string" },
                          "error": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "402": { "description": "Insufficient balance", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/account": {
      "get": {
        "operationId": "getAccount",
        "tags": ["Account"],
        "summary": "Account info -- balance, tier, stats, recent orders",
        "responses": {
          "200": {
            "description": "Account info",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["balance", "tier", "total_orders"],
                  "properties": {
                    "service": { "type": "string" },
                    "balance": { "type": "number" },
                    "total_spent": { "type": "number" },
                    "total_orders": { "type": "integer" },
                    "successful_orders": { "type": "integer" },
                    "tier": { "type": "string", "enum": ["Standard", "Silver", "Gold", "VIP"] },
                    "discount": { "type": "string" },
                    "next_tier": { "type": ["string", "null"] },
                    "orders_to_next_tier": { "type": ["integer", "null"] },
                    "webhook_active": { "type": "boolean" },
                    "member_since": { "type": "string" },
                    "recent_orders": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "order_id": { "type": "string" },
                          "platform": { "type": "string" },
                          "status": { "type": "string" },
                          "price": { "type": "number" },
                          "created_at": { "type": "string" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/usage": {
      "get": {
        "operationId": "getUsage",
        "tags": ["Account"],
        "summary": "Usage analytics -- per-platform breakdown + daily spending",
        "responses": {
          "200": {
            "description": "Usage stats",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["by_platform", "daily"],
                  "properties": {
                    "service": { "type": "string" },
                    "by_platform": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "platform": { "type": "string" },
                          "total_orders": { "type": "integer" },
                          "completed": { "type": "integer" },
                          "failed": { "type": "integer" },
                          "total_spent": { "type": "number" },
                          "first_order": { "type": "string" },
                          "last_order": { "type": "string" }
                        }
                      }
                    },
                    "daily": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "date": { "type": "string" },
                          "orders": { "type": "integer" },
                          "completed": { "type": "integer" },
                          "spent": { "type": "number" }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/webhook": {
      "put": {
        "operationId": "setWebhook",
        "tags": ["Account"],
        "summary": "Set webhook URL for push notifications",
        "description": "Receive sms.received, order.failed, and balance.low events via HTTP POST. Generates a new HMAC signing secret each time the URL changes.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": { "type": ["string", "null"], "description": "Webhook URL. Set null to disable." }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Webhook configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status"],
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string" },
                    "webhook_url": { "type": ["string", "null"] },
                    "webhook_secret": { "type": "string", "description": "Only returned when URL changes" },
                    "events": { "type": "array", "items": { "type": "string" } },
                    "note": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid URL", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/deposit/addresses": {
      "get": {
        "operationId": "getDepositAddresses",
        "tags": ["Deposits"],
        "summary": "Get crypto deposit addresses for adding funds",
        "security": [],
        "responses": {
          "200": {
            "description": "Deposit addresses",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "service": { "type": "string" },
                    "addresses": {
                      "type": "object",
                      "properties": {
                        "btc": { "type": "string" },
                        "ltc": { "type": "string" },
                        "usdt_erc20": { "type": "string" }
                      }
                    },
                    "minimum_deposit_usd": { "type": "number" },
                    "instructions": { "type": "string" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/deposit/verify": {
      "post": {
        "operationId": "verifyDeposit",
        "tags": ["Deposits"],
        "summary": "Submit a TX hash for on-chain deposit verification",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["tx_hash"],
                "properties": {
                  "tx_hash": { "type": "string", "description": "64-character hex transaction hash" },
                  "amount": { "type": "number", "description": "Optional claimed amount in USD" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Deposit submitted for verification",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string" },
                    "transaction_id": { "type": "string" },
                    "amount": { "type": "number" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "description": "Invalid TX hash or amount", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "401": { "description": "Invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "description": "Too many pending deposits", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "tags": ["Discovery"],
        "summary": "Service health check",
        "security": [],
        "responses": {
          "200": {
            "description": "Service status",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": ["status", "platforms"],
                  "properties": {
                    "service": { "type": "string" },
                    "status": { "type": "string", "enum": ["operational"] },
                    "platforms": { "type": "integer" },
                    "uptime_seconds": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
