
# Webhooks

Receba eventos da sua instância do WhatsApp no backend do seu sistema. Você configura uma URL de destino; a API envia um **POST com JSON** para essa URL quando ocorre um evento selecionado.

## Fluxo de uma integração

1. Disponibilize um receptor HTTP acessível ao servidor da API.
2. Configure a URL e a lista de eventos na instância.
3. Valide e registre cada recebimento, responda rapidamente com `2xx` e processe a regra da aplicação.
4. Consulte os erros e reconcilie dados quando houver falhas de entrega.

A URL de destino é do **seu sistema**. Ela é diferente da [Server URL](/docs/server-url), usada para chamar a API.

## Configurar o webhook da instância

```bash
curl -X POST "$BASE_URL/webhook" \
  -H "token: $INSTANCE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "url": "https://seu-sistema.example/hooks/whatsapp",
    "events": ["messages", "messages_update", "connection"],
    "excludeMessages": ["wasSentByApi"],
    "addUrlEvents": false,
    "addUrlTypesMessages": false
  }'
```

O modo simples configura o webhook principal. Para gerenciar mais de um destino, consulte as ações `add`, `update` e `delete` e os IDs retornados em [GET /webhook](/endpoint/get/webhook). Confira o contrato completo de [POST /webhook](/endpoint/post/webhook) antes de alterar um destino existente.

### Filtros de mensagens

`excludeMessages` contém os casos que você deseja **excluir** da entrega:

| Valor | Exclui |
|---|---|
| `wasSentByApi` | Mensagens classificadas como enviadas pela API |
| `wasNotSentByApi` | Mensagens que não foram classificadas como enviadas pela API |
| `fromMeYes` | Mensagens originadas pela conta conectada |
| `fromMeNo` | Mensagens que não são da conta conectada |
| `isGroupYes` | Mensagens de grupo |
| `isGroupNo` | Mensagens fora de grupos |

`wasSentByApi` e `fromMeYes` são critérios diferentes. Uma mensagem enviada pelo celular pode ser da própria conta sem ter sido enviada pela API. Escolha os filtros conforme a automação para evitar loops de resposta.

### Como a URL final é formada

`addUrlEvents` acrescenta o `EventType` como **segmento do caminho**. `addUrlTypesMessages` acrescenta o tipo da mensagem quando ele está disponível. Não são parâmetros de query string.

| Configuração | Exemplo de destino |
|---|---|
| Ambos desativados | `/hooks/whatsapp` |
| Apenas `addUrlEvents` | `/hooks/whatsapp/messages` |
| Ambos ativados, mensagem de texto | `/hooks/whatsapp/messages/text` |

Se ativar essas opções, seu receptor precisa aceitar os caminhos derivados. Um endpoint que aceita apenas a URL base pode passar a responder 404.

## Catálogo de eventos

Use exatamente os valores da coluna `EventType` em `events`. Cada página apresenta finalidade, campos e exemplos específicos.

| EventType | O que acompanhar |
|---|---|
| [`connection`](/webhook/connection) | Conexão da instância |
| [`history`](/webhook/history) | Sincronização de histórico |
| [`messages`](/webhook/messages) | Mensagens |
| [`messages_update`](/webhook/messages_update) | Entrega e leitura |
| [`newsletter_messages`](/webhook/newsletter_messages) | Mensagens de canais |
| [`call`](/webhook/call) | Chamadas |
| [`contacts`](/webhook/contacts) | Contatos |
| [`presence`](/webhook/presence) | Digitação e gravação |
| [`groups`](/webhook/groups) | Alterações de grupos |
| [`labels`](/webhook/labels) | Definição de etiquetas |
| [`chats`](/webhook/chats) | Atualizações de chats |
| [`chat_labels`](/webhook/chat_labels) | Etiquetas de um chat |
| [`sender`](/webhook/sender) | Processamento de campanhas |

## Envelope comum

| Campo | Uso |
|---|---|
| `EventType` | Identifica o evento recebido |
| `owner` | Identidade da conta associada à instância |
| `token` | Credencial da instância; deve ser protegida |
| `BaseUrl` | Endereço base informado pela API |
| `instanceName` | Nome da instância, quando disponível |

