---
title: "Visão geral dos webhooks"
description: "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**:

<CardGroup cols={2}>
  <Card title="Endpoints de webhook (recomendado)" icon="bolt" href="/pt/webhooks/endpoints">
    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`.
  </Card>
  <Card title="Webhook legado de URL única" icon="link" href="/api-reference/organizations#legacy-single-url-webhook">
    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`.
  </Card>
</CardGroup>

Todos os tipos de evento listados no [catálogo de eventos](/pt/webhooks/events) 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`](/pt/webhooks/call-incoming) e o
[despacho de ferramentas](/pt/tools/overview) 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`:

```json
{
  "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`:

```json
{
  "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](/pt/webhooks/events) 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 cujo `t` esteja 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-Signature` assina apenas o corpo bruto. Ela continua sendo enviada,
  sem alterações, para que os verificadores existentes continuem funcionando.

### Etapas

1. Leia o cabeçalho, o método, o caminho e a consulta brutos, e o
   corpo bruto **antes** de qualquer análise.
2. Calcule o HMAC-SHA256 em hexadecimal de
   `<t>\n<METHOD>\n<path and query>\n<body>` com seu segredo.
3. Rejeite a solicitação se `t` diferir em mais de 300 segundos ou se o
   resultado não corresponder a `v1` em 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](/pt/guides/verify-webhook-signatures) contém a string
assinada exata, um exemplo completo, código sem o SDK e o cabeçalho legado.

<CodeGroup>
```python Python (Flask)
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 "", 204
```

```javascript Node.js (Express)
import 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);
  },
);
```
</CodeGroup>

## 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`](/pt/webhooks/call-incoming),
que é repetida uma vez.

<AccordionGroup>
  <Accordion title="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](/pt/webhooks/endpoints); 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.
  </Accordion>

  <Accordion title="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.
  </Accordion>

  <Accordion title="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`.
  </Accordion>

  <Accordion title="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`](/pt/webhooks/call-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](/pt/tools/overview) no modo webhook permite 20 s
    por padrão, e as declarações de ferramentas podem definir um `timeout` de nível superior.
  </Accordion>

  <Accordion title="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.
  </Accordion>
</AccordionGroup>

## 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`](/pt/webhooks/call-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

<CardGroup cols={2}>
  <Card title="Catálogo de eventos" icon="list" href="/pt/webhooks/events">
    Todos os tipos de evento e suas cargas úteis.
  </Card>
  <Card title="Endpoints de webhook" icon="bolt" href="/pt/webhooks/endpoints">
    Gerencie vários endpoints, filtros de eventos e segredos.
  </Card>
  <Card title="telephony.incoming / web.incoming" icon="phone" href="/pt/webhooks/call-incoming">
    A solicitação bloqueante que seu servidor deve responder para configurar chamadas.
  </Card>
  <Card title="telephony.complete / web.complete" icon="phone" href="/pt/webhooks/call-complete">
    Carga útil pós-chamada com transcrição, gravação e métricas.
  </Card>
</CardGroup>
