Интеграция с IP-телефонией

Система из коробки включает в себя интеграции с различными провайдерами IP-телефонии. Если нужной именно вам интеграции не нашлось, вы можете воспользоваться данным API для создания собственной интеграции. Для этого вам нужно создать пользовательский модуль и реализовать несколько функций в скриптах модуля на языке TypeScript.

Встроенные и пользовательские модули интеграции с IP-телефонией по функционалу принципиально ничем не отличаются. Вашему модулю будут доступны следующие возможности:

  • инициация исходящего звонка из системы через контекстное меню поля типа Телефон;
  • отображение карточки звонка с краткой информацией по клиенту и кнопками управления вызовом, когда пользователь системы принимает входящий или совершает исходящий звонок;
  • открытие карточки сводной информации по клиенту;
  • автоматическое создание и сохранение элемента приложения, если звонок был пропущен, а номера нет в базе;
  • регистрация пропущенных звонков;
  • сохранение в ленту объекта сообщения о входящем или исходящем звонке. Если разговор состоялся, то к сообщению добавляется ссылка на запись звонка. Её можно воспроизвести в интерфейсе системы, а также оставить комментарий, содержащий, к примеру, резюме звонка;
  • автоматическое создание элемента приложения Звонок в разделе Телефония для каждого входящего и исходящего звонка;
  • сопоставление учётных записей пользователей IP-телефонии и пользователей системы для маршрутизации и корректного отражения информации об операторе, принявшем или осуществившем звонок.

Ограничения

Прежде чем реализовывать модуль интеграции, обратите внимание на следующие ограничения API:

  1. На стороне системы не осуществляется маршрутизация звонка во избежание конфликтов с настройками маршрутизации на стороне телефонии и на стороне системы. Такую возможность предоставляет практически каждый провайдер: после того, как звонок маршрутизирован на сотрудника или группу, входящий вызов отображается в системе для указанных пользователей.
  2. На текущий момент обработка событий телефонии производится путем доставки сообщений на определенную HTTP-ссылку (Webhook). Если провайдер телефонии не предоставляет возможность указать ссылку для доставки сообщений, то необходимо создать промежуточный сервис, который преобразует данные провайдера телефонии в запрос на сервер системы. Для этого вы можете создать переносимый сервис в модуле.
  3. Для записей звонков сохраняется только ссылка на файл. Обычно сами записи хранятся у провайдера телефонии. Он предоставляет только ссылку. Вам следует обратить внимание на политику хранения файлов на серверах провайдера телефонии. Файлы могут быть доступны ограниченное время.

Реализация

Для создания модуля интеграции вам необходимо в скриптах пользовательского модуля реализовать следующие функции:

// Проверить соединение с телефонией. Вызывается при нажатии кнопки Проверить соединение на странице модуля
// Возвращает статус проверки соединения, который отобразится для пользователя на странице модуля
async function VoipTestConnection(): Promise<VoipTestConnectionResult> { }

// Обработать запрос от провайдера IP-телефонии. Вызывается, когда происходит запрос на вебхук модуля
// В параметре `request` содержится информация об HTTP-запросе, в том числе HTTP-заголовки и содержимое тела запроса
// Функция возвращает результат обработки запроса, на основании которого система будет показывать уведомления
// о входящем звонке, сохранять запись звонка и т. д.
async function VoipParseWebhookRequest(request: FetchRequest): Promise<VoipWebhookParseResult> { }

// Получить список пользователей со стороны провайдера IP-телефонии
// Вызывается при сопоставлении пользователей телефонии с пользователями системы после нажатия кнопки Настроить на странице модуля
// Возвращает список пользователей провайдера IP-телефонии
async function VoipGetMembers(): Promise<VoipMember[]> { }

// Сгенерировать исходящий звонок. Функция вызывается, когда пользователь системы нажимает кнопку звонка
// в контекстном меню поля типа Телефон или кнопку Перезвонить в карточке звонка. В параметре
// `srcPhone` указывается номер звонящего пользователя, в `dstPhone` — номер, на который нужно позвонить
async function VoipGenerateCall(srcPhone: string, dstPhone: string): Promise<void> { }

// Получить ссылку на запись звонка. Функция вызывается, когда пользователь системы проигрывает запись звонка из
// ленты элемента приложения или при сохранении ссылки на запись звонка в контекст элемента приложения Звонок
// раздела Телефония. В параметре `callData` содержатся данные, которые были указаны при сохранении
// информации о записи звонка из функции `VoipParseWebhookRequest`. Функция должна возвращать ссылку на файл
async function VoipGetCallLink(callData: any): Promise<string> { }

// Вызывается автоматически при изменении ссылки на вебхук (например, при обновлении токена)
// В параметре `webhookUrl` указывается абсолютная ссылка на вебхук модуля интеграции. Функция не обязательна к реализации
async function VoipOnWebhookUpdated(webhookUrl: string): Promise<void> { }

После реализации этих функций и сохранения скрипта на странице модуля вы найдете новый раздел под названием Настройки телефонии. В этом разделе будет указана ссылка на вебхук — при отправке данных на эту ссылку будет вызываться функция VoipParseWebhookRequest из скрипта. В этой функции вы должны обработать запрос и вернуть из неё экземпляр VoipWebhookParseResult, на основании которого система отобразит уведомления о входящем звонке или сохранит информацию о записи звонка. Саму ссылку на вебхук вам необходимо указать в настройках вашего провайдера телефонии. Ссылка обрабатывает HTTP-запросы типа GET и POST. Также в ссылке должен присутствовать обязательный параметр token.

Рекомендуем вам ознакомиться со статьей справки «Интеграция с IP-телефонией через пользовательский модуль». Внутри статьи вы найдете заготовку модуля и пример реального использования API на основе интеграции с IP-телефонией Гравител.

Реализация поддержки кнопок в карточке звонка

При получении входящего звонка или совершении исходящего звонка у пользователя системы в правом нижнем углу появляется карточка с информацией о текущем звонке. В зависимости от состояния звонка, в этой карточке могут отображаться различные кнопки: Принять звонок, Завершить звонок, Переназначить и так далее. Чтобы эти кнопки отображались, реализуйте следующие функции в пользовательском модуле телефонии:

// Принять звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Принять звонок
// После этого начинают передаваться голосовые данные между оператором и клиентом
// В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок
async function VoipAcceptCall(srcPhone: string, dstPhone: string): Promise<void> { }

// Завершить звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Завершить звонок
// Звонок между оператором и клиентом завершается
// В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок
async function VoipHangupCall(srcPhone: string, dstPhone: string): Promise<void> { }

// Переназначить звонок. Функция вызывается, когда в карточке звонка пользователь системы нажимает кнопку Переназначить
// Звонок текущего оператора завершается, и клиент соединяется с другим оператором
// В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок,
// `redirectTo` — внутренний номер оператора, на которого переназначается звонок
async function VoipRedirectCall(srcPhone: string, dstPhone: string, redirectTo: string): Promise<void> { }

// Поставить звонок на ожидание. Функция вызывается, когда в карточке звонка пользователь системы
// нажимает кнопку Поставить на ожидание. Передача голосовых данных между оператором и клиентом прекращается без завершения звонка
// В параметре `srcPhone` указывается номер телефона звонящего, в `dstPhone` — номер, на который производится звонок,
// `hold` — значение `true`. Оно указывает, что нужно поставить звонок на ожидание, иначе — снять с ожидания
async function VoipHoldCall(srcPhone: string, dstPhone: string, hold: boolean): Promise<void> { }

Если в пользовательском модуле телефонии функция не реализована, соответствующая кнопка не будет отображаться в карточке звонка.