Skip to main content
Todas as solicitações que enviamos ao seu servidor — entregas de webhook e invocações de endpoints de ferramentas — incluem uma assinatura HMAC-SHA256 no cabeçalho X-ThunderPhone-Signature. Implemente a verificação corretamente uma vez e use o mesmo auxiliar em todos os handlers.

O algoritmo

  1. Leia o corpo bruto da solicitação — os bytes exatos que enviamos para você via POST.
  2. Calcule hmac_sha256(secret, body).hexdigest().
  3. Compare em tempo constante com X-ThunderPhone-Signature. (Uma comparação ingênua de strings expõe informações de temporização.)
Assinamos exatamente os bytes que transmitimos, portanto verificar o corpo bruto sempre funciona. Esses bytes também são a serialização JSON canônica do payload — chaves ordenadas alfabeticamente, separadores compactos (, e : sem espaços), UTF-8. Isso oferece uma segunda receita totalmente equivalente quando seu framework expõe apenas JSON analisado: serialize novamente de forma canônica e calcule o HMAC disso.
Prefira o corpo bruto — é uma etapa a menos e evita peculiaridades de conversão de números JSON em algumas linguagens.

Qual segredo?

Armazene o segredo no seu gerenciador de segredos ou em uma variável de ambiente — nunca faça commit dele.

Implementações de referência

Todas as quatro verificam o corpo bruto da solicitação:

Configuração específica do framework

Verificação de chamadas de ferramenta

Quando o agente invoca diretamente uma das suas ferramentas de função (a ferramenta tem um endpoint), a solicitação inclui dois cabeçalhos do ThunderPhone junto com os endpoint.headers configurados:
  • X-ThunderPhone-Call-ID — o ID numérico da chamada ao vivo.
  • X-ThunderPhone-Signature — HMAC-SHA256, usando como chave o seu segredo de webhook no nível da organização, sobre os bytes exatos do corpo da solicitação.
O mesmo auxiliar verify() funciona sem alterações, com duas particularidades:
  1. Ferramentas GET / DELETE não têm corpo. Os argumentos são enviados como parâmetros de consulta, e a assinatura é calculada sobre a string de bytes vazia — portanto, verify(b"", sig, secret) (Python) ou verify(Buffer.alloc(0), sig, secret) (Node). Não gere hash da string de consulta.
  2. Organizações sem um webhook legado configurado não têm um segredo da organização. Nesse caso, as chamadas de ferramenta incluem apenas X-ThunderPhone-Call-ID e nenhum cabeçalho de assinatura. Configure o webhook legado (PUT /v1/webhook) para obter um segredo de assinatura ou autentique as chamadas de ferramenta com seu próprio cabeçalho via endpoint.headers.
O envio de ferramentas no modo webhook (ferramentas sem um endpoint, entregues ao webhook da sua organização como telephony.tool / web.tool) é um webhook comum assinado — a receita padrão acima se aplica. Consulte Ferramentas de função para ver os dois formatos de solicitação.

Erros comuns

Analisar o corpo e serializá-lo novamente com os padrões da sua biblioteca JSON (espaços após , / :, chaves na ordem de inserção) produz bytes diferentes e invalida o HMAC. Verifique o corpo bruto — ou, se precisar resserializá-lo, corresponda exatamente ao nosso formato canônico: chaves ordenadas, separadores compactos, UTF-8.
O middleware express.json() do Express consome o fluxo do corpo e você perde os bytes brutos. Use express.raw() especificamente na rota do webhook ou armazene o corpo bruto em buffer em um pré-middleware. O mesmo vale para NestJS / Koa — consulte a documentação sobre “corpo bruto”.
expected === signature em JS ou expected == signature em Python são comparações com tempo variável. Use crypto.timingSafeEqual ou hmac.compare_digest, respectivamente. A diferença de desempenho é nula.
Chamadas diretas a endpoints de ferramentas são assinadas com o segredo de webhook no nível da organização (GET /v1/webhook) — não com qualquer segredo por endpoint de /v1/developer/webhook-endpoints. Reutilize a mesma função verify(), mas certifique-se de fornecer a ela o segredo da organização nas rotas de ferramentas.
Para métodos de ferramentas sem corpo, a assinatura abrange a string de bytes vazia, mantendo uma única receita universal: aplique HMAC ao corpo bruto da solicitação, seja ele qual for. Gerar hash da URL ou da string de consulta nunca corresponderá.
Retornar 200 quando a verificação falha transforma o manipulador em um alvo de repetição. Sempre responda com um código diferente de 2xx se a verificação falhar.

Próximas etapas

Visão geral dos webhooks

Semântica de entrega, novas tentativas, IPs de origem.

Endpoints de webhook

Gerencie várias URLs, alterne segredos.

Ferramentas de função

Os dois caminhos de invocação de ferramentas e os formatos das solicitações.

Integrações de ferramentas

Crie uma integração completa com ferramentas, de ponta a ponta.