{
  "openapi": "3.1.0",
  "info": {
    "title": "TGLift Reseller API",
    "version": "1.0.0",
    "description": "Public API for TGLift accounts. Every order, service, balance and status in this contract belongs to TGLift."
  },
  "servers": [
    {
      "url": "https://tglift.ru",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "paths": {
    "/api/v1/services": {
      "get": {
        "operationId": "listServices",
        "summary": "List available TGLift services",
        "parameters": [
          { "$ref": "#/components/parameters/Locale" },
          { "$ref": "#/components/parameters/Currency" }
        ],
        "responses": {
          "200": {
            "description": "Available services",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Service" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api/v1/balance": {
      "get": {
        "operationId": "getBalance",
        "summary": "Get account balance",
        "parameters": [
          { "$ref": "#/components/parameters/Currency" }
        ],
        "responses": {
          "200": {
            "description": "Current account balances",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Balance" },
                "example": {
                  "balance": "1250.50",
                  "currency": "RUB",
                  "balances": { "RUB": "1250.50", "USD": "0.00" }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/orders": {
      "get": {
        "operationId": "listOrders",
        "summary": "List account orders",
        "parameters": [
          { "$ref": "#/components/parameters/Limit" },
          { "$ref": "#/components/parameters/Offset" }
        ],
        "responses": {
          "200": {
            "description": "Paginated orders, newest first",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrderList" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "post": {
        "operationId": "createOrder",
        "summary": "Create a TGLift order",
        "parameters": [
          { "$ref": "#/components/parameters/IdempotencyKey" }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateOrder" },
              "example": {
                "service": "631",
                "link": "https://t.me/example_channel/10",
                "quantity": 1000,
                "locale": "ru",
                "currency": "RUB"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": { "$ref": "#/components/schemas/CreateOrderForm" }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Order accepted. A repeated request with the same idempotency key returns the same order.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/CreateOrderResult" },
                "example": {
                  "order": "RQ-MRX1ABC2-12AB34",
                  "status": "pending",
                  "idempotentReplay": false
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/InsufficientBalance" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/api/v1/orders/{order}": {
      "get": {
        "operationId": "getOrder",
        "summary": "Get one TGLift order",
        "parameters": [
          { "$ref": "#/components/parameters/OrderId" }
        ],
        "responses": {
          "200": {
            "description": "Order status",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Order" }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/orders/{order}/cancel": {
      "post": {
        "operationId": "cancelOrder",
        "summary": "Request cancellation",
        "parameters": [
          { "$ref": "#/components/parameters/OrderId" }
        ],
        "responses": {
          "200": {
            "description": "Cancellation request accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrderActionResult" },
                "example": {
                  "request": "2026-07-22T12:00:00.000Z",
                  "status": "cancel_requested"
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/api/v1/orders/{order}/refill": {
      "post": {
        "operationId": "refillOrder",
        "summary": "Request a refill",
        "parameters": [
          { "$ref": "#/components/parameters/OrderId" }
        ],
        "responses": {
          "200": {
            "description": "Refill request accepted",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/OrderActionResult" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "409": { "$ref": "#/components/responses/Conflict" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "TGLift account API key. Never send it in a URL or browser code."
      }
    },
    "parameters": {
      "Locale": {
        "name": "locale",
        "in": "query",
        "required": false,
        "schema": { "type": "string", "enum": ["ru", "en"] },
        "description": "Service text language. Account preference is used when omitted."
      },
      "Currency": {
        "name": "currency",
        "in": "query",
        "required": false,
        "schema": { "type": "string", "enum": ["RUB", "USD"] },
        "description": "Public price and balance currency. Account preference is used when omitted."
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 100 }
      },
      "Offset": {
        "name": "offset",
        "in": "query",
        "required": false,
        "schema": { "type": "integer", "minimum": 0, "default": 0 }
      },
      "IdempotencyKey": {
        "name": "Idempotency-Key",
        "in": "header",
        "required": true,
        "schema": {
          "type": "string",
          "minLength": 8,
          "maxLength": 128,
          "pattern": "^[A-Za-z0-9._:-]+$"
        },
        "description": "Unique per logical order. Reuse the same value only when retrying that exact order."
      },
      "OrderId": {
        "name": "order",
        "in": "path",
        "required": true,
        "schema": { "type": "string", "pattern": "^RQ-" },
        "description": "TGLift order ID returned by createOrder."
      }
    },
    "schemas": {
      "Service": {
        "type": "object",
        "required": ["service", "name", "type", "category", "rate", "ratePer", "pricingUnit", "currency", "min", "max", "refill", "cancel", "orderRequirements"],
        "properties": {
          "service": { "type": "string", "description": "TGLift service ID" },
          "name": { "type": "string" },
          "type": { "type": "string" },
          "category": { "type": "string" },
          "rate": { "type": "string", "description": "Public account price in currency" },
          "ratePer": { "type": "integer", "enum": [1, 1000] },
          "pricingUnit": { "type": "string", "enum": ["package", "1000_units"] },
          "currency": { "type": "string", "enum": ["RUB", "USD"] },
          "emoji": { "type": "string" },
          "reactionEmoji": { "type": "string" },
          "min": { "type": "integer" },
          "max": { "type": "integer" },
          "refill": { "type": "boolean" },
          "cancel": { "type": "boolean" },
          "description": { "type": "string" },
          "tags": { "type": "array", "items": { "type": "string" } },
          "highlights": { "type": "array", "items": { "type": "string" } },
          "orderRequirements": { "$ref": "#/components/schemas/OrderRequirements" }
        }
      },
      "OrderRequirements": {
        "type": "object",
        "required": ["type", "requiresLink", "requiresQuantity", "fields"],
        "properties": {
          "type": { "$ref": "#/components/schemas/ServiceOrderType" },
          "requiresLink": { "type": "boolean" },
          "requiresQuantity": { "type": "boolean" },
          "quantityFrom": { "type": ["string", "null"] },
          "fields": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/OrderField" }
          }
        }
      },
      "ServiceOrderType": {
        "type": "string",
        "enum": ["default", "package", "custom_comments", "custom_comments_package", "custom_replies", "seo", "poll", "invites_from_groups", "comment_likes", "comment_replies", "mentions_user_followers", "mentions_hashtag", "mentions_with_hashtags", "mentions_custom_list", "mentions", "mentions_media_likers", "subscriptions"]
      },
      "OrderField": {
        "type": "object",
        "required": ["name", "type", "required", "description"],
        "properties": {
          "name": { "type": "string" },
          "type": { "type": "string", "enum": ["string", "integer"] },
          "required": { "type": "boolean" },
          "description": { "type": "string" },
          "format": { "type": "string" },
          "minimum": { "type": "number" },
          "maximum": { "type": "number" }
        }
      },
      "CreateOrder": {
        "type": "object",
        "required": ["service"],
        "properties": {
          "service": { "type": "string", "description": "TGLift service ID" },
          "link": { "type": "string", "format": "uri" },
          "quantity": { "type": "integer", "minimum": 1 },
          "locale": { "type": "string", "enum": ["ru", "en"] },
          "currency": { "type": "string", "enum": ["RUB", "USD"] },
          "fields": { "$ref": "#/components/schemas/SpecialFields" }
        },
        "description": "Read orderRequirements for the selected service before building the request."
      },
      "CreateOrderForm": {
        "allOf": [
          { "$ref": "#/components/schemas/CreateOrder" },
          { "$ref": "#/components/schemas/SpecialFields" }
        ],
        "description": "For form encoding, special fields are sent at the top level."
      },
      "SpecialFields": {
        "type": "object",
        "properties": {
          "comments": { "type": "string", "description": "One comment or reply per line" },
          "keywords": { "type": "string", "description": "One keyword per line" },
          "pollAnswer": { "type": "integer", "minimum": 1, "description": "One-based answer number" },
          "groups": { "type": "string", "description": "One source group per line" },
          "username": { "type": "string" },
          "usernames": { "type": "string", "description": "One username per line" },
          "hashtag": { "type": "string" },
          "hashtags": { "type": "string", "description": "One hashtag per line" },
          "mediaUrl": { "type": "string", "format": "uri" },
          "min": { "type": "integer", "minimum": 1 },
          "max": { "type": "integer", "minimum": 1 },
          "posts": { "type": "integer", "minimum": 0 },
          "oldPosts": { "type": "integer", "minimum": 0 },
          "delay": { "type": "integer", "minimum": 0, "description": "Minutes between subscription runs" },
          "expiry": { "type": "string", "pattern": "^\\d{2}/\\d{2}/\\d{4}$", "description": "Optional dd/mm/yyyy date" }
        }
      },
      "CreateOrderResult": {
        "type": "object",
        "required": ["order", "status", "idempotentReplay"],
        "properties": {
          "order": { "type": "string", "description": "TGLift order ID" },
          "status": { "$ref": "#/components/schemas/OrderStatus" },
          "idempotentReplay": { "type": "boolean" }
        }
      },
      "OrderStatus": {
        "type": "string",
        "enum": ["pending", "in_progress", "completed", "partial", "canceled", "failed", "cancel_requested", "payment_required", "under_review"]
      },
      "Order": {
        "type": "object",
        "required": ["order", "service", "status", "charge", "currency", "quantity", "refundedAmount", "createdAt", "updatedAt"],
        "properties": {
          "order": { "type": "string", "description": "TGLift order ID" },
          "service": { "type": "string", "description": "TGLift service ID" },
          "status": { "$ref": "#/components/schemas/OrderStatus" },
          "statusMessage": { "type": "string" },
          "charge": { "type": "string" },
          "currency": { "type": "string", "enum": ["RUB", "USD"] },
          "link": { "type": "string" },
          "quantity": { "type": "integer" },
          "remains": { "type": ["integer", "null"] },
          "startCount": { "type": ["integer", "null"] },
          "refundedAmount": { "type": "string" },
          "cancelRequestedAt": { "type": ["string", "null"], "format": "date-time" },
          "refillRequestedAt": { "type": ["string", "null"], "format": "date-time" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "OrderList": {
        "type": "object",
        "required": ["orders", "total", "limit", "offset", "hasMore"],
        "properties": {
          "orders": { "type": "array", "items": { "$ref": "#/components/schemas/Order" } },
          "total": { "type": "integer" },
          "limit": { "type": "integer" },
          "offset": { "type": "integer" },
          "hasMore": { "type": "boolean" }
        }
      },
      "Balance": {
        "type": "object",
        "required": ["balance", "currency", "balances"],
        "properties": {
          "balance": { "type": "string" },
          "currency": { "type": "string", "enum": ["RUB", "USD"] },
          "balances": {
            "type": "object",
            "required": ["RUB", "USD"],
            "properties": {
              "RUB": { "type": "string" },
              "USD": { "type": "string" }
            }
          }
        }
      },
      "OrderActionResult": {
        "type": "object",
        "required": ["status"],
        "properties": {
          "request": { "type": ["string", "null"], "format": "date-time" },
          "status": { "$ref": "#/components/schemas/OrderStatus" },
          "refunded": { "type": "string" }
        }
      },
      "ApiError": {
        "type": "object",
        "required": ["ok", "error", "code", "requestId"],
        "properties": {
          "ok": { "type": "boolean", "const": false },
          "error": { "type": "string" },
          "code": { "type": "string" },
          "requestId": { "type": "string" },
          "details": { "type": "object", "additionalProperties": true }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid X-API-Key",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ApiError" },
            "example": { "ok": false, "error": "X-API-Key header is required", "code": "api_key_required", "requestId": "REQ-EXAMPLE" }
          }
        }
      },
      "InsufficientBalance": {
        "description": "Insufficient account balance",
        "content": {
          "application/json": {
            "schema": { "$ref": "#/components/schemas/ApiError" },
            "example": {
              "ok": false,
              "error": "Insufficient balance. Add funds and place the order again.",
              "code": "insufficient_balance",
              "requestId": "REQ-EXAMPLE",
              "details": { "required": "150.00", "balance": "100.00", "currency": "RUB", "topUpUrl": "/addfunds" }
            }
          }
        }
      },
      "Conflict": {
        "description": "Idempotency conflict or action conflict",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "NotFound": {
        "description": "TGLift order not found for this account",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "RateLimited": {
        "description": "Rate limit exceeded. Inspect Retry-After and X-RateLimit-* headers.",
        "headers": {
          "Retry-After": { "schema": { "type": "integer" } },
          "X-RateLimit-Limit": { "schema": { "type": "integer" } },
          "X-RateLimit-Remaining": { "schema": { "type": "integer" } },
          "X-RateLimit-Reset": { "schema": { "type": "integer" } }
        },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      },
      "ServerError": {
        "description": "Temporary TGLift error. Keep requestId for support.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ApiError" } } }
      }
    }
  }
}
