← Все статьи
Руководство

Голосовые звонки WhatsApp в службе поддержки: от ссылки до вебхука

Чтобы добавить голосовые звонки WhatsApp в систему поддержки через UnifyPort, сервер подготавливает звонок с media_type: "voice" и передаёт назначенному оператору приватную ссылку для браузера. Набор начинается, когда оператор открывает её и нажимает Start call. Сервер связывает полученный call_id с задачей поддержки и отслеживает результат по событиям звонка.

Руководство описывает исходящие звонки одному собеседнику, запускаемые человеком в закрытой бете. UnifyPort использует неофициальный интерфейс; это не инструкция для Meta WhatsApp Business Calling API. Обзор возможностей и порядок подачи заявки есть в анонсе беты звонков.

1. Подготовьте аккаунт и выберите диалог

Попросите техническую поддержку включить доступ к звонкам для рабочего пространства. Создание API-ключа не открывает доступ: is_beta — признак допуска только для чтения, а не настройка, которую можно изменить через metadata рабочего пространства.

Перед отображением действия звонка убедитесь, что аккаунт мессенджера WhatsApp авторизован и его runtime_status равен running. Выберите личный диалог этого же аккаунта и сохраните возвращённый conversation_id. Не подставляйте вместо него номер телефона и не собирайте идентификатор провайдера самостоятельно.

В приложении закрепите за действием выбранные рабочее пространство, аккаунт, диалог и задачу поддержки. Проверяйте права оператора на сервере. Новое сообщение или переключение диалога не должно незаметно менять адресата уже подготовленного звонка.

В примерах API-ключ остаётся на сервере. Браузер получает только нужную ему приватную ссылку.

2. Подготовьте голосовой звонок на сервере

Замените заполнители API-ключом рабочего пространства, подключённым аккаунтом и выбранным диалогом. Выполните запрос на сервере:

curl -X POST 'https://api.unifyport.ai/v1/calls' \
  -H 'X-Api-Key: <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{
    "account_id": "acc_example",
    "to": { "id": "<conversation_id>", "type": "user" },
    "media_type": "voice"
  }'

Справочник создания звонка описывает ответ 201 Created следующей структуры. Значения приведены для примера и не подтверждают реальный звонок:

{
  "request_id": "req_example",
  "data": {
    "call_id": "call_example",
    "direction": "outbound",
    "media_type": "voice",
    "state": "preparing",
    "join_url": "https://calls.example.com/call/call_example#ticket=example-only",
    "expires_at": "2026-10-27T08:02:00Z"
  }
}

Сохраните data.call_id вместе с выбранными аккаунтом, диалогом и задачей. Сохраните request_id для диагностики. Считайте data.join_url секретом: передайте его без изменений назначенному оператору. Полный URL не должен попадать в журналы, аналитику или публичные сообщения.

201 и preparing означают, что ссылка готова. Они не означают, что телефон клиента звонит или клиент ответил.

3. Дайте оператору начать звонок в браузере

В интерфейсе покажите выбранного клиента и индикатор готовности к запуску. Предоставляйте join_url только нужному оператору. На странице звонка оператор разрешает доступ к микрофону и нажимает Start call до наступления expires_at.

По умолчанию подготовка действует две минуты с момента создания, но сервер может менять срок. Читайте expires_at, а не вычисляйте жёстко заданный дедлайн. Этот срок не ограничивает длительность уже соединённого звонка. Доступ к микрофону обязателен, к камере — необязателен.

Блокируйте повторную отправку, пока приложение ждёт ответ создания. Если ответ потерян, покажите неопределённый результат и запросите текущий звонок, прежде чем рассматривать новый запрос создания. Одна заблокированная кнопка не координирует нескольких операторов, поэтому обрабатывайте конфликты на уровне аккаунта и на сервере.

4. Свяжите вебхуки с задачей поддержки

Если вебхук использует явный список событий, добавьте оба имени ниже, сохранив остальные нужные подписки. Это фрагмент поля, а не полный запрос создания вебхука:

{
  "subscribed_events": ["call.answered", "call.ended"]
}

В рабочих пространствах с доступом к бете *, пустой или отсутствующий список также включает разрешённые события звонков. Подписка с шаблоном не предоставляет доступ к этим событиям рабочим пространствам вне беты.

