Вебхуки асистента CallAIder: повна інструкція з прикладами

Webhook асистента дозволяє отримувати серверні події про сесію у вашому зовнішньому сервісі: CRM, BI, data warehouse або інтеграційному шлюзі.

У цьому гайді зібрані всі важливі технічні деталі: які події надсилаються, які заголовки ви отримаєте, як перевірити підпис, що саме приходить у payload і як правильно обробляти ці дані на бекенді.

Коли webhook корисний

Webhook варто підключати, якщо вам потрібно:

  • запускати пост-обробку після завершення діалогу;
  • зберігати транскрипт у власній системі;
  • синхронізувати статуси сесій із CRM;
  • будувати власні аналітичні воронки поза інтерфейсом платформи.

Крок 1. Налаштуйте webhook в асистенті

У картці асистента заповніть:

  • webhookUrl - URL endpoint для прийому подій;
  • webhookSecret (необов’язково, але рекомендовано) - секрет для підпису X-Callaider-Signature;
  • webhookHeaders - додаткові заголовки, наприклад Authorization: Basic 12345.

Якщо поле webhookSecret залишити порожнім, секрет може бути згенерований автоматично.

Налаштування webhook в асистенті

Якщо webhookUrl не вказано, події не надсилаються.

Які події надсилаються

Надсилаються лише дві серверні події:

  • session.started
  • session.ended

HTTP-запит і заголовки

Параметри запиту:

  • Метод: POST
  • Тіло: application/json
  • Формат: JSON payload

Системні заголовки, які сервіс додає завжди:

  • Content-Type: application/json
  • X-Callaider-Event: <event_name>
  • X-Callaider-Signature: sha256=<hex> (якщо задано webhookSecret)

Користувацькі заголовки з webhookHeaders також додаються до запиту, але є важливе правило пріоритету:

  • системні заголовки мають вищий пріоритет;
  • Content-Type, X-Callaider-Event, X-Callaider-Signature не можна перевизначити через webhookHeaders.

Крок 2. Перевірте події через webhook.site

Для швидкої перевірки можна тимчасово вставити URL із webhook.site у поле webhookUrl.

Після тестової сесії ви побачите окремі POST-запити для старту і завершення сесії.

Приклад session.started:

Приклад запиту session.started у webhook.site

Приклад session.ended:

Приклад запиту session.ended у webhook.site

Структура payload

Загальний формат:

{
  "event": "session.started | session.ended",
  "timestamp": "2026-05-28T12:34:56.789Z",
  "assistantId": 123,
  "sessionId": "2d7b8f7f-2de0-4db9-ae6f-9a1f8d98f6d2",
  "data": {}
}

Подія session.started

data містить метадані сесії:

{
  "metadata": {
    "userAgent": "Mozilla/5.0 ...",
    "sessionMode": "voice | text",
    "callId": "optional"
  }
}

Що важливо:

  • metadata береться з даних створення сесії;
  • metadata.sessionMode може бути voice або text;
  • склад metadata залежить від джерела сесії (widget, web app, telephony тощо).

Подія session.ended

data містить результат завершеної сесії:

{
  "reason": "assistant_ended",
  "durationSeconds": 27,
  "transcript": [
    {
      "role": "assistant",
      "content": "Доброго дня, чим можу допомогти?",
      "timestamp": 1779954672417
    },
    {
      "role": "user",
      "content": "Привіт. Як справи?",
      "timestamp": 1779954679847
    }
  ]
}

Поля:

  • reason - причина завершення (assistant_ended, user_ended, client_disconnect, timeout тощо);
  • durationSeconds - тривалість сесії в секундах (коли доступні startedAt і endedAt);
  • transcript - масив накопичених повідомлень сесії.

Формат елемента transcript

{
  "role": "user | assistant | system | tool",
  "content": "text",
  "timestamp": 1716900000000,
  "toolCall": {
    "name": "optional",
    "arguments": {},
    "result": {},
    "error": "optional"
  },
  "files": [
    {
      "gcsUri": "gs://...",
      "mimeType": "application/pdf",
      "filename": "document.pdf"
    }
  ]
}

