{
  "openapi": "3.0.3",
  "info": {
    "title": "JoinPoint API",
    "version": "29.09.2026",
    "description": "API кабинета инфлюенсера JoinPoint: подписчики, подписки, платежи, тарифы, ссылки-источники, промокоды и статистика. Каждый запрос видит данные только вашего бота.\n\nДокументация с примерами: https://joinpoint.uz/developers/",
    "contact": {
      "name": "JoinPoint",
      "url": "https://t.me/joinpoint_admin"
    }
  },
  "servers": [
    {
      "url": "https://prod-api.joinpoint.uz/api"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Вход"
    },
    {
      "name": "Подписчики"
    },
    {
      "name": "Подписки"
    },
    {
      "name": "Платежи"
    },
    {
      "name": "Тарифы"
    },
    {
      "name": "Ссылки-источники"
    },
    {
      "name": "Промокоды"
    },
    {
      "name": "Статистика"
    }
  ],
  "paths": {
    "/auth/admin-login": {
      "post": {
        "tags": [
          "Вход"
        ],
        "operationId": "login",
        "summary": "Вход, получение токена",
        "description": "Выдаёт токен по номеру телефона и паролю от кабинета JoinPoint. Токен действует 24 часа; после этого запросы возвращают 401 — войдите снова.\n\n- HTTP-код успешного входа — 201.\n\n- Неверный телефон или пароль — 400. Кабинет приостановлен или бот на паузе — 403.\n\n- 5 неудачных попыток на один номер или 10 с одного IP за 15 минут — ответ 429, вход закрыт на 15 минут.",
        "responses": {
          "201": {
            "description": "Создано",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 42,
                    "phone": "+998901234567",
                    "name": "Premium kanal",
                    "channelId": "-1001234567890",
                    "channelName": "Premium kanal",
                    "freeTrial": 0,
                    "isActive": true,
                    "note": null,
                    "isNavigation": false,
                    "status": "active",
                    "isSuspended": false,
                    "role": "admin",
                    "trialNotifyEnabled": false
                  },
                  "meta": {
                    "message": "success",
                    "statusCode": 200,
                    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.…",
                    "hasTelegramUsers": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "phone",
                  "password"
                ],
                "properties": {
                  "phone": {
                    "type": "string",
                    "description": "Телефон кабинета в формате `+998XXXXXXXXX`."
                  },
                  "password": {
                    "type": "string",
                    "description": "Пароль от кабинета."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "phone": "+998901234567",
                "password": "YOUR_PASSWORD"
              }
            }
          }
        }
      }
    },
    "/user-bot": {
      "get": {
        "tags": [
          "Подписчики"
        ],
        "operationId": "subs",
        "summary": "Подписчики",
        "description": "Все, кто запускал вашего бота, с фильтром по сегменту и поиском.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 100501,
                      "createdAt": "2026-06-08T12:31:40.512Z",
                      "lastUpdatedAt": "2026-09-28T07:17:02.114Z",
                      "firstname": "Aziz",
                      "lastname": null,
                      "status": "created",
                      "inChannel": true,
                      "isUnlimited": false,
                      "lang": "uz",
                      "role": "user",
                      "useFreeTrial": false,
                      "bot": {
                        "id": 42,
                        "name": "Premium kanal"
                      },
                      "user": {
                        "id": 900001,
                        "tgUsername": "aziz_example",
                        "tgId": "1234567890",
                        "tgPhone": "998901234567",
                        "createdAt": "2026-06-08T12:31:40.500Z",
                        "lastUpdatedAt": "2026-06-08T12:31:40.500Z",
                        "userDetail": null
                      },
                      "startingPoint": null
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200,
                    "currentPage": 1,
                    "totalPages": 25,
                    "total": 1238,
                    "count": 50,
                    "hasPrev": false,
                    "hasNext": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "description": "Сегмент: `all` — все; `subscribed` — с действующей подпиской; `not_subscribed` — ни разу не оформляли; `not_confirm_card` — начали оплату, но не подтвердили карту; `subscribed_ended` — подписка закончилась; `subscribed_ended_after_free_trial` — пробный период закончился без оплаты; `free_trial` — сейчас на пробном периоде; `free` — на бесплатном тарифе без карты.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Поиск по имени, Telegram ID, username или телефону.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "createdAt",
            "in": "query",
            "required": false,
            "description": "Сортировка по дате появления: `ascend` или `descend`. Так же работают `name` и `status`.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/user-bot/get-count": {
      "get": {
        "tags": [
          "Подписчики"
        ],
        "operationId": "subsCount",
        "summary": "Размер сегмента",
        "description": "Сколько подписчиков в сегменте. Параметры `page` и `count` обязательны, но на результат не влияют.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "count": 1238
                  },
                  "meta": {
                    "message": "success",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "filter",
            "in": "query",
            "required": false,
            "description": "Сегмент, как в `/user-bot`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Поиск, как в `/user-bot`.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/user-bot/{id}": {
      "get": {
        "tags": [
          "Подписчики"
        ],
        "operationId": "sub",
        "summary": "Карточка подписчика",
        "description": "Один подписчик вашего бота. Чужой ID — ответ 404.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 100501,
                    "createdAt": "2026-06-08T12:31:40.512Z",
                    "lastUpdatedAt": "2026-09-28T07:17:02.114Z",
                    "firstname": "Aziz",
                    "lastname": null,
                    "status": "created",
                    "inChannel": true,
                    "isUnlimited": false,
                    "lang": "uz",
                    "role": "user",
                    "useFreeTrial": false,
                    "bot": {
                      "id": 42,
                      "name": "Premium kanal"
                    },
                    "user": {
                      "id": 900001,
                      "tgUsername": "aziz_example",
                      "tgId": "1234567890",
                      "tgPhone": "998901234567",
                      "createdAt": "2026-06-08T12:31:40.500Z",
                      "lastUpdatedAt": "2026-06-08T12:31:40.500Z"
                    },
                    "startingPoint": null
                  },
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID подписчика (`/user-bot[].id`).",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/clients": {
      "get": {
        "tags": [
          "Подписчики"
        ],
        "operationId": "clients",
        "summary": "Реестр клиентов",
        "description": "Плоский список подписчиков для CRM: статус подписки и ссылка, по которой человек пришёл. Телефоны приходят с маской. У метода своя обёртка ответа — без `meta`.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "user_bot_id": 100501,
                      "tg_id": "1234567890",
                      "full_name": "Aziz",
                      "phone": "+99890***4567",
                      "tg_username": "aziz_example",
                      "lang": "uz",
                      "registered_at": "2026-06-08T12:31:40.512Z",
                      "bot_id": 42,
                      "bot_name": "Premium kanal",
                      "source_id": 12,
                      "source_name": "Instagram stories",
                      "source_raw": "1759000000001",
                      "attributed_at": "2026-06-08T12:31:41.000Z",
                      "in_channel": true,
                      "subscription_status": "active"
                    }
                  ],
                  "total": 1238,
                  "page": 1,
                  "count": 100,
                  "phonesMasked": true
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Номер страницы, по умолчанию 1.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": false,
            "description": "Строк на странице, по умолчанию 50, максимум 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "description": "Дата регистрации «с», формат `YYYY-MM-DD`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "description": "Дата регистрации «по», формат `YYYY-MM-DD`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`active` — оплачен доступ, `expired` — закончился, `cancelled` — отменён, `never_paid` — ни разу не оформлял.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sourceId",
            "in": "query",
            "required": false,
            "description": "Только пришедшие по ссылке с этим ID.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Поиск по имени, username, Telegram ID, телефону.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/user-bot-plan": {
      "get": {
        "tags": [
          "Подписки"
        ],
        "operationId": "subscriptions",
        "summary": "Подписки",
        "description": "История подписок ваших подписчиков. У одного человека может быть несколько записей.\n\n- Есть ли доступ сейчас: у подписчика есть запись с `nextDate` в будущем.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 70001,
                      "createdAt": "2026-09-28T07:16:55.231Z",
                      "lastUpdatedAt": "2026-09-28T07:17:01.903Z",
                      "deletedAt": null,
                      "note": null,
                      "isActive": true,
                      "isDeleted": false,
                      "createdBy": null,
                      "lastUpdatedBy": null,
                      "deletedBy": null,
                      "status": "active",
                      "paymentType": "atmos-uzcard-humo",
                      "nextDate": "2026-10-28T07:16:55.000Z",
                      "retryDate": "2026-10-28T07:16:55.000Z",
                      "repeatTimes": 0,
                      "userBot": {
                        "id": 100501,
                        "firstname": "Aziz",
                        "status": "created",
                        "inChannel": true,
                        "isUnlimited": false,
                        "lang": "uz",
                        "role": "user"
                      },
                      "plan": {
                        "id": 7,
                        "name": "1 oy",
                        "type": "1",
                        "price": "50000000",
                        "status": "accepted",
                        "freeTrial": 0,
                        "cardRequired": true,
                        "freeDays": 0
                      }
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200,
                    "currentPage": 1,
                    "totalPages": 1,
                    "total": 3,
                    "count": 50,
                    "hasPrev": false,
                    "hasNext": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "userBotId",
            "in": "query",
            "required": false,
            "description": "Только подписки этого подписчика.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Только в этом статусе, см. «Статусы подписки».",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Подписки"
        ],
        "operationId": "grant",
        "summary": "Выдать доступ вручную",
        "description": "Открывает подписчику доступ без списания с карты: бесплатно на N дней или по тарифу, оплаченному наличными или переводом.\n\n- Передайте ровно одно из полей: `day` (для `free`) или `planId` (для `cash`/`transfer`). Иначе — 400.\n\n- Если у человека уже действует ручной доступ или разовая оплата, новый период добавляется к его концу.\n\n- Если у человека включено автопродление картой, выдать доступ нельзя — ответ 400.\n\n- Для `cash` и `transfer` создаётся запись об успешной оплате на сумму тарифа: она попадает в выручку и статистику.\n\n- Ссылку в канал человек получает сам: команда /link в боте или кнопка в мини-приложении. Сообщите ему об этом.\n\n- Успешный ответ — HTTP 201, запись со статусом `manual-active`.",
        "responses": {
          "201": {
            "description": "Создано",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 70002,
                    "createdAt": "2026-09-29T09:00:00.000Z",
                    "lastUpdatedAt": "2026-09-29T09:00:00.000Z",
                    "status": "manual-active",
                    "paymentType": "atmos-uzcard-humo",
                    "nextDate": "2026-10-29T09:00:00.000Z",
                    "retryDate": "2026-10-29T09:00:00.000Z",
                    "repeatTimes": 0,
                    "isActive": false,
                    "note": "Manual created"
                  },
                  "meta": {
                    "message": "created",
                    "statusCode": 201
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "userBotId",
                  "type"
                ],
                "properties": {
                  "userBotId": {
                    "type": "integer",
                    "description": "ID подписчика вашего бота."
                  },
                  "type": {
                    "type": "string",
                    "description": "`free` — бесплатно; `cash` — наличными; `transfer` — переводом."
                  },
                  "day": {
                    "type": "integer",
                    "description": "Только для `free`: на сколько дней, от 1 до 200."
                  },
                  "planId": {
                    "type": "integer",
                    "description": "Только для `cash` и `transfer`: ID вашего тарифа в статусе `accepted`. Срок берётся из тарифа."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "userBotId": 100501,
                "type": "free",
                "day": 30
              }
            }
          }
        }
      }
    },
    "/user-bot-plan/{id}": {
      "patch": {
        "tags": [
          "Подписки"
        ],
        "operationId": "cancel",
        "summary": "Отключить автопродление",
        "description": "Выключает автопродление подписки. Доступ сохраняется до `nextDate`, дальше списаний не будет. Тело запроса не нужно.\n\n- После вызова статус подписки — `manual-canceled`, `isActive` = `false`.\n\n- Работает только для подписки с включённым автопродлением (`isActive` = `true`), иначе — ошибка.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 70001,
                    "status": "manual-canceled",
                    "isActive": false,
                    "repeatTimes": 0,
                    "nextDate": "2026-10-28T07:16:55.000Z"
                  },
                  "meta": {
                    "message": "update",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID подписки вашего подписчика (`/user-bot-plan[].id`).",
            "schema": {
              "type": "integer"
            }
          }
        ]
      },
      "delete": {
        "tags": [
          "Подписки"
        ],
        "operationId": "deleteGrant",
        "summary": "Удалить ручной доступ",
        "description": "Удаляет запись о ручном доступе (статус `manual-active` или `manual-canceled`). Другие подписки так удалить нельзя — ответ 400.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "status": "manual-active",
                    "isActive": false
                  },
                  "meta": {
                    "message": "removed",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID ручной подписки.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/transaction-meta/transactions/{botId}": {
      "get": {
        "tags": [
          "Платежи"
        ],
        "operationId": "txList",
        "summary": "Платежи",
        "description": "Все платежи и попытки списания по вашему боту, включая неудачные. Выручка — записи со статусом `success`.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 500001,
                      "createdat": "2026-09-28T07:16:55.231Z",
                      "lastUpdatedAt": "2026-09-28T07:17:01.903Z",
                      "status": "success",
                      "price": "500000",
                      "type": "atmos-uzcard-humo",
                      "extId": "5f1c2a9e-3b7d-4e61-9a0c-2d84b6e1f3a7",
                      "refundedat": null,
                      "refundamount": null,
                      "plan": {
                        "id": 7,
                        "name": "1 oy",
                        "type": "1",
                        "price": 500000
                      },
                      "user": {
                        "id": 900001,
                        "tgUsername": "aziz_example",
                        "tgId": "1234567890",
                        "tgPhone": "998901234567",
                        "username": null
                      },
                      "userbot": {
                        "id": 100501,
                        "firstname": "Aziz",
                        "lastname": null,
                        "status": "created",
                        "inChannel": true,
                        "isUnlimited": false,
                        "lang": "uz",
                        "role": "user",
                        "useFreeTrial": false
                      },
                      "basket": {
                        "message": null,
                        "code": null
                      },
                      "transactionId": null
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200,
                    "currentPage": 1,
                    "totalPages": 4,
                    "total": 312,
                    "count": 100,
                    "hasPrev": false,
                    "hasNext": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "botId",
            "in": "path",
            "required": true,
            "description": "Любое число: всегда используется бот из токена. Удобно передавать `0`.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Только в этом статусе, например `success`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "userBotId",
            "in": "query",
            "required": false,
            "description": "Только платежи этого подписчика.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "planId",
            "in": "query",
            "required": false,
            "description": "Только по этому тарифу.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": false,
            "description": "Начало периода, ISO 8601. Только вместе с `toDate`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "required": false,
            "description": "Конец периода, ISO 8601.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Поиск по имени, телефону, username.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/transaction-meta/{id}": {
      "get": {
        "tags": [
          "Платежи"
        ],
        "operationId": "tx",
        "summary": "Карточка платежа",
        "description": "Один платёж вашего бота. Сумма здесь в тийинах, номер карты замаскирован.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 500001,
                    "createdAt": "2026-09-28T07:16:55.231Z",
                    "lastUpdatedAt": "2026-09-28T07:17:01.903Z",
                    "deletedAt": null,
                    "note": null,
                    "isActive": true,
                    "isDeleted": false,
                    "createdBy": null,
                    "lastUpdatedBy": null,
                    "deletedBy": null,
                    "extId": "5f1c2a9e-3b7d-4e61-9a0c-2d84b6e1f3a7",
                    "type": "atmos-uzcard-humo",
                    "price": "50000000",
                    "cardNumber": "860012******3456",
                    "userId": 900001,
                    "botId": 42,
                    "planId": 7,
                    "status": "success",
                    "userBotPlanId": null,
                    "transactionId": null
                  },
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID платежа.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/transaction-meta/userbot/{userBotId}": {
      "get": {
        "tags": [
          "Платежи"
        ],
        "operationId": "txSub",
        "summary": "Платежи подписчика",
        "description": "История оплат одного подписчика. Суммы в сумах.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 500001,
                      "createdat": "2026-09-28T07:16:55.231Z",
                      "lastupdatedat": "2026-09-28T07:17:01.903Z",
                      "status": "success",
                      "price": "500000",
                      "type": "atmos-uzcard-humo",
                      "plan": {
                        "id": 7,
                        "name": "1 oy",
                        "type": "1",
                        "price": 500000
                      }
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200,
                    "currentPage": 1,
                    "totalPages": 1,
                    "total": 4,
                    "count": 50,
                    "hasPrev": false,
                    "hasNext": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "userBotId",
            "in": "path",
            "required": true,
            "description": "ID подписчика.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/transaction-meta/statistics/{userBotId}": {
      "get": {
        "tags": [
          "Платежи"
        ],
        "operationId": "txSubStats",
        "summary": "Итоги подписчика",
        "description": "Сколько подписчик заплатил за всё время.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "yearlyPlans": 0,
                    "totalPlans": 4,
                    "totalAmount": 2000000
                  },
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "userBotId",
            "in": "path",
            "required": true,
            "description": "ID подписчика.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/transaction-meta/plan-summary": {
      "get": {
        "tags": [
          "Платежи"
        ],
        "operationId": "planSummary",
        "summary": "Выручка по тарифам",
        "description": "Успешные оплаты, сгруппированные по тарифам. Суммы в сумах.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "plan_id": 7,
                      "plan_name": "1 oy",
                      "plan_months": "1",
                      "plan_price": "500000",
                      "payments": 118,
                      "amount": "59000000",
                      "subscribers": 113
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "fromDate",
            "in": "query",
            "required": false,
            "description": "Начало периода, ISO 8601. Только вместе с `toDate`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "required": false,
            "description": "Конец периода, ISO 8601.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/plan": {
      "get": {
        "tags": [
          "Тарифы"
        ],
        "operationId": "tariffs",
        "summary": "Тарифы",
        "description": "Тарифы вашего бота. Удалённые не показываются, если не передать `status=deleted`. Цена здесь в сумах.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 7,
                      "createdAt": "2025-06-02T07:14:03.120Z",
                      "isActive": true,
                      "name": "1 oy",
                      "type": "1",
                      "price": 500000,
                      "status": "accepted",
                      "freeTrial": 0,
                      "cardRequired": true,
                      "freeDays": 0,
                      "startingPoint": null,
                      "bot": {
                        "id": 42,
                        "name": "Premium kanal"
                      }
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "`accepted`, `pending`, `rejected`, `paused` или `deleted`.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/plan/{id}": {
      "get": {
        "tags": [
          "Тарифы"
        ],
        "operationId": "tariff",
        "summary": "Карточка тарифа",
        "description": "Один тариф вашего бота. Цена здесь в тийинах. Чужой тариф — ответ 403.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 7,
                    "createdAt": "2025-06-02T07:14:03.120Z",
                    "name": "1 oy",
                    "type": "1",
                    "price": "50000000",
                    "status": "accepted",
                    "freeTrial": 0,
                    "cardRequired": true,
                    "freeDays": 0,
                    "bot": {
                      "id": 42,
                      "name": "Premium kanal"
                    },
                    "userBotPlans": [
                      {
                        "id": 70001
                      }
                    ],
                    "startingPoint": null
                  },
                  "meta": {
                    "message": "found",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID тарифа.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/starting-point": {
      "get": {
        "tags": [
          "Ссылки-источники"
        ],
        "operationId": "sources",
        "summary": "Ссылки-источники",
        "description": "Ссылки, по которым люди приходят в бота, со счётчиками.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 12,
                      "createdAt": "2026-03-10T09:00:00.000Z",
                      "lastUpdatedAt": "2026-03-10T09:00:00.000Z",
                      "deletedAt": null,
                      "note": null,
                      "isActive": true,
                      "isDeleted": false,
                      "createdBy": null,
                      "lastUpdatedBy": null,
                      "deletedBy": null,
                      "name": "Instagram stories",
                      "extId": "1759000000001",
                      "redirectUrl": null,
                      "clickCount": 1520,
                      "userCount": 845,
                      "subscribersCount": 61,
                      "allowedTelegramIds": null,
                      "expireDate": "2030-12-31T19:00:00.000Z",
                      "deepLink": "https://t.me/my_channel_bot?start=1759000000001",
                      "redirectDropsPayload": false,
                      "attributionDisabledReason": null
                    }
                  ],
                  "meta": {
                    "message": "found",
                    "statusCode": 200,
                    "currentPage": 1,
                    "totalPages": 1,
                    "total": 21,
                    "count": 50,
                    "hasPrev": false,
                    "hasNext": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "required": true,
            "description": "Номер страницы, от 1 до 500.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "count",
            "in": "query",
            "required": true,
            "description": "Строк на странице, от 5 до 200 000. Рекомендуем до 1 000.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "search",
            "in": "query",
            "required": false,
            "description": "Поиск по названию и метке.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": false,
            "description": "Пересчитать счётчики за период: начало, ISO 8601. Только вместе с `toDate`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "required": false,
            "description": "Конец периода, ISO 8601.",
            "schema": {
              "type": "string"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Ссылки-источники"
        ],
        "operationId": "sourceCreate",
        "summary": "Создать ссылку-источник",
        "description": "Создаёт новую отслеживаемую ссылку. Метка `extId` генерируется автоматически.\n\n- Успешный ответ — HTTP 201. В ответе есть готовая `deepLink`.",
        "responses": {
          "201": {
            "description": "Создано",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 13,
                    "name": "Instagram stories",
                    "extId": "1759200000077",
                    "redirectUrl": null,
                    "clickCount": 0,
                    "userCount": 0,
                    "subscribersCount": 0,
                    "expireDate": "2030-12-31T19:00:00.000Z",
                    "deepLink": "https://t.me/my_channel_bot?start=1759200000077",
                    "redirectDropsPayload": false,
                    "attributionDisabledReason": null
                  },
                  "meta": {
                    "message": "created",
                    "statusCode": 201
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "expireDate"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "description": "Название, например «Instagram — сторис»."
                  },
                  "expireDate": {
                    "type": "string",
                    "description": "До какой даты ссылка работает, ISO 8601."
                  },
                  "redirectUrl": {
                    "type": "string",
                    "description": "Сайт, который открыть перед ботом (полный URL)."
                  },
                  "allowedTelegramIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Если задан, ссылка засчитывается только для этих Telegram ID."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "name": "Instagram stories",
                "expireDate": "2030-12-31T19:00:00.000Z"
              }
            }
          }
        }
      }
    },
    "/promo": {
      "get": {
        "tags": [
          "Промокоды"
        ],
        "operationId": "promoList",
        "summary": "Промокоды",
        "description": "Промокоды вашего бота со статистикой использования. Поля в `snake_case`.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": 3,
                      "code": "STORY30",
                      "discount_type": "percent",
                      "discount_value": 30,
                      "scope": "bot",
                      "bot_id": 42,
                      "plan_id": null,
                      "max_uses": 100,
                      "used_count": 7,
                      "per_user_once": true,
                      "valid_from": null,
                      "valid_until": "2026-10-31T18:59:59.000Z",
                      "is_active": true,
                      "created_at": "2026-09-20T08:00:00.000Z",
                      "updated_at": "2026-09-20T08:00:00.000Z",
                      "bot_name": "Premium kanal",
                      "plan_name": null,
                      "redemption_count": 7,
                      "discount_given_tiyin": "105000000"
                    }
                  ],
                  "meta": {
                    "message": "Promo codes",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "Промокоды"
        ],
        "operationId": "promoCreate",
        "summary": "Создать промокод",
        "description": "Создаёт промокод на скидку при оформлении подписки.\n\n- Цена любого тарифа после скидки должна остаться не меньше 10 сум, иначе 400.\n\n- Код должен быть уникальным. Успешный ответ — HTTP 201.",
        "responses": {
          "201": {
            "description": "Создано",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 3,
                    "code": "STORY30",
                    "discount_type": "percent",
                    "discount_value": 30,
                    "scope": "bot",
                    "bot_id": 42,
                    "plan_id": null,
                    "max_uses": 100,
                    "used_count": 0,
                    "per_user_once": true,
                    "valid_from": null,
                    "valid_until": "2026-10-31T18:59:59.000Z",
                    "is_active": true,
                    "created_at": "2026-09-20T08:00:00.000Z",
                    "updated_at": "2026-09-20T08:00:00.000Z"
                  },
                  "meta": {
                    "message": "Promo code created",
                    "statusCode": 201
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "discountType",
                  "discountValue",
                  "maxUses",
                  "validUntil"
                ],
                "properties": {
                  "discountType": {
                    "type": "string",
                    "description": "`percent` — процент, `fixed` — фиксированная сумма."
                  },
                  "discountValue": {
                    "type": "integer",
                    "description": "Для `percent` — от 1 до 50. Для `fixed` — сумма в сумах."
                  },
                  "maxUses": {
                    "type": "integer",
                    "description": "Сколько раз код можно применить всего, от 1 до 100 000."
                  },
                  "validUntil": {
                    "type": "string",
                    "description": "До какого момента действует, ISO 8601, в будущем."
                  },
                  "validFrom": {
                    "type": "string",
                    "description": "С какого момента действует."
                  },
                  "code": {
                    "type": "string",
                    "description": "Свой код: 3–32 символа, латиница, цифры, `_` и `-`. Приводится к верхнему регистру. Без него код сгенерируется."
                  },
                  "planId": {
                    "type": "integer",
                    "description": "Только для этого тарифа. Без поля — для всех платных тарифов."
                  },
                  "perUserOnce": {
                    "type": "boolean",
                    "description": "Один раз на человека, по умолчанию `true`."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "discountType": "percent",
                "discountValue": 30,
                "maxUses": 100,
                "validUntil": "2026-10-31T18:59:59Z",
                "code": "STORY30"
              }
            }
          }
        }
      }
    },
    "/promo/{id}": {
      "patch": {
        "tags": [
          "Промокоды"
        ],
        "operationId": "promoUpdate",
        "summary": "Изменить промокод",
        "description": "Включает или выключает код, меняет лимит и срок. Передайте хотя бы одно поле.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": {
                    "id": 3,
                    "code": "STORY30",
                    "discount_type": "percent",
                    "discount_value": 30,
                    "scope": "bot",
                    "bot_id": 42,
                    "plan_id": null,
                    "max_uses": 100,
                    "used_count": 7,
                    "per_user_once": true,
                    "valid_from": null,
                    "valid_until": "2026-10-31T18:59:59.000Z",
                    "is_active": false,
                    "created_at": "2026-09-20T08:00:00.000Z",
                    "updated_at": "2026-09-20T08:00:00.000Z",
                    "bot_name": "Premium kanal",
                    "plan_name": null,
                    "redemption_count": 7,
                    "discount_given_tiyin": "105000000"
                  },
                  "meta": {
                    "message": "Promo code updated",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID промокода.",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "isActive": {
                    "type": "boolean",
                    "description": "`false` — выключить код."
                  },
                  "maxUses": {
                    "type": "integer",
                    "description": "Новый лимит, не меньше уже использованного."
                  },
                  "validUntil": {
                    "type": "string",
                    "description": "Новый срок, ISO 8601."
                  }
                },
                "additionalProperties": false
              },
              "example": {
                "isActive": false
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Промокоды"
        ],
        "operationId": "promoDelete",
        "summary": "Удалить промокод",
        "description": "Удаляет код, который ни разу не применяли. Использованный код можно только выключить.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": null,
                  "meta": {
                    "message": "Promo code deleted",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "ID промокода.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/user-bot/today-statistics": {
      "get": {
        "tags": [
          "Статистика"
        ],
        "operationId": "statsToday",
        "summary": "Продажи за день",
        "description": "Продажи и выручка за день или период. По умолчанию — за сегодня. Ответ — массив из одного объекта. Суммы в сумах, числа приходят строками.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "subscribers_in_channel": "1238",
                      "total_revenue_today": "61500000",
                      "sales_today": "123",
                      "average_sale_price_today": "500000"
                    }
                  ],
                  "meta": {
                    "message": "success",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        },
        "parameters": [
          {
            "name": "startDate",
            "in": "query",
            "required": false,
            "description": "Начало периода, `YYYY-MM-DD`.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "endDate",
            "in": "query",
            "required": false,
            "description": "Конец периода, `YYYY-MM-DD`.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    },
    "/user-bot/statistics/{botId}": {
      "get": {
        "tags": [
          "Статистика"
        ],
        "operationId": "stats",
        "summary": "Сводка по боту",
        "description": "Общие показатели бота за всё время. Ответ — массив из одного объекта. Суммы в сумах.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "subscribers_in_channel": "1238",
                      "total_revenue": "1832000000",
                      "all_users_count": "69946",
                      "starting_point_users_count": "30870",
                      "average_check": "512340.55",
                      "subscriber_conversion_percent": 5.2,
                      "user_conversion_percent": 44.1,
                      "subscribed_ended_after_free_trial": 139,
                      "subscribed_ended_after_plan": 12083,
                      "not_subscribed": 51210,
                      "subscribed": 1238,
                      "not_confirm_card": 3587
                    }
                  ],
                  "meta": {
                    "message": "success",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "botId",
            "in": "path",
            "required": true,
            "description": "Любое число: всегда используется бот из токена. Удобно передавать `0`.",
            "schema": {
              "type": "integer"
            }
          }
        ]
      }
    },
    "/user-bot/period-statistics/{botId}": {
      "get": {
        "tags": [
          "Статистика"
        ],
        "operationId": "statsPeriod",
        "summary": "Воронка за период",
        "description": "Новые пользователи, подписки и выручка за период. Ответ — массив из одного объекта. Суммы в сумах.",
        "responses": {
          "200": {
            "description": "Успешно",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "starting_point_users_count": "1840",
                      "all_users_count": "4120",
                      "subscribed": "236",
                      "subscribers_in_channel": "1238",
                      "total_revenue": "118000000",
                      "average_check": "500000.00",
                      "user_conversion_percent": 44.6,
                      "subscriber_conversion_percent": 5.7
                    }
                  ],
                  "meta": {
                    "message": "success",
                    "statusCode": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        },
        "parameters": [
          {
            "name": "botId",
            "in": "path",
            "required": true,
            "description": "Любое число: всегда используется бот из токена. Удобно передавать `0`.",
            "schema": {
              "type": "integer"
            }
          },
          {
            "name": "fromDate",
            "in": "query",
            "required": true,
            "description": "Начало периода, ISO 8601.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "toDate",
            "in": "query",
            "required": true,
            "description": "Конец периода, ISO 8601.",
            "schema": {
              "type": "string"
            }
          }
        ]
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "description": "Токен из POST /auth/admin-login. Действует 24 часа."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "data": {
            "description": "null"
          },
          "meta": {
            "type": "object",
            "properties": {
              "message": {
                "type": "string"
              },
              "statusCode": {
                "type": "integer"
              }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Ошибка в параметрах или теле запроса",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Нет токена, токен истёк или неверный",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "data": null,
              "meta": {
                "message": "Authorization Error!",
                "statusCode": 401
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Нет доступа, кабинет приостановлен или бот на паузе",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "data": null,
              "meta": {
                "message": "Forbidden Error!",
                "statusCode": 403
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Не найдено или запись другого бота",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Слишком много неудачных попыток входа, подождите 15 минут",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "data": null,
              "meta": {
                "message": "Too many failed login attempts. Try again in 15 minutes.",
                "statusCode": 429
              }
            }
          }
        }
      }
    }
  }
}
