openapi: "3.1.0"
info:
  title: Telephony MiniApp — Исходящие запросы
  description: >
    Исходящие запросы от нашего приложения во внешнее (Acloud → MiniApp).
    Отправляются POST-запросом на endpoint_url, настроенный в интеграции.
    Authorization: Bearer {api_token}
  version: "1.0.0"

x-retry-policy:
  max_retries: 3
  strategy: exponential backoff
  delays_seconds: [1, 2, 4]

x-expected-response:
  success_codes: [200, 201, 202]
  description: >
    Любой 2xx-ответ считается успешным.
    4xx ошибки не ретраются. 5xx ошибки ретраются согласно retry policy.

webhooks:

  call.init:
    post:
      summary: Инициировать исходящий звонок
      description: >
        Запрашивает внешнее приложение инициировать звонок от имени сотрудника.
        Отправляется, когда пользователь нажимает кнопку звонка в интерфейсе Acloud.
      x-headers:
        Content-Type: application/json
        Authorization: Bearer {api_token}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - call.init
                payload:
                  $ref: '#/components/schemas/CallInitPayload'
            examples:
              call_init:
                summary: Инициировать звонок сотрудника клиенту
                value:
                  method: call.init
                  payload:
                    to: "+79995556677"
                    from: "101"
      responses:
        "200":
          description: Запрос на инициацию звонка принят

  call.list:
    post:
      summary: Получить список звонков
      description: >
        Запрашивает список звонков за указанный период.
        Используется для синхронизации звонков из внешней системы.
      x-headers:
        Content-Type: application/json
        Authorization: Bearer {api_token}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - call.list
                payload:
                  $ref: '#/components/schemas/CallListPayload'
            examples:
              call_list_by_days:
                summary: Список звонков за последние 7 дней
                value:
                  method: call.list
                  payload:
                    days_left: 7
              call_list_by_range:
                summary: Список звонков за период
                value:
                  method: call.list
                  payload:
                    from_date: "2026-04-01"
                    to_date: "2026-04-09"
      responses:
        "200":
          description: Список звонков
          content:
            application/json:
              schema:
                type: object
                properties:
                  calls:
                    type: array
                    items:
                      $ref: '#/components/schemas/CallItem'
              examples:
                call_list_response:
                  summary: Список звонков
                  value:
                    calls:
                      - call_id: call_abc123
                        direction: in
                        from: "+79990001234"
                        to: "101"
                        timestamp: "2026-04-09T10:30:00Z"
                        call_duration: 295
                        status: terminated
                        has_record: true
                      - call_id: call_abc124
                        direction: out
                        from: "102"
                        to: "+79991112233"
                        timestamp: "2026-04-09T11:00:00Z"
                        call_duration: 0
                        status: missed
                        has_record: false

  call.get:
    post:
      summary: Получить данные конкретного звонка
      description: >
        Запрашивает данные одного звонка по его идентификатору.
      x-headers:
        Content-Type: application/json
        Authorization: Bearer {api_token}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - call.get
                payload:
                  $ref: '#/components/schemas/CallGetPayload'
            examples:
              call_get:
                summary: Получить звонок по ID
                value:
                  method: call.get
                  payload:
                    call_id: call_abc123
      responses:
        "200":
          description: Данные звонка (null если не найден)
          content:
            application/json:
              schema:
                type: object
                properties:
                  call:
                    oneOf:
                      - $ref: '#/components/schemas/CallItem'
                      - type: "null"
              examples:
                call_found:
                  summary: Звонок найден
                  value:
                    call:
                      call_id: call_abc123
                      direction: in
                      from: "+79990001234"
                      to: "101"
                      timestamp: "2026-04-09T10:30:00Z"
                      call_duration: 295
                      status: terminated
                      has_record: true
                call_not_found:
                  summary: Звонок не найден
                  value:
                    call: null

  sip.employees.list:
    post:
      summary: Получить список SIP-сотрудников
      description: >
        Запрашивает список сотрудников, настроенных в внешней телефонной системе.
        Используется для сопоставления extension сотрудников с пользователями Acloud.
      x-headers:
        Content-Type: application/json
        Authorization: Bearer {api_token}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - sip.employees.list
                payload:
                  type: object
                  description: Пустой payload
            examples:
              sip_employees_list:
                summary: Запрос списка сотрудников
                value:
                  method: sip.employees.list
                  payload: {}
      responses:
        "200":
          description: Список SIP-сотрудников
          content:
            application/json:
              schema:
                type: object
                properties:
                  employees:
                    type: array
                    items:
                      $ref: '#/components/schemas/SipEmployee'
              examples:
                employees_list:
                  summary: Список сотрудников
                  value:
                    employees:
                      - id: "emp_001"
                        name: Иван Иванов
                        email: ivan@example.com
                        extension: "101"
                      - id: "emp_002"
                        name: Мария Петрова
                        email: maria@example.com
                        extension: "102"

  integration.status:
    post:
      summary: Получить статус интеграции
      description: >
        Проверяет доступность и статус интеграции с внешним приложением.
        Используется для health-check и диагностики.
      x-headers:
        Content-Type: application/json
        Authorization: Bearer {api_token}
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - method
                - payload
              properties:
                method:
                  type: string
                  enum:
                    - integration.status
                payload:
                  type: object
                  description: Пустой payload
            examples:
              integration_status:
                summary: Запрос статуса интеграции
                value:
                  method: integration.status
                  payload: {}
      responses:
        "200":
          description: Статус интеграции
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationStatusResponse'
              examples:
                status_active:
                  summary: Интеграция активна
                  value:
                    status: active
                    message: ""
                status_inactive:
                  summary: Интеграция неактивна
                  value:
                    status: inactive
                    message: "API token is invalid"


