Кастомна інтеграція потрібна, коли ви хочете підключити до CallAIder власну телефонну систему або внутрішній API, який не входить до стандартних конекторів.
Цей матеріал побудований у правильній послідовності для впровадження:
- Спочатку розбираємо, навіщо це потрібно бізнесу і команді.
- Потім йдемо у детальну технічну реалізацію API за контрактом.
- І тільки після цього показуємо, як підключити все в інтерфейсі платформи.
Якщо ви технічний лід, CTO, інтегратор або backend-розробник, цей гайд можна використовувати як практичний чеклист запуску.
Чому варто робити кастомну інтеграцію і яку цінність вона дає
Багато команд бачать інтеграцію лише як «щоб діалоги підтягувалися». Насправді кастомна інтеграція вирішує значно ширші задачі.
1) Єдине джерело правди для аналітики
Ви самі визначаєте, які саме дзвінки вважаються валідними для аналізу, які атрибути передавати і як називати властивості. Це прибирає розрив між даними у вашій телефонії/CRM і даними в аналітиці CallAIder.
Результат:
- менше суперечок про «чому тут інші цифри»;
- прозорий аудит даних;
- контроль якості на вашому боці.
2) Повніші дані про кожен дзвінок
Через properties ви можете передавати те, чого часто немає у стандартних інтеграціях:
- відділ або черга;
- сегмент клієнта;
- місто/регіон;
- бізнес-статус (наприклад, «питання вирішено»);
- внутрішні скоринги якості або пріоритети.
Ці дані стають основою для точної вибірки, порівняння команд і побудови релевантних зрізів.
3) Точна фільтрація під реальний бізнес-процес
Завдяки propertyFilters ви можете не просто «тягнути всі дзвінки», а відбирати їх за бізнес-логікою:
- тільки підтримка і тільки VIP;
- тільки вхідні звернення з певних міст;
- тільки дзвінки з оцінкою якості в заданому діапазоні.
Це особливо важливо, коли різні команди мають різні KPI і не повинні аналізувати один і той самий масив розмов.
4) Безпека та керованість інтеграції
Механізм X-Secret-Key дозволяє контролювати авторизований доступ до endpoint-ів. Ви зберігаєте повний контроль над тим, які запити приймаються, і можете додати власні правила безпеки: rate limiting, IP allowlist, журналювання, ротацію ключів.
5) Масштабування без ручних операцій
Коли процес налаштований правильно, команда не витрачає час на ручний експорт/імпорт дзвінків. Система стабільно постачає дані, а аналітика працює у фоновому режимі.
6) Готовність до складних сценаріїв
Кастомний API дає гнучкість для сценаріїв, де стандартний конектор майже завжди обмежений:
- кілька АТС або кілька джерел даних;
- внутрішні правила нормалізації номерів і операторів;
- додаткові поля з CRM або ERP;
- особливі вимоги до зберігання й доступу до записів.
Коли саме варто обирати Custom Telephony
Кастомна інтеграція найкраще підходить, якщо:
- у вас власна телефонія або нестандартний провайдер;
- потрібні додаткові властивості дзвінків для фільтрації;
- важливо контролювати контракт даних і якість імпорту;
- у вас кілька відділів/команд з різними правилами обробки;
- потрібна предиктивна або сегментна аналітика на базі внутрішніх бізнес-ознак.
Як виглядає потік даних end-to-end
У реальному потоці це працює так:
- Ви підключаєте інтеграцію в кабінеті.
- CallAIder перевіряє доступність через
/health. - Для списку операторів запитує
/contacts. - Для імпорту діалогів запитує
/callsіз часовим діапазоном, напрямком, операторами таpropertyFilters. - Для відтворення/аналізу аудіо звертається до
/calls/:id/recording. - Якщо реалізовано
/properties/schema, у майстрі команди з’являється крок налаштування властивостей.
Що підготувати до початку розробки API
Перед імплементацією узгодьте всередині команди:
- базовий URL API (публічний і доступний ззовні);
- секретний ключ для
X-Secret-Key; - мапінг полів між джерелом дзвінків і контрактом CallAIder;
- формат і словник ключів у
properties; - політику доступу до записів дзвінків (постійні або тимчасові URL);
- логування і моніторинг помилок інтеграції.
Реалізація API: повна технічна специфікація і практичні деталі
Нижче - центральна частина гайду. Саме її потрібно реалізувати на вашому бекенді.
Загальні вимоги до всіх endpoint-ів
- Приймайте і віддавайте JSON.
- Перевіряйте
X-Secret-Keyна кожному endpoint. - Повертайте коректні HTTP-коди (
200,401,404,500). - Для помилок використовуйте єдину структуру відповіді.
- Працюйте тільки з завершеними дзвінками.
Рекомендований формат помилки:
{
"status": "error",
"message": "Опис помилки"
}
Автентифікація через X-Secret-Key
У кожному запиті від CallAIder буде:
X-Secret-Key: <ваш_секретний_ключ>
Що обов’язково реалізувати:
- перевірку заголовка до бізнес-логіки;
- повернення
401 Unauthorized, якщо ключ відсутній або не збігся; - журналювання відхилених запитів (без виводу секрета в лог).
Мінімальний middleware-приклад:
function auth(req, res, next) {
if (req.headers['x-secret-key'] !== process.env.CALLAIDER_SECRET) {
return res.status(401).json({ status: 'error', message: 'Unauthorized' });
}
next();
}
Endpoint 1: GET /health
Призначення: перевірка доступності API при підключенні інтеграції.
Запит:
GET {your_api_url}/health
X-Secret-Key: <secret>
Відповідь 200 OK:
{ "status": "success" }
Практична порада: цей endpoint має бути максимально легким і швидким, без важких операцій.
Endpoint 2: GET /contacts
Призначення: повернути операторів (співробітників), доступних для команди.
Запит:
GET {your_api_url}/contacts
X-Secret-Key: <secret>
Відповідь 200 OK:
{
"contacts": [
{
"id": "101",
"phone": "+380971234567",
"name": "Іван Петренко",
"department": "Продажі"
}
]
}
Поля:
id(string, обов’язково) - стабільний унікальний ID оператора;phone(string, обов’язково) - номер оператора;name(string, обов’язково) - ім’я оператора;department(string, опційно) - назва відділу.
Рекомендації:
- не змінюйте
idодного й того ж оператора між синхронізаціями; - віддавайте актуальний склад команди;
- якщо є і зовнішній, і внутрішній номер - визначте сталу політику, який саме передаєте у
phone.
Endpoint 3: POST /calls
Призначення: повернути список завершених дзвінків за період і фільтрами.
Запит:
POST {your_api_url}/calls
Content-Type: application/json
X-Secret-Key: <secret>
Приклад тіла запиту:
{
"startTime": 1709500000,
"stopTime": 1709586400,
"direction": "incoming",
"operators": ["101", "102"],
"propertyFilters": {
"Відділ": ["продажі", "підтримка"],
"Оцінка якості": {
"mode": "all",
"conditions": [
{ "operator": "gt", "value": 2 },
{ "operator": "lt", "value": 8 }
]
}
}
}
Розбір полів запиту:
startTime(number, обов’язково) - початок періоду (Unix timestamp, секунди);stopTime(number, обов’язково) - кінець періоду (Unix timestamp, секунди);direction(string, опційно) -incomingабоoutgoing;operators(string[], опційно) - фільтр за ID операторів;propertyFilters(object, опційно) - додаткова фільтрація.
Формати propertyFilters
Підтримуються три основні формати:
- Точний збіг значення:
{ "Місто клієнта": "Київ" }
- Один із кількох варіантів:
{ "Відділ": ["продажі", "підтримка"] }
- Числові умови з логікою
allабоany:
{
"Оцінка якості": {
"mode": "any",
"conditions": [
{ "operator": "gt", "value": 10 },
{ "operator": "lt", "value": 5 }
]
}
}
Оператори для числових умов:
eq- дорівнює;ne- не дорівнює;gt- більше;gte- більше або дорівнює;lt- менше;lte- менше або дорівнює.
Якщо mode не передано, використовується all.
Як правильно реалізувати фільтрацію
Є два допустимі режими роботи:
- Рекомендований: фільтрувати одразу у вашому API за всіма вхідними параметрами, включно з
propertyFilters. - Спрощений: ігнорувати
propertyFiltersна вашому боці, але обов’язково повертатиproperties, щоб CallAIder застосував постфільтрацію після імпорту.
Ключове уточнення зі специфікації: реалізація фільтрації
propertyFiltersсаме на вашому API не є обов’язковою. Якщо ваш backend не підтримує ці фільтри, інтеграція все одно коректно працює: ви можете повернути всі завершені дзвінки в межахstartTime,stopTime,direction,operators, а платформа CallAIder виконає додаткову фільтрацію на своїй стороні за об’єктомproperties.
Щоб такий fallback-режим працював правильно, дотримуйтесь правил:
- передавайте
propertiesу кожному дзвінку, де потрібна додаткова фільтрація; - якщо
/properties/schemaреалізовано, ключіpropertiesмають збігатися зkeyзі схеми; - якщо
/properties/schemaне реалізовано, ключі можуть бути довільними, але значення мають бути простих типів:string,number,boolean.
Відповідь POST /calls
Приклад 200 OK:
{
"calls": [
{
"id": "call-abc-123",
"clientNumber": "+380501234567",
"clientName": "Client One",
"direction": "incoming",
"duration": 185,
"startTime": 1709586000,
"endTime": 1709586185,
"operatorId": "101",
"operatorName": "John Carter",
"operatorNumber": "7545",
"whoHungUp": "client",
"properties": {
"Відділ": "підтримка",
"Місто клієнта": "Львів",
"Питання вирішено": true,
"Оцінка якості": 72
}
}
]
}
Поля дзвінка:
id(string, обов’язково) - унікальний ID дзвінка;clientNumber(string, опційно) - номер клієнта;clientName(string, опційно) - ім’я клієнта;direction(string, обов’язково) -incomingабоoutgoing;duration(number, обов’язково) - тривалість у секундах;startTime(number, обов’язково) - початок дзвінка (Unix timestamp, секунди);endTime(number, опційно) - завершення дзвінка (Unix timestamp, секунди);operatorId(string, обов’язково) - ID оператора;operatorName(string, обов’язково) - ім’я оператора;operatorNumber(string, обов’язково) - номер оператора;whoHungUp(string, опційно) -operator,clientабоsystem;properties(object, опційно) - додаткові властивості дзвінка.
Критично важливо:
- повертайте лише завершені дзвінки;
- не віддавайте активні або пропущені виклики;
- якщо реалізовано
/properties/schema, ключі уpropertiesмають збігатися зkeyзі схеми.
Додаткове важливе уточнення:
- поле
propertiesзагалом не є обов’язковим для базового імпорту завершених діалогів; - але якщо ви хочете використовувати додаткову фільтрацію (під час імпорту команди або у фільтрах діалогів),
propertiesпотрібно передавати; - саме
propertiesвикористовуються платформою як джерело додаткових ознак для фільтрації.
Endpoint 4: GET /properties/schema (необов’язковий; потрібен для гнучкого налаштування імпорту)
Цей endpoint не є обов’язковим для роботи інтеграції. Його призначення вузьке і конкретне: дати можливість гнучко налаштовувати імпорт діалогів на платформу через додаткові фільтри під час створення команди.
Тобто /properties/schema потрібен не для базового імпорту як такого, а для керованого UI-кроку «Властивості» у майстрі команди.
Запит:
GET {your_api_url}/properties/schema
X-Secret-Key: <secret>
Приклад відповіді:
{
"properties": [
{ "key": "Відділ", "type": "enum", "values": ["продажі", "підтримка", "утримання"] },
{ "key": "Сегмент клієнта", "type": "enum", "values": ["стандарт", "vip"] },
{ "key": "Місто клієнта", "type": "string" },
{ "key": "Питання вирішено", "type": "boolean" },
{ "key": "Оцінка якості", "type": "number" }
]
}
Поля схеми:
key(string, обов’язково) - назва властивості;type(string, обов’язково) -string,number,booleanабоenum;values(array, опційно) - допустимі значення.
Якщо endpoint не реалізований:
- можна повернути
{ "properties": [] }, або 404 Not Found.
Інтеграція продовжить працювати, але платформа пропустить крок гнучкого налаштування властивостей у майстрі команди.
Важливо розуміти різницю між schema і properties:
/properties/schemaописує, які фільтри показати користувачу під час налаштування команди;calls[].propertiesмістить фактичні значення властивостей конкретного дзвінка;calls[].propertiesвикористовуються платформою для додаткової фільтрації під час імпорту та також для додаткової фільтрації у списку діалогів.
Endpoint 5: GET /calls/:id/recording
Призначення: повернути посилання на запис конкретного дзвінка.
Запит:
GET {your_api_url}/calls/123/recording
X-Secret-Key: <secret>
Відповідь 200 OK:
{
"url": "https://your-storage.com/recordings/call-abc-123.mp3",
"filename": "call_recording_call-abc-123.mp3",
"mimeType": "audio/mpeg"
}
Поля:
url(string, обов’язково) - пряме посилання на файл;filename(string, опційно) - назва файлу;mimeType(string, опційно) - MIME-тип (audio/mpeg,audio/wavтощо).
Якщо запис недоступний, поверніть 404 Not Found.
Рекомендація: якщо URL тимчасовий, забезпечте строк життя не менше 30 хвилин.
Коди відповідей і єдина обробка помилок
Використовуйте передбачувану матрицю:
200- успіх;401- невалідний/відсутній секретний ключ;404- ресурс не знайдено;500- внутрішня помилка.
Практичні рекомендації для production
Окрім базового контракту, варто додати:
- ідемпотентність за
call.id, щоб уникати дублювань; - логування запитів/відповідей з кореляційним ID;
- таймаути і retry до внутрішніх джерел;
- моніторинг частоти помилок по кожному endpoint;
- алерти на різке падіння кількості імпортованих дзвінків.
Підключення інтеграції в платформі CallAIder (після реалізації API)
Коли API уже реалізовано і перевірено, переходьте до підключення в інтерфейсі.
Крок 1. Створіть підключення Custom API
- Відкрийте розділ Інтеграції.
- Знайдіть картку Кастомне API.
- Натисніть Підключити.

