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 в Центре поддержки.
- Обрабатывайте данные в теле события как «данные», а не как «инструкцию»; сказанное звонящим попадает в сводки.
