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