{
  "openapi": "3.0.3",
  "info": {
    "title": "Store API",
    "version": "1.0.0",
    "description": "Buy products programmatically from your wallet balance.\n\nGet your personal API key from the Telegram bot (Profile → 🔑 API Access), top up your wallet, then call these endpoints. Authenticate every request with the `X-API-Key` header.\n\n**Rate limit:** 20 requests/minute per key. Responses include `X-RateLimit-Remaining` and `X-RateLimit-Reset` headers."
  },
  "servers": [
    { "url": "https://YOUR_API_DOMAIN/api/v1", "description": "Production (override via config.js)" }
  ],
  "security": [{ "ApiKeyAuth": [] }],
  "tags": [
    { "name": "Wallet", "description": "Balance and account" },
    { "name": "Catalog", "description": "Products and stock" },
    { "name": "Purchases", "description": "Buying with wallet balance" }
  ],
  "paths": {
    "/balance": {
      "get": {
        "tags": ["Wallet"],
        "summary": "Get wallet balance",
        "description": "Returns the current wallet balance for the authenticated key's owner.",
        "operationId": "getBalance",
        "responses": {
          "200": {
            "description": "Current balance",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Balance" },
                "example": { "balance": 24.5, "currency": "USDT" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/products": {
      "get": {
        "tags": ["Catalog"],
        "summary": "List products",
        "description": "Lists all available products with real-time stock.",
        "operationId": "listProducts",
        "responses": {
          "200": {
            "description": "Product list",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/ProductList" },
                "example": {
                  "products": [
                    { "id": "abc123", "name": "Gemini Pro 18 month", "price": 3.0, "stock": 53, "in_stock": true, "currency": "USDT" }
                  ],
                  "total": 1,
                  "timestamp": "2026-01-01T00:00:00.000Z"
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/purchase": {
      "post": {
        "tags": ["Purchases"],
        "summary": "Purchase a product",
        "description": "Buys a product using wallet balance and returns the delivered codes.\n\nSend an optional `Idempotency-Key` header to safely retry without double-charging: an identical retry within 24h returns the original result instead of buying again.",
        "operationId": "purchase",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": { "type": "string", "maxLength": 128 },
            "description": "Unique id for this purchase. Retrying with the same value returns the original result."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/PurchaseRequest" },
              "example": { "product_id": "abc123", "quantity": 1 }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase succeeded",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/PurchaseResult" },
                "example": {
                  "success": true,
                  "order_id": "ORD-A-1A2B3C4D",
                  "product": "Gemini Pro 18 month",
                  "quantity": 1,
                  "total_charged": 3.0,
                  "currency": "USDT",
                  "balance_remaining": 21.5,
                  "codes": ["XXXX-XXXX-XXXX"],
                  "purchased_at": "2026-01-01T00:00:00.000Z"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/ValidationError" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": {
            "description": "Insufficient wallet balance",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "Insufficient balance", "code": "INSUFFICIENT_BALANCE", "required": 3.0, "available": 1.5 }
              }
            }
          },
          "403": {
            "description": "Account suspended",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "Account suspended", "code": "FORBIDDEN" }
              }
            }
          },
          "404": {
            "description": "Product not found",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "Product not found", "code": "PRODUCT_NOT_FOUND" }
              }
            }
          },
          "409": {
            "description": "Not enough stock",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Error" },
                "example": { "error": "Not enough stock", "code": "OUT_OF_STOCK", "requested": 2, "available": 1 }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Your personal key in the form mk_xxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. Get it from the Telegram bot: Profile → 🔑 API Access."
      }
    },
    "schemas": {
      "Balance": {
        "type": "object",
        "properties": {
          "balance": { "type": "number", "example": 24.5 },
          "currency": { "type": "string", "example": "USDT" }
        }
      },
      "Product": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "price": { "type": "number" },
          "stock": { "type": "integer" },
          "in_stock": { "type": "boolean" },
          "currency": { "type": "string" }
        }
      },
      "ProductList": {
        "type": "object",
        "properties": {
          "products": { "type": "array", "items": { "$ref": "#/components/schemas/Product" } },
          "total": { "type": "integer" },
          "timestamp": { "type": "string", "format": "date-time" }
        }
      },
      "PurchaseRequest": {
        "type": "object",
        "required": ["product_id", "quantity"],
        "properties": {
          "product_id": { "type": "string", "description": "Product id from GET /products" },
          "quantity": { "type": "integer", "minimum": 1, "maximum": 10, "default": 1 }
        }
      },
      "PurchaseResult": {
        "type": "object",
        "properties": {
          "success": { "type": "boolean" },
          "order_id": { "type": "string" },
          "product": { "type": "string" },
          "quantity": { "type": "integer" },
          "total_charged": { "type": "number" },
          "currency": { "type": "string" },
          "balance_remaining": { "type": "number" },
          "codes": { "type": "array", "items": { "type": "string" } },
          "purchased_at": { "type": "string", "format": "date-time" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "code": { "type": "string" }
        }
      }
    },
    "responses": {
      "Unauthorized": {
        "description": "Missing, malformed, or revoked API key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": "Invalid or revoked API key", "code": "INVALID_KEY" }
          }
        }
      },
      "RateLimited": {
        "description": "Too many requests (20/min)",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": "Rate limit exceeded", "code": "RATE_LIMITED", "retry_after_seconds": 42 }
          }
        }
      },
      "ValidationError": {
        "description": "Invalid request body",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/Error" },
            "example": { "error": "quantity must be 1-10", "code": "VALIDATION" }
          }
        }
      }
    }
  }
}
