External Conversation Bridge - це спосіб підключити текстового асистента CallAIder до вашого власного каналу спілкування через API. Каналом може бути Telegram-бот, WhatsApp, Instagram, Viber, CRM-чат, чат у мобільному застосунку, власний операторський інтерфейс або будь-яка інша система, яка вміє приймати повідомлення від користувача і робити HTTP-запити на бекенд.
Головна ідея проста: CallAIder не забирає у вас токени месенджерів і не керує доставкою повідомлень у ваш канал. Ваша програма отримує повідомлення від користувача, надсилає текст і контекст у CallAIder, отримує відповідь асистента і сама доставляє її назад користувачу.
Ця інструкція написана для двох аудиторій:
- клієнтів платформи, які хочуть зрозуміти, що саме потрібно налаштувати в кабінеті CallAIder;
- розробників клієнтських інтеграцій, які будуть реалізовувати bridge server, payload, retry, handoff і доставку відповідей у зовнішній канал.
Коли використовувати External Conversation Bridge
Зовнішній API-канал варто використовувати, якщо у вас вже є власна точка контакту з клієнтом і ви хочете підключити до неї AI-асистента без перенесення каналу всередину CallAIder.
Типові сценарії:
- ваш Telegram-бот вже працює у production і має власні команди, меню, правила груп і forum topics;
- CRM вже приймає повідомлення з сайту, месенджерів або форми підтримки;
- оператори працюють у власному інтерфейсі, а AI має відповідати тільки до моменту handoff;
- потрібно підключити асистента до каналу, для якого в CallAIder немає готового native-конектора;
- ви не хочете передавати CallAIder токени Telegram, WhatsApp, Instagram, Viber або іншої зовнішньої платформи.
У цьому режимі CallAIder працює як текстовий асистент для вашого каналу: приймає вхідний текст, підтримує контекст діалогу, за потреби обробляє вкладення, генерує текстову відповідь і повертає її вашій програмі.
Що залишається на вашій стороні
External Conversation Bridge не є готовим адаптером конкретного месенджера. Це важливо врахувати ще до початку розробки.
На стороні клієнтської програми залишаються:
- отримання повідомлень із зовнішнього каналу;
- зберігання токенів Telegram, WhatsApp, CRM або іншої системи;
- webhook-и, polling, group topics, routing і логіка каналу;
- перетворення вхідного повідомлення у payload CallAIder;
- відправлення відповідей CallAIder назад користувачу;
- операторський handoff;
- retry, таймаути, черги і rate limiting;
- фільтрація повідомлень, на які AI не має відповідати.
CallAIder відповідає за:
- перевірку API-ключа;
- пошук асистента за
assistantId; - перевірку, що зовнішній API-канал увімкнений;
- створення або відновлення діалогу асистента;
- збереження історії повідомлень для контексту;
- підтримку контексту за
externalConversationId; - генерацію відповіді асистента;
- блокування відповіді, якщо діалог переведено у
pausedабоblocked; - автоматичний старт нового звернення після
closed, коли користувач знову пише у той самий діалог; - базовий захист від повторної обробки останнього
messageId.
Загальна схема роботи
У production-сценарії між вашим каналом і CallAIder зазвичай стоїть ваш backend або bridge server. Саме він зберігає секрети і робить server-to-server запити.
Користувач у зовнішньому каналі
|
v
Ваш backend / bridge server
|
| POST /v1/assistants/:assistantId/external-conversations/messages
| Authorization: Bearer cld_...
v
Публічний API CallAIder
|
v
Асистент CallAIder
|
v
JSON response: messages[]
|
v
Ваш backend доставляє messages[] у Telegram, CRM, сайт або інший канал
Не викликайте цей API напряму з браузера кінцевого користувача або з мобільного застосунку, якщо ключ можна буде витягнути з клієнтського коду. API-ключ має жити тільки на серверній стороні.
Що потрібно підготувати перед інтеграцією
Перед тим як писати код, переконайтесь, що у вас є:
- Активний асистент у CallAIder.
- Доступ до налаштувань цього асистента.
- Увімкнений зовнішній API-канал в асистенті.
assistantId, який у кабінеті показується якІдентифікатор бота в API.- API-ключ компанії у форматі
cld_.... - Backend-сервіс, який буде приймати повідомлення з вашого каналу і викликати API CallAIder.
- Base URL публічного API для вашого підключення, наприклад
https://api.callaider.ai/v1.
Якщо у вашому тарифі або договорі доступ до API не активований, зверніться до менеджера або підтримки CallAIder. Ключ може існувати в кабінеті, але API-запити мають проходити перевірку доступності відповідної можливості для компанії.
Крок 1. Відкрийте вкладку каналів асистента
У кабінеті CallAIder відкрийте потрібного асистента для редагування. Далі перейдіть у вкладку Канали.
Шлях у кабінеті:
Асистенти -> Редагувати -> Канали