НаблюдениеДействие приложения
data.call_id в ответе созданияСвязать звонок с выбранной задачей поддержки
data.call.id в call.answeredЗафиксировать, что соединение установлено
data.call.id, data.reason, data.duration_seconds в call.endedЗаписать причину завершения и длительность соединения

Перед обработкой подписанных событий настройте signing_secret у вебхука и храните этот секрет на сервере.

Проверяйте подпись по исходному телу запроса и устраняйте дубликаты по id конверта события согласно контракту доставки. Сопоставляйте account_id и data.call.id события с сохранённой связью. Запоздавшее или повторное событие не должно возвращать завершённый звонок в состояние разговора в интерфейсе.

Храните подтверждение ответа отдельно: duration_seconds округляется вниз, поэтому 0 само по себе не доказывает отсутствие ответа. Синхронная ошибка создания может не сопровождаться событием завершения; фиксируйте HTTP-ошибки отдельно. Полные данные описаны в справочниках события ответа и события завершения. Завершение звонка не означает автоматического решения задачи поддержки.

5. Запросите или завершите управляемый звонок

Для восстановления состояния или потерянного идентификатора используйте получение текущего звонка:

curl --get 'https://api.unifyport.ai/v1/calls/active' \
  -H 'X-Api-Key: <YOUR_API_KEY>' \
  --data-urlencode 'account_id=acc_example'

data: {} означает отсутствие текущего звонка, которым UnifyPort управляет для этого аккаунта. Это не история звонков, не подтверждение результата предыдущей попытки и не способ обнаружить звонок в родном приложении WhatsApp. Ответ не выдаёт одноразовый join_url повторно.

Когда оператор решает завершить известный звонок, используйте сохранённый call_id и его аккаунт:

curl -X POST 'https://api.unifyport.ai/v1/calls/call_example/hangup' \
  -H 'X-Api-Key: <YOUR_API_KEY>' \
  -H 'Content-Type: application/json' \
  -d '{"account_id":"acc_example"}'

Метод завершения звонка возвращает конечное состояние ended или failed; повторный запрос может вернуть уже существующее конечное состояние. Не повторяйте запрос лишь из-за failed и не завершайте звонок другого оператора только для устранения конфликта создания.

Частые проблемы интеграции

СитуацияСледующий шаг
403 beta_feature_not_enabledУточнить допуск рабочего пространства у поддержки; metadata не включает доступ
Истёк срок ссылки подготовкиПерестать использовать ссылку, проверить текущий звонок и дать оператору явно решить, нужна ли новая подготовка
Браузеру недоступен микрофонПроверить разрешение для страницы звонка, прежде чем ожидать успешного набора
Создание конфликтует с существующим звонкомЗапросить управляемый звонок и определить его оператора и назначение в приложении
Тайм-аут создания или завершенияСохранить неопределённый результат, сопоставить текущее состояние и полученные события до решения о повторе

Проверьте полный сценарий поддержки

В согласованном тестовом диалоге проверьте соединение и завершение, просроченную ссылку, отказ в доступе к микрофону, двойное нажатие, конфликт аккаунта и потерянный HTTP-ответ. Убедитесь, что повторная доставка событий не создаёт дубли задач, а полные ссылки не попадают в журналы. Это проверки для приёмки вашей интеграции, а не результаты испытаний, заявленные в статье.

Можно автоматически обзвонить список номеров?

Нет. Этот процесс требует conversation_id выбранного аккаунта и нажатия Start call человеком в браузере.

Можно принимать входящие звонки через эту интеграцию?

В текущей бете — нет. call.incoming зарезервирован; наличие в каталоге событий не открывает входящие звонки. Групповые звонки, запись, транскрибация, SIP/PBX и голосовые ИИ-агенты также не входят в эту бету.

С чего начать команде?

Если доступ ещё не открыт, подайте заявку технической поддержке, указав ID рабочего пространства и предполагаемый сценарий поддержки. Не отправляйте API-ключ или приватную ссылку. После включения доступа проверьте один выбранный диалог по справочнику создания звонка и затем добавляйте действие в рабочий процесс поддержки.

UnifyPort API

Превратите интеграцию сообщений в стабильный продуктовый pipeline.

Начните с отправки через единый API, затем возвращайте входящие сообщения в бизнес-систему стандартными событиями.