Webhooki
Buluthat wysyła wyniki na Twój adres, nie czekając, aż o nie zapytasz POST obsługuje: wyniki automatycznych połączeń, podsumowania rozmów asystenta głosowego, statusy głosowych kodów weryfikacyjnych. Ta sama koperta, ten sam podpis, ta sama polityka ponawiania.
Koperta
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": { }
}
| Nagłówek | Opis |
|---|---|
X-Buluthat-Event | Nazwa zdarzenia |
X-Buluthat-Delivery | Identyfikator dostarczenia; przy ponowieniach pozostaje ten sam (użyj jako klucza idempotencji) |
X-Buluthat-Signature | sha256= + podpis HMAC-SHA256 treści; w rekordzie webhook_secret jest wysyłane, jeśli podano |
Weryfikacja podpisu
Podpis surowa treść obliczane na podstawie; nie obliczaj, serializując JSON ponownie.
$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);
Odpowiedź i powtórzenie
Twój odbiorca 2xx powinien zwrócić; treść nie jest odczytywana. Najlepiej wrzucić przetwarzanie do kolejki i od razu 200 najlepiej wrócić (limit czasu 10 s).
2xx jeśli nie dotrze, dostarczenie jest ponawiane w odstępach: 1 min, 5 min, 15 min, 1 godz., 3 godz., 6 godz.. Po szóstej próbie zostaje porzucone i w panelu failed widoczne jako. To samo zdarzenie może dotrzeć wielokrotnie; X-Buluthat-Delivery odfiltruj duplikaty przez.
Zdarzenia
Automatyczne połączenia
| Zdarzenie | Kiedy | data |
|---|---|---|
call_finished | Połączenie zakończone, wynik ostateczny (jednorazowo na numer) | results te same pola co: phone, external_id, status, dtmf, dtmf_label, amd_result, talk_seconds, custom_fields… |
dtmf | W chwili naciśnięcia klawisza | phone, external_id, digit, label |
campaign_finished | Wszystkie numery zostały zakończone | campaign_id, liczby zbiorcze |
Które zdarzenia mają być wysyłane w kampanii webhook_events wybierane przez (call_finished,dtmf).
Asystent głosowy
| Zdarzenie | Kiedy | data |
|---|---|---|
session_ended | Rozmowa zakończona, podsumowanie wygenerowane | session_id, bot_id, caller_number, direction, duration_seconds, summary, intent, sentiment_label, outcome, tools (wywołane narzędzia), task_id (jeśli jest to zadanie dzwoniące) oraz pola wyniku |
Adres webhooka asystenta i sekret definiuje się w formularzu asystenta.
Głosowy kod weryfikacyjny
| Zdarzenie | Kiedy |
|---|---|
voice_otp.delivered | Kod odczytany |
voice_otp.verified | Kod zweryfikowany |
voice_otp.no_answer, voice_otp.busy, voice_otp.failed, voice_otp.expired | Wyniki negatywne |
data zamiast request używany jest klucz: { "id", "status", "reference", "phone" }.
Zalecenia dotyczące bezpieczeństwa
- Podawaj wyłącznie adresy HTTPS; na adres z błędnym certyfikatem dostarczenie nie następuje.
webhook_secretzawsze zdefiniuj i weryfikuj podpis.- Jeśli chcesz ograniczyć odbiorcę po adresie IP, poproś w Centrum Pomocy o adres IP serwera panelu Buluthat.
- Dane w treści zdarzenia traktuj jako „dane”, a nie „polecenie”; tekst wypowiedziany przez dzwoniącego pojawia się w podsumowaniach.