На цій сторінці можуть бути різні канали, наприклад Telegram і зовнішній API-канал. Для інтеграції через External Conversation Bridge потрібен саме блок Зовнішній API-канал.
Крок 2. Увімкніть зовнішній API-канал
У блоці Зовнішній API-канал увімкніть перемикач Увімкнути зовнішній API-канал і збережіть налаштування.

Після збереження перевірте два моменти:
- статус блоку має бути активним;
- у полі
Ідентифікатор бота в APIмає відображатися ID асистента.
Цей ID використовується в URL API як assistantId.
Приклад:
POST /v1/assistants/17/external-conversations/messages
У цьому прикладі 17 - це значення з поля Ідентифікатор бота в API.
Base URL публічного API не налаштовується у цьому блоці. Його потрібно взяти з документації або від команди CallAIder для вашого підключення. У прикладах нижче використовується умовний URL https://api.example.com/v1; у реальній інтеграції замініть його на актуальний.
Крок 3. Створіть API-ключ для доступу до API
API-ключ потрібен, щоб CallAIder міг перевірити, що запит надходить від вашої компанії. Це не Telegram token, не preview token віджета і не JWT користувача. Це окремий server-to-server ключ компанії.
У кабінеті відкрийте розділ Інтеграції і знайдіть блок API ключі. Натисніть Створити ключ.

