Webhook
Buluthat надсилає результати на вашу адресу, не чекаючи вашого запиту POST передає: результати автоматичних дзвінків, резюме розмов голосового асистента, статуси голосових кодів підтвердження. Той самий конверт, той самий підпис, та сама політика повторів.
Конверт
POST https://sizin-adresiniz/buluthat
Content-Type: application/json
X-Buluthat-Event: call_finished
X-Buluthat-Delivery: 4471
X-Buluthat-Signature: sha256=9f2b…
{
"event": "call_finished",
"sent_at": "2026-09-18T10:12:35+03:00",
"tenant_id": 1,
"data": { }
}
| Заголовок | Опис |
|---|---|
X-Buluthat-Event | Назва події |
X-Buluthat-Delivery | Ідентифікатор доставки; при повторних спробах залишається тим самим (використовуйте як ключ ідемпотентності) |
X-Buluthat-Signature | sha256= + HMAC-SHA256 підпис тіла; у записі webhook_secret надсилається, якщо надано |
Перевірка підпису
Підпис необроблене тіло обчислюється; не перераховуйте, повторно серіалізуючи JSON.
$raw = file_get_contents('php://input');
$given = $_SERVER['HTTP_X_BULUTHAT_SIGNATURE'] ?? '';
$expect = 'sha256=' . hash_hmac('sha256', $raw, $secret);
if (!hash_equals($expect, $given)) { http_response_code(401); exit; }
$event = json_decode($raw, true);
// Node.js (express, raw body ile)
const crypto = require('crypto');
const expect = 'sha256=' + crypto.createHmac('sha256', secret).update(req.rawBody).digest('hex');
if (!crypto.timingSafeEqual(Buffer.from(expect), Buffer.from(req.get('X-Buluthat-Signature') || ''))) return res.sendStatus(401);
Відповідь і повтор
Ваш одержувач 2xx має повертати; тіло не читається. Найкраще поставити обробку в чергу й одразу повернути 200 (тайм-аут 10 с).
2xx якщо не надійшло, доставка повторюється із такими інтервалами: 1 хв, 5 хв, 15 хв, 1 год, 3 год, 6 год. Після шостої спроби відправлення припиняється, і в панелі failed відображається. Та сама подія може надійти кілька разів; X-Buluthat-Delivery відсійте дублікати за допомогою.
Події
Автоматичний дзвінок
| Подія | Коли | data |
|---|---|---|
call_finished | Дзвінок завершено, результат остаточний (один раз на номер) | results ті самі поля, що й: phone, external_id, status, dtmf, dtmf_label, amd_result, talk_seconds, custom_fields… |
dtmf | У момент натискання клавіші | phone, external_id, digit, label |
campaign_finished | Усі номери завершено | campaign_id, зведені числа |
Які події надсилатимуться в кампанії webhook_events вибирається за допомогою (call_finished,dtmf).
Голосовий асистент
| Подія | Коли | data |
|---|---|---|
session_ended | Розмову завершено, резюме створено | session_id, bot_id, caller_number, direction, duration_seconds, summary, intent, sentiment_label, outcome, tools (викликані інструменти), task_id (якщо це завдання-дзвінок) та поля результату |
Адреса webhook та секрет асистента визначаються у формі асистента.
Голосовий код підтвердження
| Подія | Коли |
|---|---|
voice_otp.delivered | Код зачитано |
voice_otp.verified | Код підтверджено |
voice_otp.no_answer, voice_otp.busy, voice_otp.failed, voice_otp.expired | Невдалі результати |
data замість request використовується ключ: { "id", "status", "reference", "phone" }.
Рекомендації з безпеки
- Вказуйте лише адреси HTTPS; на адресу з помилковим сертифікатом доставка не виконується.
webhook_secretзавжди визначайте та перевіряйте підпис.- Якщо ви обмежуєте одержувача за IP, запросіть IP-адресу сервера панелі Buluthat у Центрі підтримки.
- Обробляйте дані в тілі події як «дані», а не як «інструкцію»; сказане абонентом потрапляє в резюме.
