Webhooks

A Buluthat envia os resultados para o seu endereço sem esperar que os peça POST envia: resultados das chamadas automáticas, resumos de conversas do assistente de voz, estados dos códigos de verificação por voz. O mesmo envelope, a mesma assinatura, a mesma política de repetição.

Envelope

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": { }
}
CabeçalhoDescrição
X-Buluthat-EventNome do evento
X-Buluthat-DeliveryIdentificador de entrega; mantém-se igual nas novas tentativas (use-o como chave de idempotência)
X-Buluthat-Signaturesha256= + assinatura HMAC-SHA256 do corpo; no registo webhook_secret se for indicado, é enviado

Validação da assinatura

Assinatura corpo bruto é calculada a partir de; não volte a serializar o JSON para calcular.

$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);

Resposta e repetição

O seu interlocutor 2xx deve devolver; o corpo não é lido. O mais seguro é pôr o processamento em fila e devolver de imediato 200 (prazo de 10 s).

2xx se não chegar, a entrega é repetida nos seguintes intervalos: 1 min, 5 min, 15 min, 1 h, 3 h, 6 h. Após a sexta tentativa é abandonado e no painel failed aparece como. O mesmo evento pode chegar mais de uma vez; X-Buluthat-Delivery elimine a repetição com.

Eventos

Chamadas automáticas

EventoQuandodata
call_finishedA chamada terminou, o resultado é definitivo (uma vez por número)results campos iguais aos de: phone, external_id, status, dtmf, dtmf_label, amd_result, talk_seconds, custom_fields…
dtmfNo momento em que a tecla é premidaphone, external_id, digit, label
campaign_finishedTodos os números concluídoscampaign_id, totais resumidos

Quais os eventos a enviar na campanha webhook_events escolhe-se com (call_finished,dtmf).

Assistente de voz

EventoQuandodata
session_endedA conversa terminou e o resumo foi geradosession_id, bot_id, caller_number, direction, duration_seconds, summary, intent, sentiment_label, outcome, tools (ferramentas invocadas), task_id (se for uma chamada de tarefa) e os campos de resultado

O endereço do webhook e o segredo do assistente são definidos no formulário do assistente.

Código de verificação por voz

EventoQuando
voice_otp.deliveredCódigo lido
voice_otp.verifiedCódigo validado
voice_otp.no_answer, voice_otp.busy, voice_otp.failed, voice_otp.expiredResultados com falha

data em vez de request é utilizada a chave: { "id", "status", "reference", "phone" }.

Recomendações de segurança

  • Indique apenas endereços HTTPS; não se entrega a endereços com certificado inválido.
  • webhook_secret defina sempre e valide a assinatura.
  • Se for restringir o destinatário por IP, peça ao Centro de Apoio o IP do servidor do painel Buluthat.
  • Trate os dados do corpo do evento como "dados" e não como "instruções"; o texto dito por quem liga aparece nos resumos.