Рекомендований порядок:
- Відкрийте
Інтеграції. - У блоці
API ключінатиснітьСтворити ключ. - Вкажіть зрозумілу назву, наприклад
external-bridge-productionабоcrm-chat-staging. - Скопіюйте ключ у форматі
cld_.... - Збережіть ключ у секретах вашого backend-сервісу.
- Не додавайте ключ у frontend-код, мобільний застосунок, відкриті логи або публічний репозиторій.
Зазвичай після створення ключ у списку показується замасковано. Тому скопіюйте повне значення одразу під час створення і передайте його розробнику через безпечний канал.
Приклад змінних середовища на стороні вашого backend:
CALLAIDER_API_BASE_URL="https://api.callaider.ai/v1"
CALLAIDER_ASSISTANT_ID="17"
CALLAIDER_API_KEY="cld_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
У кожному HTTP-запиті ключ передається в заголовку Authorization:
Authorization: Bearer cld_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
OpenAPI-специфікація публічного API доступна в репозиторії NBM-Labs/callaider_openapi. Її зручно використовувати для перевірки контрактів, генерації клієнтів і синхронізації backend-розробки з актуальними endpoint-ами.
Endpoint для повідомлень
Основний endpoint приймає вхідне повідомлення користувача і синхронно повертає відповідь асистента.
POST /v1/assistants/:assistantId/external-conversations/messages
Authorization: Bearer <API_KEY>
Content-Type: application/json
Повний URL складається з base URL, ID асистента і шляху endpoint:
https://api.example.com/v1/assistants/17/external-conversations/messages
Endpoint працює синхронно:
- приймає повідомлення;
- знаходить або створює діалог за вашим
externalConversationId; - відновлює контекст цього діалогу;
- запускає асистента;
- чекає відповідь;
- повертає
messages[].
Через це ваш HTTP client має мати достатній timeout. Для production-інтеграцій рекомендовано закладати не менше 30-60 секунд.
Мінімальний payload
Найменший коректний запит містить стабільний ID діалогу, ID користувача у вашому каналі, ID повідомлення і текст.
{
"externalConversationId": "tg:123456",
"externalUserId": "123456",
"messageId": "789",
"text": "Добрий день"
}
Приклад curl:
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"externalConversationId": "tg:123456",
"externalUserId": "123456",
"messageId": "789",
"text": "Добрий день"
}'
Поля payload
| Поле | Тип | Обов’язкове | Для чого потрібно |
|---|---|---|---|
externalConversationId | string | Так | Стабільний ID діалогу на вашій стороні. За ним CallAIder відновлює контекст. |
externalUserId | string | Ні | ID користувача у вашому зовнішньому каналі. Корисний для аудиту і пошуку. |
messageId | string | Ні, але рекомендовано | ID вхідного повідомлення. Потрібен для захисту від повторної обробки при retry. |
text | string | Так, якщо немає attachments | Текст, який буде передано асистенту. |
attachments | array | Ні | До 5 вкладень типу remote_url. |
metadata | object | Ні | Додатковий JSON-контекст для аудиту або інтеграції. |
Практично завжди варто передавати messageId, навіть якщо поле не є строго обов’язковим. Без нього вашій інтеграції буде складніше безпечно повторювати запит після timeout або мережевої помилки.
Як вибрати externalConversationId
externalConversationId - це ключ діалогу. Якщо він однаковий, CallAIder вважає повідомлення частиною одного контексту. Якщо він інший, буде створено інший діалог.
Вибирайте ID залежно від того, як у вашому каналі має працювати пам’ять асистента.
| Сценарій | Приклад externalConversationId | Поведінка |
|---|---|---|
| Один діалог на Telegram-користувача | tg:user:123456 | Асистент пам’ятає контекст конкретного користувача. |
| Один діалог на Telegram-чат | tg:chat:-1001234567890 | Контекст спільний для чату. |
| Окремий діалог на forum topic | tg:-1001234567890:topic:42 | Кожна тема має власний контекст. |
| Один діалог на CRM-тикет | crm:ticket:ABC-1001 | Контекст прив’язаний до звернення в CRM. |
| Один діалог на чат сайту | site:conversation:9f3a | Контекст прив’язаний до звернення або чату на сайті. |
Різні асистенти можуть використовувати однакові externalConversationId без конфлікту, тому що контекст прив’язується до комбінації:
assistantId + externalConversationId
Не змінюйте externalConversationId випадково між повідомленнями одного діалогу. Якщо кожне повідомлення матиме новий ID, асистент не зможе відновити контекст попередньої розмови.
Як використовувати messageId і retry
messageId має бути стабільним ID вхідного повідомлення у вашому каналі. Якщо ви повторюєте той самий запит через timeout, мережеву помилку або 5xx, використовуйте той самий messageId.
Правильна поведінка:
- користувач надіслав повідомлення
789; - ваш bridge server відправив його в CallAIder з
messageId: "789"; - запит завис або відповідь не дійшла;
- bridge server повторив запит з тим самим
messageId: "789"; - якщо CallAIder вже обробив це повідомлення, відповідь міститиме
duplicate: trueі порожнійmessages[].
Не генеруйте новий messageId для retry одного й того самого повідомлення. Інакше CallAIder сприйме retry як нове повідомлення користувача.
Захист від дублікатів розрахований на типовий retry останнього повідомлення у конкретному діалозі. Для високонавантажених інтеграцій все одно варто мати власну ідемпотентність або чергу на стороні клієнтського bridge server.
Повний payload з metadata і вкладенням
Коли потрібно передати додатковий контекст або файл, використовуйте metadata і attachments.
{
"externalConversationId": "crm:ticket:ABC-1001",
"externalUserId": "customer:555",
"messageId": "crm-msg-9002",
"text": "Перевір, будь ласка, цей рахунок",
"attachments": [
{
"type": "remote_url",
"url": "https://client.example.com/downloads/invoice-1001.pdf",
"mimeType": "application/pdf",
"filename": "invoice-1001.pdf",
"sizeBytes": 245760,
"sha256": "f2c7d0b4f4e8f1b7a12a4d34a9f6b7c0d1e2f3a4567890abcdef1234567890ab"
}
],
"metadata": {
"source": "crm",
"ticketId": "ABC-1001",
"customerPlan": "business",
"operatorQueue": "support-l2"
}
}
metadata не керує логікою каналу автоматично, але допомагає з аудитом, трасуванням і майбутньою інтеграційною логікою. Передавайте туди тільки технічний і бізнес-контекст, який справді потрібен для вашого сценарію.
Attachments через remote_url
External Conversation Bridge підтримує inbound-вкладення у форматі remote_url. Це означає, що ваша програма не передає файл напряму в JSON. Замість цього вона передає короткоживучий HTTPS URL, за яким backend CallAIder може завантажити файл під час обробки повідомлення.
Формат одного attachment:
{
"type": "remote_url",
"url": "https://client.example.com/files/photo.jpg",
"mimeType": "image/jpeg",
"filename": "photo.jpg",
"sizeBytes": 734003,
"sha256": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
}
Поля attachment:
| Поле | Тип | Обов’язкове | Опис |
|---|---|---|---|
type | string | Так | Поки підтримується тільки remote_url. |
url | string | Так | Публічний HTTPS URL, доступний backend-сервісу CallAIder під час обробки. |
mimeType | string | Ні, але рекомендовано | Очікуваний MIME type. Особливо корисно для signed URL, які повертають application/octet-stream. |
filename | string | Ні | Назва файла, яка буде відображатися в історії діалогу та під час обробки. |
sizeBytes | number | Ні | Очікуваний розмір файла. Якщо він більший за ліміт, запит буде відхилено до скачування. |
sha256 | string | Ні | SHA-256 checksum. Якщо передано, CallAIder перевірить файл після скачування. |
Підтримувані типи файлів:
- зображення:
image/png,image/jpeg,image/webp,image/heic,image/heif,image/gif; - відео:
video/mp4; - аудіо:
audio/wav,audio/x-wav,audio/wave,audio/mp3,audio/mpeg,audio/aiff,audio/x-aiff,audio/aac,audio/ogg,audio/flac; - документи:
application/pdf.
Поточні обмеження:
- до 5 вкладень в одному повідомленні;
- до 20 MB на один файл;
- тільки
https; - без username/password у URL;
- hostname має резолвитись у публічну IP-адресу;
- private, localhost, link-local, multicast і службові IP-діапазони блокуються;
- redirect-и обмежені і перевіряються повторно;
Content-Lengthі фактичний розмір перевіряються;- після скачування файл готується до аналізу асистентом без повторного звернення до вашого URL.
Не передавайте довгоживучі URL з приватними секретами у query string. Краще використовуйте short-lived signed URL або власний одноразовий download endpoint, який живе достатньо довго для обробки одного повідомлення.
Успішна відповідь на повідомлення
Якщо повідомлення оброблено, API повертає ok: true, поточний статус діалогу і масив messages.
{
"ok": true,
"status": "active",
"messages": [
{
"text": "Добрий день! Чим можу допомогти?"
}
]
}
messages - це масив текстових відповідей, які ваша програма має доставити у свій канал у тому самому порядку. У більшості сценаріїв там буде один елемент, але контракт одразу зроблений масивом, щоб у майбутньому підтримувати кілька відповідей без зміни формату.
CallAIder не доставляє ці повідомлення в Telegram, CRM або месенджер самостійно. Доставка завжди на вашій стороні.
Відповідь на повторне повідомлення
Якщо messageId збігається з останнім обробленим inbound message у цій conversation, повторна генерація не запускається.
{
"ok": true,
"status": "active",
"duplicate": true,
"messages": []
}
Для вашої програми це означає: нічого не доставляти користувачу. Така відповідь є нормальною для retry, якщо попередній запит вже був оброблений.
Відповідь, коли AI поставлено на паузу
Якщо conversation має статус paused або blocked, асистент не відповідає на нові повідомлення.
{
"ok": true,
"status": "paused",
"skipped": true,
"messages": []
}
Це корисно для операторського handoff. Наприклад, оператор взяв діалог у роботу, ваша програма перевела conversation у paused, а всі наступні повідомлення користувача продовжують надходити в систему, але AI не втручається.
Закритий діалог і нове звернення
Статус closed означає, що поточне звернення завершене. Коли ви переводите діалог у closed, CallAIder завершує поточний контекст звернення.
Якщо користувач пізніше напише у той самий externalConversationId, вам не потрібно створювати новий діалог вручну. Просто надішліть звичайний POST /messages з новим messageId. CallAIder автоматично почне нове звернення і поверне діалог у active.
{
"ok": true,
"status": "active",
"reopened": true,
"messages": [
{
"text": "Добрий день! Чим можу допомогти?"
}
]
}
Так можна використовувати один і той самий externalConversationId для довгострокового каналу, наприклад Telegram-чату, але розділяти окремі звернення через статус closed.
Endpoint для зміни стану діалогу
Другий endpoint керує станом діалогу. Він потрібен для handoff, повернення діалогу асистенту і закриття звернення.
POST /v1/assistants/:assistantId/external-conversations/:externalConversationId/state
Authorization: Bearer <API_KEY>
Content-Type: application/json
Приклад URL:
https://api.example.com/v1/assistants/17/external-conversations/tg:123456/state
Якщо externalConversationId містить символи, які мають спеціальне значення в URL, закодуйте його через URL encoding.
Підтримувані статуси
| Вхідне значення | Збережений статус | Поведінка |
|---|---|---|
active | active | Асистент може відповідати. |
ai_active | active | Alias для active. |
paused | paused | Асистент не відповідає. |
handoff | paused | Alias для paused, зручно для операторського сценарію. |
human_handoff | paused | Alias для paused. |
closed | closed | Поточне звернення закривається. Наступне inbound message відкриє нове звернення. |
blocked | blocked | Асистент не відповідає. |
Поставити діалог на паузу
Коли оператор бере діалог у роботу, переведіть conversation у paused або handoff.
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/tg:123456/state" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"status": "handoff",
"metadata": {
"reason": "operator_joined",
"operatorId": "op-17"
}
}'
Очікувана відповідь:
{
"ok": true,
"status": "paused"
}
Після цього нові POST /messages для цього діалогу повертатимуть skipped: true і порожній messages[].
Повернути діалог асистенту
Якщо оператор завершив свою частину, але звернення ще не закрите, поверніть conversation у active.
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/tg:123456/state" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"status": "active",
"metadata": {
"reason": "operator_left"
}
}'
Наступне повідомлення користувача знову буде оброблено асистентом у межах поточного контексту.
Закрити звернення
Коли питання клієнта вирішене, переведіть conversation у closed.
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/tg:123456/state" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"status": "closed",
"metadata": {
"reason": "operator_closed_issue"
}
}'
Наступне повідомлення у той самий externalConversationId автоматично почне нове звернення. Це зручно для CRM-тикетів, підтримки в месенджерах і повторних звернень клієнта в той самий чат.
Приклад клієнтської інтеграції на TypeScript
Нижче спрощений приклад backend-коду. Він показує тільки взаємодію з CallAIder. Функція sendTextToExternalChannel має бути реалізована у вашій системі для конкретного каналу.
type BridgeMessage = {
externalConversationId: string;
externalUserId?: string;
messageId?: string;
text: string;
metadata?: Record<string, unknown>;
};
type CallaiderBridgeResponse = {
ok: boolean;
status: string;
duplicate?: boolean;
skipped?: boolean;
reopened?: boolean;
messages: Array<{ text: string }>;
};
const baseUrl = process.env.CALLAIDER_API_BASE_URL;
const assistantId = process.env.CALLAIDER_ASSISTANT_ID;
const apiKey = process.env.CALLAIDER_API_KEY;
async function askCallaider(message: BridgeMessage): Promise<CallaiderBridgeResponse> {
const response = await fetch(
`${baseUrl}/assistants/${assistantId}/external-conversations/messages`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify(message),
},
);
if (!response.ok) {
const text = await response.text();
throw new Error(`CallAIder bridge failed: ${response.status} ${text}`);
}
return response.json() as Promise<CallaiderBridgeResponse>;
}
async function handleIncomingText(input: {
chatId: string;
userId: string;
messageId: string;
text: string;
}) {
const result = await askCallaider({
externalConversationId: `tg:chat:${input.chatId}`,
externalUserId: input.userId,
messageId: input.messageId,
text: input.text,
metadata: {
source: 'telegram',
chatId: input.chatId,
},
});
if (result.duplicate || result.skipped) {
return;
}
for (const message of result.messages) {
const text = message.text.trim();
if (text) {
await sendTextToExternalChannel(input.chatId, text);
}
}
}
Для production-коду додайте:
- HTTP timeout;
- retry тільки з тим самим
messageId; - логування request id або власного correlation id;
- чергу або lock на один
externalConversationId, якщо ваш канал очікує послідовний діалог; - обробку помилок доставки відповіді у зовнішній канал.
Приклад для Telegram forum topic
Якщо ви використовуєте Telegram-групу з forum topics, сформуйте externalConversationId так, щоб різні теми не змішували контекст.
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"externalConversationId": "tg:-1001234567890:topic:42",
"externalUserId": "123456",
"messageId": "789",
"text": "Потрібна допомога з оплатою",
"metadata": {
"chatId": "-1001234567890",
"messageThreadId": 42,
"username": "client_user"
}
}'
У такій схемі topic 42 матиме окремий контекст від topic 43, навіть якщо це одна Telegram-група.
Приклад для CRM-чату
Для CRM часто найзручніше прив’язувати conversation до тикета або звернення.
curl -X POST \
"https://api.example.com/v1/assistants/17/external-conversations/messages" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <API_KEY>" \
-d '{
"externalConversationId": "crm:ticket:ABC-1001",
"externalUserId": "customer:555",
"messageId": "crm-msg-9001",
"text": "Я хочу змінити дату запису",
"metadata": {
"crm": "custom",
"ticketId": "ABC-1001",
"priority": "normal"
}
}'
Коли оператор закрив тикет, викличте /state зі статусом closed. Якщо клієнт створить новий тикет, використовуйте новий externalConversationId. Якщо клієнт напише у той самий довгий чат, але ви хочете почати нове звернення, також можна закрити старий діалог і дозволити CallAIder почати новий контекст при наступному повідомленні.
Типовий handoff-сценарій
Операторський handoff зазвичай виглядає так:
- Користувач пише у Telegram, WhatsApp, CRM або чат сайту.
- Ваш backend надсилає повідомлення у
POST /messages. - CallAIder повертає
messages[]. - Ваш backend доставляє відповідь користувачу.
- Оператор вирішує взяти діалог.
- Ваш backend викликає
/stateзі статусомhandoffабоpaused. - Нові повідомлення користувача можуть продовжувати надходити у CallAIder, але API повертатиме
skipped: true. - Якщо оператор повертає діалог AI, backend викликає
/stateзі статусомactive. - Якщо оператор закрив питання, backend викликає
/stateзі статусомclosed. - Коли користувач напише знову, звичайний
POST /messagesавтоматично почне нове звернення.
Цей підхід дозволяє не змішувати відповіді AI і людини. Головне - щоб саме ваша система була джерелом правди щодо того, хто зараз веде діалог.
Таймаути, черги і паралельні повідомлення
/messages повертає відповідь тільки після генерації асистента, тому інтеграція має бути готова до довших HTTP-запитів.
Рекомендації:
- ставте timeout 30-60 секунд або більше, якщо ваш сценарій допускає довші відповіді;
- повторюйте запит тільки з тим самим
messageId; - не запускайте багато паралельних запитів для одного
externalConversationId, якщо порядок відповідей важливий; - використовуйте queue або lock на рівні conversation;
- логування робіть так, щоб можна було знайти
externalConversationId,messageId, HTTP status і час обробки; - якщо відповідь CallAIder отримана, але доставка у зовнішній канал не вдалася, повторюйте саме доставку у канал, а не генерацію нової відповіді без потреби.
External Conversation Bridge повертає відповідь синхронно у HTTP response. Окремий callback URL у цьому сценарії не потрібен.
Помилки і діагностика
Типові HTTP-статуси:
| HTTP status | Що перевірити |
|---|---|
400 | Payload неповний або некоректний: немає externalConversationId, немає text при відсутніх attachments, передано некоректний status. |
403 | Асистент або зовнішній API-канал вимкнений, або компанія не має доступу до потрібної API-можливості. |
404 | Для цього асистента не знайдено увімкнену конфігурацію external bridge в межах компанії API-ключа. |
500 | Неочікувана серверна помилка. Запит можна повторити з тим самим messageId. |
Якщо запит не проходить авторизацію, перевірте:
- чи передано заголовок
Authorization: Bearer <API_KEY>; - чи не обрізаний API-ключ;
- чи ключ активний у кабінеті;
- чи ключ належить тій самій компанії, що й асистент;
- чи доступ до API активований для вашої компанії.
Якщо помилка сталася під час обробки повідомлення асистентом, API може повернути стандартний текст помилки як звичайний елемент у messages[]. У такому випадку ваша програма доставляє його користувачу так само, як інші відповіді асистента, або обробляє за власними правилами підтримки.
Безпека
Для безпечної інтеграції дотримуйтесь таких правил:
- використовуйте тільки HTTPS;
- зберігайте API-ключ тільки на backend-стороні;
- не викликайте External Conversation Bridge напряму з браузера користувача;
- не додавайте API-ключ у mobile app, frontend bundle або публічний репозиторій;
- не логувати API-ключ у відкриті логи;
- не передавайте токени Telegram, WhatsApp, CRM або інших каналів у CallAIder;
- обмежте доступ до вашого bridge server;
- додайте rate limiting на reverse proxy або на рівні backend;
- для attachments використовуйте короткоживучі URL;
- для production-інтеграцій ведіть аудит запитів без секретів.
API-ключ і токен зовнішнього каналу - це різні секрети. API-ключ дозволяє вашому backend звертатися до CallAIder. Токен Telegram, WhatsApp або CRM дозволяє вашому backend працювати з відповідним каналом. Не змішуйте їх і не передавайте токени каналів у payload CallAIder.
Чеклист перевірки інтеграції
Перед запуском у production пройдіть повний тестовий сценарій:
- Увімкніть
Зовнішній API-каналу вкладціКанали. - Скопіюйте
Ідентифікатор бота в API. - Створіть API-ключ у розділі
Інтеграції. - Збережіть
CALLAIDER_API_BASE_URL,CALLAIDER_ASSISTANT_IDіCALLAIDER_API_KEYу backend-секретах. - Надішліть тестовий
POST /messagesз унікальнимexternalConversationId. - Переконайтесь, що відповідь містить
ok: true,status: activeі непорожнійmessages[]. - Повторіть той самий запит з тим самим
messageId. - Переконайтесь, що відповідь містить
duplicate: trueіmessages: []. - Викличте
/stateзі статусомpausedабоhandoff. - Надішліть нове повідомлення у той самий
externalConversationId. - Переконайтесь, що відповідь містить
skipped: trueіmessages: []. - Викличте
/stateзі статусомactive. - Надішліть нове повідомлення і перевірте, що асистент знову відповідає.
- Викличте
/stateзі статусомclosed. - Надішліть нове повідомлення з тим самим
externalConversationIdі новимmessageId. - Переконайтесь, що відповідь містить
status: active,reopened: trueі новіmessages[]. - Перевірте доставку відповіді у ваш реальний канал.
- Перевірте retry, timeout і логування на стороні вашого bridge server.
Короткий підсумок
External Conversation Bridge підходить для інтеграцій, де клієнтська система сама володіє каналом, токенами, операторською логікою і доставкою повідомлень. CallAIder у цій схемі відповідає за AI-частину: контекст діалогу, обробку повідомлення і генерацію відповіді.
Для запуску потрібні три базові речі: увімкнений зовнішній API-канал в асистенті, assistantId з кабінету і API-ключ компанії. Далі ваш backend надсилає повідомлення в /messages, доставляє messages[] у свій канал і за потреби керує станом діалогу через /state.