Як налаштувати UniTalk
Підключіть UniTalk до ConnectiveOne через вбудований preset UniTalk: завершені дзвінки з'являтимуться в архіві дзвінків із записом, призначеним оператором і полями в картці клієнта.
Ця інструкція — повний гайд для імплементації: preset, webhook, два способи призначення оператора (з готовими JSON), поля клієнта, smoke-тест і типові проблеми.
Передумови
- Доступ адміністратора до кабінету UniTalk
- Доступ до налаштувань бота в ConnectiveOne (Налаштування → Боти → Телефонія)
- Email операторів у ConnectiveOne збігаються з email у UniTalk (для автопризначення)
- Для шляху A (рекомендовано): таблиця SIP-лінія (line у UniTalk) ↔ email оператора
- Для шляху B (опційно): API-ключ UniTalk (Інтеграція → API)
Коли знадобиться
- UniTalk — провайдер телефонії
- Потрібно швидко підключити інтеграцію без ручного маппінгу полів webhook
- Завершені дзвінки мають з'являтися в Операторській панелі з записом і оператором
Два способи призначити оператора
Шлях A — operator_mapping |
Шлях B — action_telephony_staff_enrich |
|
|---|---|---|
| Суть | Статична таблиця SIP → email у Advanced Config | Запит до UniTalk API /users/list, матч по полю line |
| Зовнішні API | Ні | Так (кеш обовʼязковий через ліміти UniTalk) |
| Коли обирати | Відомий стабільний список ліній (типовий кейс First / більшості клієнтів) | Лінії часто змінюються, таблицю не хочете вести вручну |
| Що вказати в каналі | Блок operator_mapping у JSON |
API Key + Action збагачення webhook = action_telephony_staff_enrich |
Якщо спрацював
operator_mapping, ConnectiveOne не викликає enrich — зайвих запитів до API немає.
action_telephony_staff_enrich — універсальний internal action (будь-який HTTP-список співробітників через json_config). Нижче — готова конфігурація саме під UniTalk.
Крок 1: Відкрити налаштування каналу
- Налаштування → Боти
- Оберіть бот
- Вкладка Телефонія
- Створіть новий канал або відкрийте існуючий
Заповніть мінімум:
| Поле каналу | Значення |
|---|---|
| Назва | Наприклад UniTalk |
| Активний | Увімкнено |
| Код країни за замовчуванням | Наприклад UA / 380 (як у вашому інстансі) |
Після першого збереження зʼявляться Webhook URL і токен.
Крок 2: Застосувати preset UniTalk
- У блоці Розширена конфігурація (JSON) оберіть у списку провайдера UniTalk
- Натисніть Застосувати пресет
- Натисніть Зберегти і скопіюйте Webhook URL (з
?token=...)
Preset додає:
event_detection— лише подіяCALL_ENDfield_mapping/status_mapping/direction_mappingclient_field_mapping— UTM, джерело, коментар → картка клієнта- записи з
call.link
Повний JSON preset (без operator_mapping) також є в репозиторії: apps/engine/modules/extra/telephony/presets/unitalk.json.
Крок 3: Webhook у кабінеті UniTalk
- Кабінет UniTalk → Обробка подій
- Додайте обробник «Надіслати вебхук»
- Привʼяжіть лише до події
CALL_END(не надсилайтеCALL_NEWтощо)
| Поле в UniTalk | Значення |
|---|---|
| Метод | POST |
| URL | Повний Webhook URL з ConnectiveOne, наприклад: https://<ваш-домен>/kw/telephony/webhook/<id_каналу>?token=<webhook_token> |
| Тіло | Стандартний JSON |
Токен тільки в URL (
?token=...). Шлях/kw/telephony/webhook/...не змінюйте.
Приклад тіла CALL_END (вхідний)
{
"event": "CALL_END",
"call": {
"id": "sample-call-id",
"from": "380501234567",
"to": "9578",
"direction": "in",
"state": "ANSWER",
"secondsFullTime": 120,
"secondsTalk": 90,
"date": "2026-09-02T12:00:00.000Z",
"link": "https://example.test/recording.mp3",
"utmSource": "google",
"utmCampaign": "brand",
"source": "ads",
"comment": "Коментар до дзвінка"
}
}
| Поле UniTalk | Після preset у ConnectiveOne |
|---|---|
event |
Має бути CALL_END, інакше відповідь 200 ignored |
call.id |
ID дзвінка (ідемпотентність — повтор не створить дубль) |
call.from / call.to |
Номер клієнта або SIP оператора (залежить від direction) |
call.direction |
in / out |
call.state |
ANSWER → прийнятий; NOANSWER, BUSY, … → пропущений |
call.link |
Запис розмови |
call.utmSource, utmCampaign, source, comment |
Картка клієнта (client_field_mapping) |
Напрямок і SIP оператора:
| Напрямок | Номер клієнта | SIP-лінія оператора (ключ у operator_mapping / lookup enrich) |
|---|---|---|
in (вхідний) |
call.from |
call.to |
out (вихідний) |
call.to |
call.from |
У формі каналу ConnectiveOne: формат webhook = JSON.
Крок 4A: Призначення оператора через operator_mapping (рекомендовано)
Після Застосувати пресет додайте в той самий JSON блок operator_mapping (на одному рівні з event_detection, field_mapping, …) і натисніть Валідувати JSON / Зберегти.
Приклад фрагмента
"operator_mapping": {
"source": {
"in": "callee_number",
"out": "caller_number"
},
"map": {
"9578": "[email protected]",
"201": "[email protected]"
}
}
Повний приклад Advanced Config (preset + mapping)
Скопіюйте, підставте свої SIP → email, збережіть:
{
"event_detection": {
"mode": "event_field",
"event_field": "event",
"call_ended_values": ["CALL_END"]
},
"field_mapping": {
"call_id": "call.id",
"caller_number": "call.from",
"callee_number": "call.to",
"status": "call.state",
"duration": "call.secondsFullTime",
"talk_duration": "call.secondsTalk",
"recording_url": "call.link",
"direction": "call.direction",
"date": "call.date",
"utm_source": "call.utmSource",
"utm_campaign": "call.utmCampaign",
"call_source": "call.source"
},
"status_mapping": {
"ANSWER": "answered",
"NOANSWER": "missed",
"BUSY": "missed",
"CANCEL": "missed",
"AUTOCANCEL": "missed",
"UNREACHABLE": "missed",
"VOICE_MAIL": "missed",
"FAIL": "failed",
"BLOCKED": "failed",
"AUDIO_ERR": "failed"
},
"direction_mapping": {
"in": "in",
"out": "out",
"inbound": "in",
"outbound": "out"
},
"recordings": {
"enabled": true,
"download": false
},
"transcription": {
"enabled": false,
"source": "provider"
},
"client_field_mapping": {
"utm_source": "call.utmSource",
"utm_campaign": "call.utmCampaign",
"call_source": "call.source",
"last_call_comment": "call.comment"
},
"operator_mapping": {
"source": {
"in": "callee_number",
"out": "caller_number"
},
"map": {
"9578": "[email protected]",
"201": "[email protected]"
}
}
}
Правила:
- Ключі в
map— сирі SIP-рядки як у UniTalk ("9578"), до нормалізації E.164 (не+3809578). - Email у ConnectiveOne = email оператора (активний користувач Операторської панелі).
- У UniTalk у кожного оператора заповнена внутрішня лінія (
line). - Поле Action збагачення webhook можна залишити порожнім.
Крок 4B: Динамічне призначення через action_telephony_staff_enrich (опційно)
Використовуйте, якщо не ведете operator_mapping (або як запасний шлях, коли лінії в таблиці немає).
4B.1 Поля каналу
| Поле | Значення |
|---|---|
| API Key | API-ключ UniTalk (Інтеграція → API) |
| API Base URL (якщо є в формі) | https://api.unitalk.cloud/api |
| Action збагачення webhook | action_telephony_staff_enrich |
Ключ — секрет. Не публікуйте в чатах / тікетах.
4B.2 Параметри action (json_config)
Action уже є в продукті (internal). Якщо на інстансі використовуєте Action Jail-обгортку — ті самі параметри в JSON config action.
Готовий приклад під UniTalk:
{
"api_url": "https://api.unitalk.cloud/api/users/list",
"http_method": "POST",
"auth_header_name": "Authorization",
"auth_scheme": "raw",
"request_body": {},
"response_items_path": "",
"match_field": "line",
"lookup_source": {
"in": "callee_number",
"out": "caller_number"
},
"email_field": "email",
"name_fields": ["firstName", "lastName"],
"cache_ttl_seconds": 300,
"timeout_ms": 8000
}
| Параметр | Навіщо |
|---|---|
match_field: line |
Внутрішня SIP-лінія АТС у відповіді /users/list (не плутати з phone — мобільний, часто null) |
lookup_source |
Звідки брати SIP з нормалізованого дзвінка: in → callee_number, out → caller_number |
cache_ttl_seconds |
Кеш списку співробітників (ліміти UniTalk: ~15 req/s) |
api_key |
Можна в json_config або лише в полі каналу API Key (канал має пріоритет як джерело секрету, якщо в params немає ключа) |
Якщо відповідь API — масив у корені, response_items_path залиште порожнім "". Якщо обгортка на кшталт { "data": [ … ] } — вкажіть "data".
4B.3 Що має повернути UniTalk /users/list (фрагмент)
[
{
"id": 1,
"email": "[email protected]",
"firstName": "Іван",
"lastName": "Петренко",
"line": "9578",
"phone": null,
"role": "OPERATOR"
}
]
ConnectiveOne шукає запис з line = SIP з дзвінка і пише manager_email / manager_name у збагачення → призначення за email.
Деталі загального механізму enrich: Налаштувати збагачення webhook.
Технічний шаблон для впровадників: docs/developer/engine/modules/telephony/action_telephony_staff_enrich.template.md.
Крок 5: Поля картки клієнта
Preset уже містить client_field_mapping:
Ключ у extra_data |
Шлях у webhook |
|---|---|
utm_source |
call.utmSource |
utm_campaign |
call.utmCampaign |
call_source |
call.source |
last_call_comment |
call.comment |
Щоб поля відображались у картці клієнта, додайте відповідні кастомні поля в Налаштування інстансу (схема extra_data). Сам merge у клієнта робить Telephony без Action Jail.
Крок 6: Збереження та перевірка (smoke)
- Зберегти канал (активний).
- У формі каналу — Тест webhook або curl нижче.
- Зробіть тестовий вхідний і вихідний дзвінок у UniTalk.
- Операторська панель → Закриті звернення: діалог
telephony, запис (якщо єcall.link), оператор.
Приклад curl (локальний / stage smoke)
Підставте URL каналу і токен. Тіло — як у кроці 3; для шляху A змініть "to" / email у operator_mapping під реальну лінію.
curl -X POST 'https://<ваш-домен>/kw/telephony/webhook/<channel_id>?token=<webhook_token>' \
-H 'Content-Type: application/json' \
-d '{
"event": "CALL_END",
"call": {
"id": "smoke-unitalk-001",
"from": "380501234567",
"to": "9578",
"direction": "in",
"state": "ANSWER",
"secondsFullTime": 60,
"secondsTalk": 45,
"date": "2026-09-02T12:00:00.000Z",
"link": "https://example.test/recording.mp3",
"utmSource": "google",
"utmCampaign": "brand",
"source": "ads",
"comment": "Smoke test"
}
}'
Очікувано: HTTP 200, у тілі є dialogue_id.
Повтор з тим самим call.id → 200, «already processed», без дубля діалогу.
Подія не CALL_END (наприклад "event": "CALL_NEW") → 200 ignored, діалог не створюється.
Чекліст приймання
| # | Перевірка | Очікування |
|---|---|---|
| 1 | CALL_END |
Діалог створено, канал telephony, завершений |
| 2 | Не-CALL_END |
200 ignored, без діалогу |
| 3 | Є call.link |
Запис доступний у діалозі |
| 4 | Вхідний / вихідний | Клієнт за правильним номером |
| 5 | SIP in і out | Оператор призначений (mapping або enrich) |
| 6 | UTM / comment | Значення в картці клієнта (якщо поля в Instance Settings) |
| 7 | Той самий call.id двічі |
Без дубля |
| 8 | Шлях B | Кеш / без rate-limit блокування; або шлях A без enrich |
Типові проблеми
| Симптом | Що перевірити |
|---|---|
| 200 ignored на кожному webhook | У тілі є "event": "CALL_END"; застосовано preset UniTalk (event_detection) |
| Діалог є, оператора немає | Email у map / UniTalk збігається з користувачем C1; SIP як "9578", не E.164; для out — лінія в call.from |
| Enrich не викликається | Заповнений operator_mapping з матчем — це очікувано (skip enrich) |
| Enrich error / немає email | match_field = line; у /users/list у оператора заповнений line; API Key на каналі |
| Дубль діалогів | Різні call.id від UniTalk; ідемпотентність лише за одним id |
| UTM не видно в UI | Merge в extra_data є — додайте відображення кастомних полів у Instance Settings |
| 403 / unauthorized webhook | Токен у URL = токен каналу |
Що включає preset UniTalk
- Детекція лише
CALL_END - Маппінг полів, статусів, напрямку
- Записи з
call.link client_field_mapping(UTM, джерело, коментар)
operator_mapping і webhook enrich не входять у кнопку preset — додаються вручну (кроки 4A / 4B).
Обмеження
- Лише завершені дзвінки (
CALL_END), без realtime під час розмови - Click-to-call з ConnectiveOne — поза цим обсягом
- Транскрипт / аналітика UniTalk — окремий scope