Os campos específicos ficam na raiz: por exemplo `message`, `chat`, `event` ou dados de uma campanha. Não presuma que todo evento tenha `{ event, instance, data }`. Nem todos possuem um `event_id` universal; use a estratégia de correlação da página de cada evento.

O token no payload é sensível. Faça a validação e o vínculo com a instância autorizada no seu backend; não use apenas `owner` ou `instanceName` como permissão. Não registre o payload completo em logs públicos.

## Webhook global

[GET /globalwebhook](/endpoint/get/globalwebhook) e [POST /globalwebhook](/endpoint/post/globalwebhook) usam `admintoken` para configuração administrativa. O destino global pode receber eventos de várias instâncias: faça o roteamento correto antes de processar a mensagem.

## Sempre responda 200 imediatamente

Não mantenha a requisição do webhook aberta. Para cada evento recebido, responda `200` imediatamente e coloque o trabalho na fila interna da sua aplicação. Validação, deduplicação, chamadas a CRM, respostas automáticas, download de mídia, transcrição e outras regras devem acontecer **depois**, de forma assíncrona.

Fluxo recomendado:

1. Receba o payload e preserve o objeto necessário para o processamento.
2. Responda `200` imediatamente.
3. Coloque o evento em uma fila ou caixa de entrada durável sem aguardar o processamento.
4. Valide, deduplique e processe o evento separadamente.
5. Registre sucesso ou falha para reconciliação.

```js
app.post('/hooks/whatsapp', (req, res) => {
  const event = req.body;

  res.sendStatus(200);

  webhookInbox.enqueue(event).catch(reportWebhookFailure);
});

webhookInbox.process(async (event) => {
  if (!isValidWebhook(event)) return;
  await processBusinessRules(event);
});
```

Não aguarde `enqueue`, validações externas nem `processBusinessRules` antes de responder. Isso aumenta a latência, pode causar timeout e atrasa a fila de webhooks. Monitore falhas da sua fila interna e reconcilie dados pela API quando necessário.

### Evite atrasar a fila de webhooks

Um webhook lento, indisponível ou apontando para uma URL que não existe mais ocupa a capacidade de entrega e faz os próximos eventos aguardarem. Com volume alto, a fila pode acumular e eventos podem ser descartados.

- Desative webhooks de testes assim que eles deixarem de ser usados.
- Desative o webhook durante uma manutenção em que o receptor ficará indisponível.
- Remova destinos antigos ou duplicados que não possuem mais consumidor.
- Antes de reativar, confirme que a URL está acessível e responde `200` rapidamente.
- Consulte [erros do webhook da instância](/endpoint/get/webhook~errors) para identificar timeout, conexão recusada e respostas HTTP de erro.

Use [POST /webhook](/endpoint/post/webhook) para desativar ou atualizar um destino. Não deixe um webhook quebrado ativo esperando que ele volte sozinho: isso atrasa a fila da instância.

## Diagnóstico

1. Confira `enabled`, a instância/servidor e os nomes em `events`.
2. Verifique se os filtros excluem o evento esperado.
3. Confira a URL final, especialmente quando os segmentos automáticos estão ativados.
4. Valide conectividade, HTTPS e a resposta do seu receptor.
5. Consulte [erros da instância](/endpoint/get/webhook~errors) ou [erros do webhook global](/endpoint/get/globalwebhook~errors).

O header `X-Webhook-Error-Capture-Started-At` ajuda a identificar a janela de captura disponível. Use essa consulta como diagnóstico operacional, não como armazenamento permanente de auditoria.

## Webhooks ou SSE?

Use webhooks para integração entre servidores. Use [SSE](/endpoint/get/sse) para manter uma interface atualizada durante uma conexão aberta. Eles podem coexistir; receber SSE não comprova que o seu receptor de webhook aceitou o evento.

```js
const params = new URLSearchParams({
  token: instanceToken,
  events: 'chats,messages,messages_update,connection',
});
const stream = new EventSource(`${baseUrl}/sse?${params}`);
stream.onmessage = ({ data }) => {
  const update = JSON.parse(data);
  // Atualize o estado da aplicação sem registrar credenciais.
};
// Ao desmontar a tela:
// stream.close();
```

O token fica na URL do SSE. Proteja a URL e evite incluí-la em logs e analytics. A sessão, os filtros e as permissões do seu backend continuam valendo.
