REST API АТС позволяет реализовать интеграцию с CRM-системами, которых нет в МаркетПлейсе. Реализует следующие бизнес задачи:
- обработка входящих вызовов и перевод на ответственных сотрудников;
- сохранение истории вызовов по клиентам;
- предоставление возможности прослушать ранее совершенные вызовы;
- поднятие анкеты клиента;
- совершение исходящих вызовов из CRM-системы;
- управление статусами пользователей АТС.
Для корректной работы интеграцию необходимо выполнить в двухстороннем формате. В случае использования web_hook’а, его адрес должен быть статичным. Обмен происходит по протоколу HTTP и HTTPS.
Настройка первичных параметров выполняется в интерфейсе АТС, в разделе Пользовательская интеграция.
Содержание интеграции
- Интеграция с CRM
Авторизация
Все запросы между АТС и CRM выполняются с использованием ключей, указанных в параметрах интеграции. АТС отправляет запросы к CRM с API-ключом CRM. CRM отправляет запрос к АТС с API-ключом АТС. Ключи передаются в заголовках запроса в поле Authorization со значением вида «Bearer Значение ключа».
Ниже в примерах используются переменные:
- crm_apikey — токен для доступа к методам CRM;
- pbx_apikey — токен для доступа к методам АТС.
Запрос от АТС к CRM
Тестирование URL
В процессе настройки, необходимо проверить доступность URL, указанного в интеграции. Для этого АТС отправляет запрос:POST {{crm_webhook}} Content-Type: application/json { «action»: «test», «obj»: «UserCRM», «action_id»: «123», «params»: {}}
Тестирование проходит успешно при ответе следующего вида:{ «action»: «test», «obj»: «UserCRM», «code»: 200, «body»: { «success»: true}}
Получение списка пользователей CRM
Для корректной работы интеграции необходимо реализовать запрос на получение списка пользователей от CRM. Работа интеграции невозможна без установки сопоставления пользователей АТС с пользователями CRM.POST {{crm_webhook}} Content-Type: application/json Authorization: Bearer {{crm_apikey}} { «action»: «get_users», «obj»: «UserCRM», «action_id»: «123», «params»: {}}
Пример ответа на запрос:{ «action»: «get_users», «obj»: «UserCRM», «code»: 200, «body»:[{«id»: «1», «name»: «Менеджер Рита»},{«id»: «2», «name»: «Менеджер Иван»}]}
Поиск ответственного сотрудника
Для обработки входящих запросов и закрепления вызова за ответственным сотрудником необходимо реализовать механизм поиска по номеру телефона. Поиск осуществляется по формату E164 без кода страны. К примеру +74951343060 преобразуется в 4951343060. В случае, если в параметрах маршрутизации разрешен перевод на ответственного, будет выполнен поиск среди сопоставленных пользователей CRM и АТС. Если абонент в АТС найден и он зарегистрирован, будет выполнен перевод.POST {{crm_webhook}} Content-Type: application/json Authorization: Bearer {{crm_apikey}} { «action»: «get_contact», «obj»: «UserCRM», «action_id»: «123», «params»: { «phone»: «4951343060» «e164_phone»: «74951343060» }}
Пример ответа на запрос:{ «obj»: «UserCRM», «action»: «get_contact», «code»: 200, «list»: [{ «name»: «Компания», «id»: 1, <- ID компании «type»: «company», «owner_id»: 1004 — номер телефона абонента или ID абонента из CRM },{ «name»: «Петров АА», «id»: 2, <- ID контакта «type»: «contact», «company_id»: «Компания», «company_name»: «1», «owner_id»: 1004 — номер телефона абонента или ID абонента из CRM },]}
События
В процессе работы АТС генерирует события. Например: о статусе вызова, статусе регистрации абонента и так далее. Эти события в виде запрос АТС отправляет CRM. На стороне CRM необходимо реализовать ответные действия. К примеру при входящем звонке открыть карточку клиента или отобразить статусы абонентов в CRM.
Если CRM-система поддерживает работу с websocket, то запросы можно отправлять сразу в клиентское приложение. Каждое сообщение, отправляемое по вебсокету проверяется на принадлежность события пользователю, подключенному к АТС.
Сообщение о регистрации абонента
Поля status и protocol соответствуют описанию объекта DomainUser{ ‘action’: ‘user_change’, ‘action_id’: ‘73913ae3-3051-41bc-8bee-c2c689072a96’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘user_uid’: ‘9022’, ‘crm_user’: ‘3’, ‘status’: 1, ‘protocol’: 0 }}
Сообщение о статусе сотрудника в коллценте
Поля base_status и extra_status соответствуют описанию объекта DomainAgent{ ‘action’: ‘agent_change’, ‘action_id’: ’69dba658-a137-468b-be78-96d1965064c8′, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘user_uid’: ‘1022’, ‘crm_user’: ‘2’, ‘base_status’: -1, ‘extra_status’: 1, ‘status_name’: ‘В работе’ }}
Сообщение о совершении вызова до ответа абонента
{ ‘action’: ‘call_ringing’, ‘action_id’: ‘1b9b58c9-1787-4f80-8e39-8d2affac90d3’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘call_id’: ‘7c97ce9e-97aa-4549-9a92-e0d63f570db8’, ‘session_id’: ‘93758923-1664-44eb-ae6c-59b27c53b805’, ‘crm_user’: ‘3’, ‘domain_user’: ‘9022’, ‘other_leg’: ‘+74952523060’, ‘rt_vars’: {‘gateway_number’: ‘74951343060’}, ‘direction’: 0}}
Сообщение о совершении вызова. Ответ абонента
{ ‘action’: ‘call_answer’, ‘action_id’: ‘1b9b58c9-1787-4f80-8e39-8d2affac90d3’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘call_id’: ‘7c97ce9e-97aa-4549-9a92-e0d63f570db8’, ‘session_id’: ‘93758923-1664-44eb-ae6c-59b27c53b805’, ‘crm_user’: ‘3’, ‘domain_user’: ‘9022’, ‘other_leg’: ‘+74952523060’, ‘rt_vars’: {‘gateway_number’: ‘74951343060’}, ‘direction’: 0}}
Сообщение о завершении вызова
{ ‘action’: ‘call_hangup’, ‘action_id’: ‘1b9b58c9-1787-4f80-8e39-8d2affac90d3’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘call_id’: ‘7c97ce9e-97aa-4549-9a92-e0d63f570db8’, ‘session_id’: ‘93758923-1664-44eb-ae6c-59b27c53b805’, ‘crm_user’: ‘3’, ‘domain_user’: ‘9022’, ‘other_leg’: ‘+74952523060’, ‘rt_vars’: {‘hangup_cause’: ‘NORMAL_CLEARING’}, ‘direction’: 0, ‘variable_answersec’: ‘9’}}
Сообщение о формировании CDR
{ ‘action’: ‘cdr_append’, ‘action_id’: ‘6ce285e6-c704-4857-a64a-510aa8c3cb40’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘id’: 112666, ‘uniqueid’: ‘5548f6ab-efab-4dd9-843b-c53f50a5506a’, ‘dt’: 1633333012.0, ‘src’: ‘9022’, ‘dst’: ‘+74952523060’, ‘duration’: 14, ‘billsec’: 3, ‘cc_queue_waiting_time’: 0, ‘lastapp’: ‘bind_digit_action’, ‘lastdata’: ‘office.runtel.org,~%5C*1,exec%3Aexecute_extension,*1%20XML%20office.runtel.org,a’, ‘rec_path’: ‘office.runtel.org/2021-10-04/’, ‘gateway’: ‘Test1’, ‘gateway_number’: ‘+74951343060’, ‘dial_status’: 0, ‘direction’: 0, ‘project_id’: 0, ‘project_name’: », ‘bridge_hangup_cause’: ‘NORMAL_CLEARING’, ‘hold_accum_seconds’: 0, ‘geo_ids’: ‘…’, ‘geo_names’: ‘…’, ‘link’: ‘https://pbx.runtel.org/get_file?file=onWde…’ }}
Сообщение о переводе вызова в hold
{ ‘action’: ‘call_held’, ‘action_id’: ‘4a9e14e4-cc87-4ec0-958d-4a36230ecd52’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘user_uid’: ‘9022’, ‘crm_user’: ‘3’, ‘call_id’: ‘d319b916-e987-4c0f-9b08-b915a72526fb’, ‘session_id’: ‘d319b916-e987-4c0f-9b08-b915a72526fb’, ‘other_leg’: ‘+79066800404’, ‘direction’: 0 }}
Сообщение о выходе из режими hold
{ ‘action’: ‘call_active’, ‘action_id’: ‘4a9e14e4-cc87-4ec0-958d-4a36230ecd52’, ‘obj’: ‘UserCRM’, ‘code’: 200, ‘notifies’: [], ‘body’: { ‘user_uid’: ‘9022’, ‘crm_user’: ‘3’, ‘call_id’: ‘d319b916-e987-4c0f-9b08-b915a72526fb’, ‘session_id’: ‘d319b916-e987-4c0f-9b08-b915a72526fb’, ‘other_leg’: ‘+79066800404’, ‘direction’: 0 }}
Запрос от CRM к АТС
Получение истории вызовов
Получение истории вызовов необходимо для отображения в карточке клиента. Возможна фильтрация по номеру телефона, направлению и дате совершения вызова.POST {{v2_host}}/integration/usercrm/ Content-Type: application/json Authorization: Bearer {{pbx_apikey}} { «action»: «get_cdr», «obj»: «UserCRM», «action_id»: «123», «sort»: {«dt»: «+»}, «limit»: 10, «offset»: 0, «params»: { «start_dt»: «1633074025», «end_dt»: «1633074725», «src_or_dst_list»: [«+74951343060», «+74952523060»]}}
Параметры отбора значений идентичны тем, что используется при получении истории вызовов в объекте ReportCallsHistory.
Совершение исходящего вызова
Если CRM-система позволяет интегрировать WEB-телефон, то обычно используется такое решение как более функциональное. Если используются учетные записи с протоколом SIP, для вызова из CRM необходимо реализовать инициализацию вызова. При отправке запроса вызов сначала поступает на пользователя и как только он отвечает, вызов совершается клиенту. Этот метод работает только для пользователей, которые добавлены в интеграцию.POST {{v2_host}}/integration/usercrm/ Content-Type: application/json Authorization: Bearer {{pbx_apikey}} { «action»: «make_call», «obj»: «UserCRM», «action_id»: «123», «params»: { «crm_user_id»: «user_crm_30», «dst»: «89066800404» }}
Установка вызова на удержание
Метод позволяет поставить вызов на удержание или снять с него.POST {{v2_host}}/integration/usercrm/ Content-Type: application/json Authorization: Bearer {{pbx_apikey}} { «action»: «switch_call_hold», «obj»: «UserCRM», «action_id»: «123», «params»: { «crm_user_id»: «user_crm_30», «call_id»: «725d2f5b-34e3-48df-96f4-8fa729da1098» }}
Параметры запроса
Name | Type | Description |
---|---|---|
crm_user_id | StringType | ID пользователя из CRM |
call_id | StringType | ID вызова |
Ответ на запросPOST {{v2_host}}/integration/usercrm/ Content-Type: application/json Authorization: Bearer {{pbx_apikey}} { «action»: «switch_call_hold», «obj»: «UserCRM», «action_id»: «123», «params»: { «crm_user_id»: «user_crm_30», «call_id»: «725d2f5b-34e3-48df-96f4-8fa729da1098» }}
Метод получения списка пользователей
Метод позволяет получить список пользователей, так как некоторые интеграции сохраняют списки пользователей на своей стороне.{ «action»: «get_domain_user_list», «obj»: «UserCRM», «params»: {}}
Ответ на запрос{ «action»: «get_domain_user_list», «action_id»: «999f1bf8-1032-467f-94ad-875dc72ec26a», «obj»: «UserCRM», «code»: 200, «notifies»: [], «body»: [{ «user_name»: «Иванов», «user_surname»: «», «uid»: «777», «id»: 3103, «proto»: 0 },{ «user_name»: «Петров», «user_surname»: «», «uid»: «1111», «id»: 1937, «proto»: 0 }]}
Пример получения событий по WebSocket
// Константы для подключения к веб-сокетуvar HOST = ‘{HOST}’ // Хост сервераvar API_KEY = ‘{API_KEY}’ // API ключ для аутентификацииvar CRM_USER_ID = ‘{USER_ID}’;// ID пользователя CRM// Запуск создания сокета с небольшой задержкой setTimeout(createSocket, 500);// Глобальные переменные для управления сокетомvar check_socket_timer,// Таймер для проверки состояния сокета proto, socket,// Объект веб-сокета socket_connect_trying = 0,// Счетчик попыток подключения last_call_id = null, not_matching_to_pbx_user = false// Флаг сопоставления пользователяvar self = this;/** * Генерирует уникальный идентификатор (GUID) * @returns {string} Сгенерированный GUID */function generateGUID(){return ‘xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx’.replace(/[xy]/g,function(c){let r = Math.random() * 16 | 0, v = c == ‘x’ ? r : (r & 0x3 | 0x8)return v.toString(16)})}/** * Создает WebSocket соединение */function createSocket(){// Установка соединения с WebSocket socket = new WebSocket(«wss://» + HOST + «/integration/usercrm/ws/»); window.api_socket = socket;// Запуск таймера проверки сокета, если он еще не запущенif(!check_socket_timer){ check_socket_timer = setInterval(check_socket, 60000);}// Обработчик закрытия соединения socket.onclose = function(event){if(socket_connect_trying < 5){ reconnect_socket();// Попытка переподключения}else{ proto = null; console.log(‘Сокет закрыт’);}};// Обработчик входящих сообщений socket.onmessage = function(event){ console.log(event)var data = JSON.parse(event.data);// Обработка различных типов сообщенийswitch(data.action){case ‘connect’: // Аутентификация при установлении соединенияvar auth_data = { obj: ‘WebSocketMember’, action: ‘auth’, action_id: generateGUID(), params: {apikey: API_KEY, crm_user_id: CRM_USER_ID}}; socket.send(JSON.stringify(auth_data));break;case ‘crm_auth’: // Обработка результатов аутентификацииif(data.code == 200){ socket_connect_trying = 0; not_matching_to_pbx_user = false; console.log(data.body);}if(data.code == 407){// пользователь не сопоставлен socket_connect_trying = 5; not_matching_to_pbx_user = true;}else{ reconnect_socket();}break;// Обработчики для различных событий звонкаcase ‘make_call’: case ‘ringing’: case ‘answer’: case ‘hangup’: if(data.code == 200){ console.log(data.body);}break;}};// Обработчик ошибок сокета socket.onerror = function(error){ reconnect_socket();};};/** * Попытка переподключения сокета */function reconnect_socket(){ socket_connect_trying++;if(socket_connect_trying < 5){ setTimeout(function(){ check_socket();}, 1000);}else{ socket.close();}};/** * Проверка состояния сокета и его восстановление */function check_socket(){// Пересоздание сокета, если он закрыт и пользователь сопоставленif((!socket || socket.readyState == 3) && !not_matching_to_pbx_user){ createSocket();}};
В данном примере:
- Реализуется WebSocket соединение с возможностью автоматического переподключения
- Применяется механизм аутентификации через API ключ
- Обрабатываются различные события, связанные с телефонией (звонки, рингование и т.д.)
- Происходит ограничение количества попыток переподключения (до 5 раз)
- Логируются основные события в консоль (в этом месте необходимо реализовать свою логику)
Модуль WebSocket соединения
Создает WebSocket соединение с сервером.
Параметры: Нет
Возвращает: Объект WebSocket
Пример использования:// Инициализация WebSocket соединения setTimeout(createSocket, 500);
Особенности:
- Автоматическая аутентификация
- Повторное подключение при потере соединения
- Обработка различных событий звонков
Константы:
HOST
— адрес сервераAPI_KEY
— ключ APICRM_USER_ID
— идентификатор пользователя CRM
Основные методы
Генерирует уникальный идентификатор (GUID).Результат:
Случайный GUIDТип результата:
string
Пример:let guid = generateGUID();// Пример результата: «f47ac10b-58cc-4372-a567-0e02b2c3d479»reconnect_socket()
Обработчик переподключения WebSocket.
Особенности:
- Количество попыток ограничено 5
- Интервал между попытками 1 секунда
Обработка событий
Модуль поддерживает следующие события:
connect
— первичное подключениеcrm_auth
— аутентификация в CRMmake_call
— исходящий звонокringing
— входящий звонокanswer
— ответ на звонокhangup
— завершение звонка
Пример обработки события:socket.onmessage = function(event){var data = JSON.parse(event.data);switch(data.action){case ‘ringing’: console.log(‘Входящий звонок’, data.body);break;}};
Конфигурация
Перед использованием необходимо установить:
HOST
— адрес сервераAPI_KEY
— ключ доступаCRM_USER_ID
— идентификатор пользователя
Пример настройки:var HOST = ‘example.websocket.com’;var API_KEY = ‘your_secret_api_key’;var CRM_USER_ID = ‘12345’;
Обработка ошибок
- При 5 неудачных попытках соединение закрывается
- Поддерживается автоматическое восстановление соединения
- В случае несопоставления пользователя (код 407) подключение блокируется
Предупреждение
Убедитесь в корректности API ключа и идентификатора пользователя.