components:
  schemas:

    OutgoingEvent:
      type: object
      required:
        - method
        - payload
      properties:
        method:
          type: string
          enum:
            - call.init
            - call.list
            - call.get
            - sip.employees.list
            - integration.status
          description: Тип запроса
        payload:
          oneOf:
            - $ref: '#/components/schemas/CallInitPayload'
            - $ref: '#/components/schemas/CallListPayload'
            - $ref: '#/components/schemas/CallGetPayload'
          discriminator:
            propertyName: method

    # ─── call.init ────────────────────────────────────────────────────────────

    CallInitPayload:
      type: object
      description: Параметры для инициации исходящего звонка
      required:
        - to
        - from
      properties:
        to:
          type: string
          description: Номер телефона, на который нужно позвонить
          example: "+79995556677"
        from:
          type: string
          description: Extension (внутренний номер) сотрудника, от имени которого совершается звонок
          example: "101"

    # ─── call.list ────────────────────────────────────────────────────────────

    CallListPayload:
      type: object
      description: >
        Параметры фильтрации для списка звонков. Все поля опциональны.
        Если не указаны — возвращаются все доступные звонки.
      properties:
        days_left:
          type: ["integer", "null"]
          description: Количество дней от текущей даты назад для выборки звонков
          example: 7
        from_date:
          type: ["string", "null"]
          description: Дата начала периода выборки (формат YYYY-MM-DD)
          example: "2026-04-01"
        to_date:
          type: ["string", "null"]
          description: Дата конца периода выборки (формат YYYY-MM-DD)
          example: "2026-04-09"

    # ─── call.get ─────────────────────────────────────────────────────────────

    CallGetPayload:
      type: object
      description: Параметры для получения данных конкретного звонка
      required:
        - call_id
      properties:
        call_id:
          type: string
          description: Уникальный идентификатор звонка во внешней системе
          example: call_abc123

    # ─── Shared types ─────────────────────────────────────────────────────────

    CallItem:
      type: object
      description: Данные одного звонка из внешней системы
      required:
        - call_id
        - direction
        - from
        - to
        - timestamp
        - call_duration
        - status
        - has_record
      properties:
        call_id:
          type: string
          description: Уникальный идентификатор звонка
          example: call_abc123
        direction:
          type: string
          enum:
            - in
            - out
          description: Направление звонка
        from:
          type: string
          description: Источник звонка (номер телефона или extension)
          example: "+79990001234"
        to:
          type: string
          description: Получатель звонка (номер телефона или extension)
          example: "101"
        timestamp:
          type: string
          description: Дата и время звонка в формате ISO 8601
          example: "2026-04-09T10:30:00Z"
        call_duration:
          type: integer
          description: Длительность разговора в секундах
          example: 295
        status:
          type: string
          enum:
            - active
            - terminated
            - missed
          description: Статус звонка
        has_record:
          type: boolean
          description: Флаг наличия записи разговора
          example: true
        record_url:
          type: string
          description: Ссылка на скачивание записи звонка
          example: https://домен/call_id
          nullable: true

    SipEmployee:
      type: object
      description: Данные сотрудника в SIP-системе внешнего приложения
      required:
        - id
        - name
        - email
        - extension
      properties:
        id:
          type: string
          description: Уникальный идентификатор сотрудника во внешней системе
          example: "emp_001"
        name:
          type: string
          description: Отображаемое имя сотрудника
          example: Иван Иванов
        email:
          type: string
          description: Email сотрудника
          example: ivan@example.com
        extension:
          type: string
          description: Внутренний SIP-номер сотрудника
          example: "101"

    IntegrationStatusResponse:
      type: object
      description: Ответ на запрос статуса интеграции
      required:
        - status
      properties:
        status:
          type: string
          enum:
            - active
            - inactive
          description: >
            Текущий статус интеграции.
            `active` — интеграция работает нормально;
            `inactive` — интеграция недоступна или отключена.
        message:
          type: string
          description: Дополнительное сообщение о статусе (например, причина неактивности)
          example: ""
