Open in
Visão geral dos webhooks
Como o ThunderPhone entrega eventos em tempo real, como verificar assinaturas e como os modelos de entrega legados e baseados em endpoint se comparam.
O ThunderPhone envia solicitações HTTP POST ao seu servidor quando algo
acontece durante uma chamada — uma chamada recebida começa, uma chamada termina, uma execução de avaliação
é concluída, um alerta é disparado e assim por diante. Há dois modelos
de entrega:
Várias URLs, segredos por endpoint, filtros de eventos por endpoint
e novas tentativas automáticas.
Gerencie por meio de GET/POST/PATCH/DELETE /v1/developer/webhook-endpoints.
Uma URL por organização. Inclui os eventos do ciclo de vida da chamada, incluindo as
trocas de configuração bloqueantes. Gerenciado em GET/PUT /v1/webhook.
Todos os tipos de evento listados no catálogo de eventos são
entregues por meio de endpoints de webhook. Os seis eventos do ciclo de vida da chamada
(telephony.incoming, telephony.complete, telephony.tool,
web.incoming, web.complete, web.tool) também são enviados ao
webhook legado de URL única — se você tiver uma URL legada e um
endpoint correspondente, receberá o evento em ambos os caminhos. O
comportamento bloqueante (a troca de configuração de
telephony.incoming / web.incoming e o
despacho de ferramentas no
modo webhook) existe exclusivamente no caminho legado; cada entrega a
um endpoint é uma notificação enviada sem aguardar resposta.
Formato da carga útil
As entregas aos endpoints são um objeto JSON com data, event_id e
type:
{
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
},
"event_id": "3f6b2ad0-1c9e-4a57-9f2b-8f6f0f9d2f11",
"type": "telephony.incoming"
}event_id é exclusivo para cada evento emitido. Ele é idêntico entre novas tentativas
e entre todos os endpoints que recebem o evento — use-o para eliminar duplicatas.
O webhook legado de URL única envia o mesmo type e data, mas
sem event_id:
{
"type": "telephony.incoming",
"data": { "call_id": 987654321, "from_number": "+14155550199", "to_number": "+15551234567" }
}Na transmissão, cada corpo é serializado de forma canônica — chaves ordenadas alfabeticamente, sem espaços em branco, UTF-8. Os exemplos formatados nestas documentações são apenas para facilitar a leitura.
Consulte o Catálogo de eventos para ver a lista completa de tipos de evento e campos de carga útil.
Verificação de assinatura
Cada solicitação contém duas assinaturas, ambas HMAC-SHA256 com chave baseada no
secret do endpoint (ou no secret de webhook no nível da sua organização para
entregas legadas):
X-ThunderPhone-Signature-V2: t=<unix seconds>,v1=<hex>assina o carimbo de data e hora, o método, o caminho e a consulta, além do corpo bruto. Verifique esta assinatura e rejeite solicitações cujotesteja a mais de 5 minutos do seu relógio para que uma solicitação capturada não possa ser reproduzida posteriormente. As tentativas são assinadas novamente quando são enviadas.X-ThunderPhone-Signatureassina apenas o corpo bruto. Ela continua sendo enviada, sem alterações, para que os verificadores existentes continuem funcionando.
Etapas
- Leia o cabeçalho, o método, o caminho e a consulta brutos, e o corpo bruto antes de qualquer análise.
- Calcule o HMAC-SHA256 em hexadecimal de
<t>\n<METHOD>\n<path and query>\n<body>com seu segredo. - Rejeite a solicitação se
tdiferir em mais de 300 segundos ou se o resultado não corresponder av1em uma comparação de tempo constante.
Os corpos usam a serialização JSON canônica (chaves ordenadas, separadores compactos), e assinamos exatamente os bytes que transmitimos. O guia de verificação contém a string assinada exata, um exemplo completo, código sem o SDK e o cabeçalho legado.
from flask import Flask, abort, request
from thunderphone import verify_signature
app = Flask(__name__)
@app.post("/thunderphone-webhook")
def handle():
query = request.query_string.decode()
if not verify_signature(
request.headers.get("X-ThunderPhone-Signature-V2"),
secret=WEBHOOK_SECRET,
method=request.method,
path=request.path + (f"?{query}" if query else ""),
body=request.get_data(), # raw bytes
):
abort(401)
event = request.get_json()
# dispatch on event["type"] …
return "", 204import express from "express";
import { verifySignature } from "@thunderphone/sdk";
const app = express();
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
const ok = verifySignature({
header: req.header("X-ThunderPhone-Signature-V2"),
secret: process.env.WEBHOOK_SECRET,
method: req.method,
path: req.originalUrl,
body: req.body,
});
if (!ok) return res.sendStatus(401);
const event = JSON.parse(req.body.toString("utf8"));
// dispatch on event.type …
res.sendStatus(204);
},
);Semântica de entrega
Estas semânticas se aplicam a entregas de endpoint. O webhook legado de URL única
é uma única tentativa síncrona, sem novas tentativas, exceto pela troca de
configuração de chamada telefônica telephony.incoming,
que é repetida uma vez.
Novas tentativas
Cada evento é tentado uma vez imediatamente. Qualquer resposta 2xx
confirma a entrega. Em qualquer outro resultado (resposta fora da faixa 2xx,
erro de conexão, tempo limite), tentamos novamente após 1 m, 5 m, 30 m, 2 h, 6 h,
12 h e 24 h da primeira tentativa — 8 tentativas ao longo de
24 horas. Se todas as tentativas falharem, a entrega é interrompida e o endpoint
é marcado como status="failing" em
endpoints de webhook; enviamos um e-mail aos
proprietários e administradores da sua organização e exibimos isso no painel. Retorne 2xx assim que
o payload for aceito de forma durável; processe-o de modo assíncrono.
Envios de teste da API de teste do endpoint recebem uma nova tentativa cerca de um minuto após
a primeira tentativa e nunca alteram o status do endpoint.
Ordenação
A ordenação de entrega é feita conforme a melhor tentativa. Na prática, entregamos na
ordem em que os eventos são emitidos, mas novas tentativas podem reordenar eventos em caso de falha.
Sempre elimine duplicatas e reconcilie por call_id / id do objeto.
Duplicatas
A entrega é pelo menos uma vez: uma nova tentativa após uma resposta que nunca
recebemos pode duplicar um evento. Cada nova tentativa contém o mesmo
event_id, portanto armazene os ids processados e ignore repetições. event_id também é
compartilhado entre endpoints — dois endpoints inscritos no
mesmo evento recebem o mesmo event_id.
Tempos limite
As entregas de endpoint têm um tempo limite de 30 s por tentativa. No
caminho legado, solicitações bloqueantes que controlam o comportamento de chamadas ao vivo — a
troca de configuração telephony.incoming / web.incoming
— são limitadas a 10 s para a primeira tentativa de uma chamada telefônica
e a 13 s para toda a troca, incluindo sua única
nova tentativa, e a 10 s para uma sessão de widget. Uma resposta lenta atrasa
o atendimento da chamada, portanto procure responder em poucos segundos. O despacho de ferramentas no modo webhook permite 20 s
por padrão, e as declarações de ferramentas podem definir um timeout de nível superior.
IPs de origem
Os webhooks de saída se originam na faixa de IPs de nuvem do ThunderPhone. Se seu firewall exigir uma lista de permissões, entre em contato com o suporte e compartilharemos as faixas atuais.
Como escolher entre webhooks legados e baseados em endpoint
| Recurso | Legado (/v1/webhook) | Endpoints (/v1/developer/webhook-endpoints) |
|---|---|---|
| Número de URLs | 1 por organização | Várias por organização |
| Cobertura de eventos | Apenas telephony.* / web.* | Todos os 10 tipos de evento |
| Filtro de eventos | — | Por endpoint |
| Tentativas | Nenhuma, exceto uma para a troca de configuração da chamada telefônica | 8 tentativas em 24 h |
| Envelope | type + data | type + data + event_id |
| Rotação de segredo | Substitui o segredo único | Segredo por endpoint |
| Desativar sem excluir | PUT /v1/webhook com {"url": ""} | status=disabled |
| Visibilidade de status | — | active / disabled / failing |
| Troca de configuração bloqueante | Sim (telephony.incoming / web.incoming) | Nunca — apenas notificações |
| Ideal para | Configuração dinâmica de chamadas | Consumo de eventos em produção |
Novas integrações devem consumir eventos por meio de webhooks baseados em endpoint. Mantenha (ou adicione) uma URL legada apenas se você configurar chamadas dinamicamente no momento do atendimento ou usar a execução de ferramentas no modo webhook — essas trocas de solicitação/resposta são executadas somente no caminho legado.
Relacionados
Todos os tipos de evento e suas cargas úteis.
Gerencie vários endpoints, filtros de eventos e segredos.
A solicitação bloqueante que seu servidor deve responder para configurar chamadas.
Carga útil pós-chamada com transcrição, gravação e métricas.