У формі підключення заповніть:
- Назва підключення;
- API URL;
- Secret Key.

Після збереження система перевірить endpoint /health.
Крок 2. Створіть команду на цій інтеграції
Далі треба створити команду, яка визначає:
- операторів для імпорту;
- правило аналітики;
- властивості для додаткового відбору дзвінків.
Покроковий майстер описаний окремо тут:
Крок 3. Налаштуйте властивості в майстрі команди
Якщо ви реалізували /properties/schema, у майстрі з’явиться крок Властивості, де можна задати додаткові умови вибірки.

Це і є прямий зв’язок між вашим API-контрактом та бізнес-логікою імпорту на платформі.
Фільтрація діалогів за додатковими параметрами після імпорту
Після того як дзвінки почали імпортуватись:
- Відкрийте розділ Діалоги.
- Натисніть кнопку фільтрів у верхній панелі.

У правій панелі будуть доступні:
- стандартні фільтри (напрямок, оператор, клієнт, тривалість);
- блок Властивості дзвінка з полями, які ви передали в
properties.

Приклади практичного використання:
- показати лише дзвінки відділу підтримки;
- відфільтрувати звернення з певних міст;
- відібрати тільки дзвінки з високим скорингом;
- швидко порівнювати сегменти клієнтів у межах однієї команди.
Розширений troubleshooting: типові помилки і як діяти
401 Unauthorized
Що означає: не пройдена перевірка X-Secret-Key.
Що перевірити:
- правильність ключа в налаштуваннях інтеграції;
- правильність ключа на сервері;
- чи не змінює заголовки ваш reverse proxy.
404 на /health, /contacts або /calls/:id/recording
Що означає: неправильний шлях або endpoint реально не існує на production.
Що перевірити:
- базовий URL інтеграції;
- роутинг на сервері;
- доступність API з зовнішньої мережі.
Порожній імпорт у /calls
Що означає: дзвінки не проходять ваші або платформні фільтри.
Що перевірити:
- коректність
startTime/stopTime(секунди, а не мілісекунди); - коректність значень
direction; - відповідність
operatorIdзначенням ізcontacts.id; - чи не занадто жорсткі
propertyFilters.
Властивості не відображаються у UI
Що означає: проблема у схемі або в ключах properties.
Що перевірити:
- чи реалізовано
/properties/schema; - чи збігаються
keyзі схеми і ключі вcalls[].properties; - чи не повертаються
null/складні об’єкти замість простих типів.
Запис не відкривається
Що означає: URL недоступний або протермінований.
Що перевірити:
- доступність URL без внутрішньої VPN;
- TTL тимчасового посилання;
- правильний
mimeType.
Фінальний чеклист перед запуском
- Реалізовані endpoint-и:
/health,/contacts,/calls,/calls/:id/recording. - Усі endpoint-и захищені перевіркою
X-Secret-Key. POST /callsповертає тільки завершені дзвінки.propertiesпередаються стабільно і в очікуваних типах.- За можливості реалізовано
/properties/schema. - Ключі у схемі та у
propertiesповністю узгоджені. - Створена команда і перевірений імпорт у розділі Діалоги.
- Перевірена робота фільтрів за додатковими параметрами.
Коли всі пункти пройдені, інтеграція вважається production-ready: дані завантажуються стабільно, діалоги правильно сегментуються, а аналітика дає коректну картину по команді.