toolCall та files присутні лише тоді, коли це застосовно до конкретного повідомлення.

Перевірка підпису X-Callaider-Signature

Підпис потрібен, щоб переконатися у двох речах: запит дійсно надійшов від CallAIder і payload не був змінений під час передачі.

«HMAC не шифрує дані, але криптографічно підтверджує цілісність тіла запиту та знання спільного секрету».

Валідація підпису - опціональна:

  • якщо хочете додатковий контроль безпеки, перевіряйте підпис;
  • якщо у вашому сценарії це не потрібно, можна обробляти webhook без валідації підпису.

Ви отримаєте підпис у заголовку:

  • X-Callaider-Signature: sha256=<hex_digest>

Підпис розраховується як HMAC SHA-256 від raw JSON body.

Алгоритм перевірки на вашому сервері:

  1. Отримайте raw body запиту без змін форматування.
  2. Обчисліть HMAC SHA-256 з вашим webhookSecret.
  3. Порівняйте результат із X-Callaider-Signature у константному часі.

Приклад для Node.js (Express):

import crypto from 'node:crypto';
import express from 'express';

const app = express();

app.post(
  '/assistant-webhook',
  express.raw({ type: 'application/json' }),
  (req, res) => {
    const rawBody = req.body as Buffer;
    const signature = req.header('x-callaider-signature') || '';
    const event = req.header('x-callaider-event') || '';

    const secret = process.env.CALLAIDER_WEBHOOK_SECRET || '';

    if (secret) {
      const digest = crypto
        .createHmac('sha256', secret)
        .update(rawBody)
        .digest('hex');

      const expected = `sha256=${digest}`;
      const valid =
        signature.length === expected.length &&
        crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));

      if (!valid) {
        return res.status(401).json({ ok: false, error: 'Invalid signature' });
      }
    }

    const payload = JSON.parse(rawBody.toString('utf8'));

    // Рекомендований ключ ідемпотентності: `${payload.sessionId}:${payload.event}`
    // Далі: черга/асинхронна обробка

    return res.status(200).json({ ok: true, event });
  }
);

Рекомендований production-патерн обробки

Щоб інтеграція працювала стабільно під навантаженням:

  1. Якщо використовуєте webhookSecret, валідуйте підпис до бізнес-логіки.
  2. Дедуплікуйте події за ключем sessionId + event.
  3. Відповідайте швидко 2xx, а важку обробку (CRM, AI post-processing, архівація) виносьте у чергу.
  4. Лімітуйте розмір payload на endpoint, бо transcript може бути великим.
  5. Логуйте помилки розбору окремо для session.started і session.ended.

Приклад маршрутизації подій

switch (payload.event) {
  case 'session.started':
    // створити/оновити картку активної сесії
    break;
  case 'session.ended':
    // зберегти transcript, durationSeconds, reason
    // запустити post-processing у фоні
    break;
  default:
    // ігноруємо невідомі події
    break;
}

Чеклист перед запуском у продакшен

  • webhookUrl доступний із зовнішньої мережі.
  • Endpoint стабільно відповідає швидше 3000 ms.
  • За потреби налаштований webhookSecret і перевірка підпису.
  • Увімкнена ідемпотентність (sessionId + event).
  • Є алерти на 4xx/5xx у вашому webhook endpoint.
  • Протестовані обидві події: session.started і session.ended.

Висновок

Webhook асистента в CallAIder - це простий і надійний спосіб отримувати життєвий цикл сесії на ваш бекенд. Для базової інтеграції достатньо одного endpoint, а для production-рівня варто додати підпис, дедуплікацію та асинхронну обробку.

Якщо починаєте з нуля, використайте webhook.site для валідації payload, а вже після цього перемикайте webhookUrl на ваш production endpoint.