openapi: 3.0.3
info:
  title: Cascade API
  version: 1.0.0
  description: |
    WhatsApp и Telegram OTP API. Получите Bearer-токен в кабинете компании (`/cabinet` → API-ключи).
    Документация: https://cascade.kz/docs
servers:
  - url: https://cascade.kz/api
security:
  - bearerAuth: []
paths:
  /otp/send:
    post:
      summary: Отправить OTP
      operationId: sendOtp
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [phone]
              properties:
                phone:
                  type: string
                  example: "77001234567"
                purpose:
                  type: string
                  default: verification
                  example: verification
                channel:
                  type: string
                  enum: [whatsapp, telegram, sms, auto]
                  description: "Канал доставки. Если не указан — default_channel компании из кабинета (Откуда отправлять). Выключенный в настройках канал вернёт 422."
                link:
                  type: string
                  format: uri
                  maxLength: 2048
                  description: "Опциональный http/https URL — будет укорочен и добавлен в то же сообщение, что и код. Одна отправка = 1 токен."
                  example: "https://example.com/confirm/abc"
                locale:
                  type: string
                  enum: [ru, kk, en]
                  default: ru
                  description: "Язык текста OTP. По умолчанию ru. Шаблоны: GET /otp/messages."
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 255
          description: Повтор с тем же ключом и телом возвращает первый ответ без второй отправки.
      responses:
        "200":
          description: OTP отправлен
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                  expires_in:
                    type: integer
                    example: 300
                  otp_id:
                    type: integer
                    example: 1241
                  channel:
                    type: string
                    example: whatsapp
                  locale:
                    type: string
                    example: ru
                  credits_charged:
                    type: integer
                    example: 1
                  short_url:
                    type: string
                    description: Присутствует, если передан link
                    example: "https://cascade.kz/s/Ab3xK9"
        "401":
          description: Неверный API-токен
        "422":
          description: Ошибка валидации / баланса / канала доставки
  /otp/verify:
    post:
      summary: Проверить OTP
      operationId: verifyOtp
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [phone, code]
              properties:
                phone:
                  type: string
                  example: "77001234567"
                code:
                  type: string
                  example: "123456"
                purpose:
                  type: string
                  default: verification
      responses:
        "200":
          description: Код подтверждён
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
        "401":
          description: Неверный API-токен
        "422":
          description: Неверный или просроченный код
        "429":
          description: Слишком много попыток
  /otp/messages:
    get:
      summary: Шаблоны OTP-сообщений
      operationId: getOtpMessages
      parameters:
        - name: locale
          in: query
          schema:
            type: string
            enum: [ru, kk, en]
            default: ru
      responses:
        "200":
          description: Шаблоны для выбранного языка
  /otp/status:
    get:
      summary: Статус последней OTP-отправки по номеру
      operationId: getOtpStatus
      parameters:
        - name: phone
          in: query
          required: true
          schema:
            type: string
        - name: purpose
          in: query
          schema:
            type: string
            default: verification
      responses:
        "200":
          description: Статус
  /otp/{otp}:
    get:
      summary: Статус OTP по id
      operationId: getOtpById
      parameters:
        - name: otp
          in: path
          required: true
          schema:
            type: integer
      responses:
        "200":
          description: Найдена
        "404":
          description: Нет такой отправки у компании
  /group/send:
    post:
      summary: Отправить уведомление в WhatsApp-группу
      operationId: sendGroupNotify
      description: |
        Отправляет текстовое сообщение в группу. В поле `group` можно передать
        название группы или id (`120363…@g.us`). Авторизация — Bearer API-токен.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [group, message]
              properties:
                group:
                  type: string
                  description: Название группы или WhatsApp group id
                  example: "OTP Alerts"
                message:
                  type: string
                  example: "Новая заявка #123 оплачена"
      responses:
        "200":
          description: Сообщение отправлено
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                  group_id:
                    type: string
                    example: "120363012345678901@g.us"
                  group_name:
                    type: string
                    nullable: true
                  message_id:
                    type: string
                    nullable: true
        "401":
          description: Неверный API-токен
        "404":
          description: Группа не найдена
        "409":
          description: Несколько групп с похожим названием — укажите id
        "422":
          description: Ошибка валидации / отправки
        "503":
          description: WhatsApp не подключён
  /links/shorten:
    post:
      summary: Укоротить URL без отправки
      operationId: shortenLink
      description: |
        Создаёт короткую ссылку `/s/{slug}` без отправки сообщения.
        Бесплатно (токены не списываются).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [url]
              properties:
                url:
                  type: string
                  format: uri
                  maxLength: 2048
                  example: "https://example.com/very/long/path"
                alias:
                  type: string
                  pattern: '^[A-Za-z0-9_-]{3,32}$'
                  description: Свой slug (иначе генерируется случайный)
                  example: "promo-may"
                title:
                  type: string
                  maxLength: 250
                expires_in:
                  type: integer
                  minimum: 60
                  maximum: 2592000
      responses:
        "200":
          description: Ссылка создана
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  short_url:
                    type: string
                    example: "https://cascade.kz/s/promo-may"
                  slug:
                    type: string
                    example: "promo-may"
                  expires_at:
                    type: string
                    format: date-time
                    nullable: true
        "401":
          description: Неверный API-токен
        "422":
          description: Ошибка валидации / занятый alias
  /links/send:
    post:
      summary: Укоротить и отправить ссылку
      operationId: sendLink
      description: |
        Укорачивает URL и отправляет сообщение на телефон через WhatsApp или Telegram.
        Списывает 1 токен за доставленную отправку. Код OTP не генерируется.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [phone, url]
              properties:
                phone:
                  type: string
                  example: "77001234567"
                url:
                  type: string
                  format: uri
                  maxLength: 2048
                  example: "https://example.com/promo"
                channel:
                  type: string
                  enum: [whatsapp, telegram, sms, auto]
                  description: "Если не указан — канал по умолчанию из настроек компании"
                text:
                  type: string
                  maxLength: 500
                  description: "Текст с плейсхолдером :link"
                  example: "Ваша скидка: :link"
                expires_in:
                  type: integer
                  minimum: 60
                  maximum: 2592000
      responses:
        "200":
          description: Ссылка отправлена
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                  short_url:
                    type: string
                    example: "https://cascade.kz/s/Ab3xK9"
                  slug:
                    type: string
                    example: "Ab3xK9"
        "401":
          description: Неверный API-токен
        "422":
          description: Ошибка валидации / баланса / канала доставки
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: API-токен из кабинета компании
