{
  "openapi": "3.0.3",
  "info": {
    "title": "TaoFlow VPN Service API",
    "description": "Privacy-focused WireGuard VPN service with cryptocurrency payments. No account required — create an order, pay with crypto, and receive your WireGuard config.\n\n## Purchase Flow\n\n1. **Browse plans** — `GET /plans` to see available VPN plans (duration, price)\n2. **Browse countries** — `GET /countries` to see available server locations\n3. **Browse payment methods** — `GET /payment-methods` to see accepted cryptocurrencies\n4. **Create order** — `POST /orders` with your chosen plan, country, and payment currency. You receive a `pay_address`, `pay_amount`, and an `access_token` (save this!)\n5. **Send payment** — Transfer the exact `pay_amount` of your chosen crypto to `pay_address`\n6. **Poll status** — `GET /orders/{id}` (with Bearer access_token) until `status` becomes `paid` and `provisioning` is `false`\n7. **Download config** — `GET /orders/{id}/config` to retrieve your WireGuard configuration file\n8. **Connect** — Import the WireGuard config into any WireGuard client and connect\n\n## Authentication\n\nOrder endpoints use Bearer token authentication. The `access_token` is returned when you create an order. Include it as `Authorization: Bearer <access_token>` on subsequent requests for that order.\n\nIf you lose your access token, use `POST /orders/recover` with your `recovery_key` to get a new one.",
    "version": "1.0.0"
  },
  "servers": [
    {
      "url": "/",
      "description": "This server"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "healthCheck",
        "summary": "Health check",
        "description": "Returns \"OK\" if the service is running.",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "Service is healthy",
            "content": {
              "text/plain": {
                "schema": { "type": "string", "example": "OK" }
              }
            }
          }
        }
      }
    },
    "/plans": {
      "get": {
        "operationId": "listPlans",
        "summary": "List available VPN plans",
        "description": "Returns all active VPN plans with pricing and duration.",
        "tags": ["Catalog"],
        "responses": {
          "200": {
            "description": "List of plans",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Plan" }
                },
                "example": [
                  { "id": "monthly-basic", "name": "Monthly Basic", "duration_days": 30, "price_usdt": 5.0 }
                ]
              }
            }
          }
        }
      }
    },
    "/countries": {
      "get": {
        "operationId": "listCountries",
        "summary": "List available server countries",
        "description": "Returns country identifiers where VPN servers are available. Use these values as-is in the country_code field when creating orders.",
        "tags": ["Catalog"],
        "responses": {
          "200": {
            "description": "List of country codes",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CountriesResponse" },
                "example": { "countries": ["US", "DE", "JP", "SG", "NL"] }
              }
            }
          }
        }
      }
    },
    "/payment-methods": {
      "get": {
        "operationId": "listPaymentMethods",
        "summary": "List accepted payment methods",
        "description": "Returns accepted cryptocurrency payment methods. Optionally filter by a specific currency to also retrieve its minimum USD amount.",
        "tags": ["Catalog"],
        "parameters": [
          {
            "name": "pay_currency",
            "in": "query",
            "required": false,
            "description": "Filter to a specific currency (e.g. \"xmr\", \"btc\", \"usdttrc20\"). When provided, the response includes `min_amount_usd`.",
            "schema": { "type": "string" }
          }
        ],
        "responses": {
          "200": {
            "description": "List of payment methods",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/PaymentMethod" }
                },
                "example": [
                  { "pay_currency": "xmr", "min_amount_usd": 0.5 },
                  { "pay_currency": "btc", "min_amount_usd": 1.0 }
                ]
              }
            }
          }
        }
      }
    },
    "/orders": {
      "post": {
        "operationId": "createOrder",
        "summary": "Create a new VPN order",
        "description": "Creates an order for a VPN plan in the selected country. Returns payment details (address and amount) and authentication credentials (access_token and recovery_key).\n\n**Important:** Save both `access_token` and `recovery_key`. The access_token is needed to check status and download your config. The recovery_key can restore access if you lose the token.",
        "tags": ["Orders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateOrderRequest" },
              "example": {
                "plan_id": "monthly-basic",
                "country_code": "US",
                "pay_currency": "xmr"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Order created successfully",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateOrderResponse" }
              }
            }
          },
          "400": {
            "description": "Invalid plan_id, country_code, or pay_currency"
          }
        }
      }
    },
    "/orders/recover": {
      "post": {
        "operationId": "recoverOrderAccess",
        "summary": "Recover order access with recovery key",
        "description": "If you lost your access_token, provide your recovery_key to get a new access_token for the order.",
        "tags": ["Orders"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/RecoverOrderRequest" },
              "example": { "recovery_key": "your-recovery-key-here" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Access recovered — new access_token issued",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RecoverOrderResponse" }
              }
            }
          },
          "404": { "description": "Order not found for the given recovery key" }
        }
      }
    },
    "/orders/{id}": {
      "get": {
        "operationId": "getOrderStatus",
        "summary": "Get order status",
        "description": "Check the current status of an order. Poll this endpoint after sending payment to track progress.\n\n**Status flow:** `pending` → `paid` → `expired`\n\n- `pending` — waiting for crypto payment\n- `paid` — payment confirmed. If `provisioning` is `true`, the VPN is still being set up. Once `provisioning` is `false`, the config is ready via `/orders/{id}/config`\n- `expired` — VPN subscription has ended",
        "tags": ["Orders"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Order UUID",
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "Order status",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrderStatusResponse" }
              }
            }
          },
          "401": { "description": "Missing or invalid access token" },
          "404": { "description": "Order not found" }
        }
      }
    },
    "/orders/{id}/config": {
      "get": {
        "operationId": "getOrderConfig",
        "summary": "Download WireGuard configuration",
        "description": "Retrieve the WireGuard configuration file for an active order. Only available when order status is `active`.\n\nThe `wg_config` field contains a complete WireGuard config file that can be saved as a `.conf` file and imported into any WireGuard client.",
        "tags": ["Orders"],
        "security": [{ "bearerAuth": [] }],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Order UUID",
            "schema": { "type": "string", "format": "uuid" }
          }
        ],
        "responses": {
          "200": {
            "description": "WireGuard config",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/WireguardConfigResponse" }
              }
            }
          },
          "401": { "description": "Missing or invalid access token" },
          "404": { "description": "Order not found or config not yet available" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "The `access_token` returned by `POST /orders`. Use as: `Authorization: Bearer <access_token>`"
      }
    },
    "schemas": {
      "Plan": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "Plan identifier, used in create order", "example": "monthly-basic" },
          "name": { "type": "string", "description": "Human-readable plan name", "example": "Monthly Basic" },
          "duration_days": { "type": "integer", "description": "VPN access duration in days", "example": 30 },
          "price_usdt": { "type": "number", "description": "Price in USD", "example": 5.0 }
        },
        "required": ["id", "name", "duration_days", "price_usdt"]
      },
      "CountriesResponse": {
        "type": "object",
        "properties": {
          "countries": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Country identifiers (e.g. \"US\", \"DE\", \"JP\"). Use these values as-is in country_code when creating orders."
          }
        },
        "required": ["countries"]
      },
      "PaymentMethod": {
        "type": "object",
        "properties": {
          "pay_currency": { "type": "string", "description": "Currency identifier (e.g. \"xmr\", \"btc\", \"usdttrc20\")", "example": "xmr" },
          "min_amount_usd": { "type": "number", "nullable": true, "description": "Minimum order amount in USD for this currency (only returned when filtering by pay_currency)", "example": 0.5 }
        },
        "required": ["pay_currency"]
      },
      "CreateOrderRequest": {
        "type": "object",
        "properties": {
          "plan_id": { "type": "string", "description": "Plan ID from GET /plans", "example": "monthly-basic" },
          "country_code": { "type": "string", "description": "Country identifier from GET /countries (use exact value returned)", "example": "US" },
          "pay_currency": { "type": "string", "description": "Payment currency from GET /payment-methods. Defaults to the server's preferred currency if omitted.", "example": "xmr" }
        },
        "required": ["plan_id", "country_code"]
      },
      "CreateOrderResponse": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "format": "uuid", "description": "Unique order identifier" },
          "access_token": { "type": "string", "description": "Bearer token for accessing this order's status and config. Save this!" },
          "recovery_key": { "type": "string", "description": "Backup key to recover access_token if lost. Save this separately!" },
          "plan_id": { "type": "string" },
          "country_code": { "type": "string" },
          "price_usdt": { "type": "number", "description": "Order price in USD" },
          "price_usd": { "type": "number", "description": "Order price in USD" },
          "pay_amount": { "type": "number", "description": "Exact amount to send in pay_currency" },
          "pay_address": { "type": "string", "description": "Crypto address to send payment to" },
          "pay_currency": { "type": "string", "description": "Currency to pay in" },
          "status": { "type": "string", "enum": ["pending"], "description": "Initial order status" }
        },
        "required": ["order_id", "access_token", "recovery_key", "plan_id", "country_code", "price_usdt", "pay_amount", "pay_address", "pay_currency", "status"]
      },
      "RecoverOrderRequest": {
        "type": "object",
        "properties": {
          "recovery_key": { "type": "string", "description": "The recovery key received when the order was created" }
        },
        "required": ["recovery_key"]
      },
      "RecoverOrderResponse": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "format": "uuid" },
          "access_token": { "type": "string", "description": "New Bearer token for this order" },
          "status": { "type": "string" },
          "plan_id": { "type": "string" },
          "country_code": { "type": "string" }
        },
        "required": ["order_id", "access_token", "status", "plan_id", "country_code"]
      },
      "OrderStatusResponse": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "format": "uuid" },
          "plan_id": { "type": "string" },
          "country_code": { "type": "string" },
          "price_usdt": { "type": "number" },
          "price_usd": { "type": "number" },
          "pay_amount": { "type": "number" },
          "pay_currency": { "type": "string" },
          "pay_address": { "type": "string", "nullable": true, "description": "Payment address (only shown while status is pending)" },
          "status": { "type": "string", "enum": ["pending", "paid", "expired"], "description": "Current order status" },
          "payment_raw_status": { "type": "string", "nullable": true, "description": "Raw status from payment provider" },
          "payment_event_status": { "type": "string", "nullable": true, "description": "Processed payment event status" },
          "payment_updated_at": { "type": "string", "nullable": true, "description": "Last payment update timestamp" },
          "provisioning": { "type": "boolean", "description": "True if VPN is currently being provisioned (status=paid, not yet active)" },
          "provisioning_message": { "type": "string", "nullable": true, "description": "Human-readable provisioning progress message" }
        },
        "required": ["order_id", "plan_id", "country_code", "price_usdt", "pay_amount", "pay_currency", "status", "provisioning"]
      },
      "WireguardConfigResponse": {
        "type": "object",
        "properties": {
          "order_id": { "type": "string", "format": "uuid" },
          "status": { "type": "string" },
          "wg_config": { "type": "string", "description": "Complete WireGuard configuration file contents. Save as a .conf file and import into any WireGuard client." }
        },
        "required": ["order_id", "status", "wg_config"]
      }
    }
  }
}
