> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wapizap.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Configurando Webhooks

> Receba notificações em tempo real de eventos do WhatsApp

# Configurando Webhooks

Webhooks permitem que sua aplicação receba notificações em tempo real quando eventos acontecem no WhatsApp (mensagens recebidas, status de entrega, etc.).

## Como Funciona

```
WhatsApp → Wapizap API → Seu Webhook → Sua Aplicação
```

1. Um evento acontece (ex: mensagem recebida)
2. A Wapizap API envia um POST para sua URL de webhook
3. Sua aplicação processa o evento

***

## Criar um Webhook

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.wapizap.com/api/v2/webhooks \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer SEU_TOKEN" \
    -d '{
      "instanceId": "sua-instancia",
      "url": "https://seu-servidor.com/webhook/wapizap",
      "events": ["message", "message.ack", "connection.update"],
      "secret": "seu_secret_para_validacao"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.wapizap.com/api/v2/webhooks', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer SEU_TOKEN'
    },
    body: JSON.stringify({
      instanceId: 'sua-instancia',
      url: 'https://seu-servidor.com/webhook/wapizap',
      events: ['message', 'message.ack', 'connection.update'],
      secret: 'seu_secret_para_validacao'
    })
  });

  const webhook = await response.json();
  console.log('Webhook ID:', webhook.data.id);
  ```

  ```python Python theme={null}
  import requests

  response = requests.post(
      'https://api.wapizap.com/api/v2/webhooks',
      headers={
          'Content-Type': 'application/json',
          'Authorization': 'Bearer SEU_TOKEN'
      },
      json={
          'instanceId': 'sua-instancia',
          'url': 'https://seu-servidor.com/webhook/wapizap',
          'events': ['message', 'message.ack', 'connection.update'],
          'secret': 'seu_secret_para_validacao'
      }
  )
  ```
</CodeGroup>

***

## Eventos Disponíveis

| Evento                      | Descrição                                       |
| --------------------------- | ----------------------------------------------- |
| `message`                   | Nova mensagem recebida                          |
| `message.ack`               | Atualização de status (enviado, entregue, lido) |
| `message.revoked`           | Mensagem apagada pelo remetente                 |
| `connection.update`         | Status da conexão mudou                         |
| `presence.update`           | Status de presença (online, digitando)          |
| `groups.upsert`             | Grupo criado ou atualizado                      |
| `groups.update`             | Configurações do grupo alteradas                |
| `group-participants.update` | Participantes adicionados/removidos             |
| `chats.upsert`              | Novo chat iniciado                              |
| `chats.update`              | Chat atualizado                                 |
| `contacts.upsert`           | Novo contato detectado                          |

<Tip>
  Use `["*"]` para receber **todos** os eventos (não recomendado em produção).
</Tip>

***

## Recebendo Webhooks

### Estrutura do Payload

```json theme={null}
{
  "event": "message",
  "instanceId": "sua-instancia",
  "timestamp": 1705233000,
  "data": {
    "key": {
      "remoteJid": "5511999999999@s.whatsapp.net",
      "fromMe": false,
      "id": "3EB0XXXXX"
    },
    "message": {
      "conversation": "Olá, preciso de ajuda!"
    },
    "messageTimestamp": 1705233000,
    "pushName": "João Silva"
  }
}
```

### Exemplo de Servidor (Node.js/Express)

```javascript theme={null}
const express = require('express');
const crypto = require('crypto');

const app = express();
app.use(express.json());

const WEBHOOK_SECRET = 'seu_secret_para_validacao';

// Validar assinatura do webhook
function validateSignature(payload, signature) {
  const hash = crypto
    .createHmac('sha256', WEBHOOK_SECRET)
    .update(JSON.stringify(payload))
    .digest('hex');
  return hash === signature;
}

app.post('/webhook/wapizap', (req, res) => {
  const signature = req.headers['x-webhook-signature'];

  // Validar assinatura (recomendado)
  if (!validateSignature(req.body, signature)) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  const { event, instanceId, data } = req.body;

  switch (event) {
    case 'message':
      console.log('Nova mensagem de:', data.pushName);
      console.log('Conteúdo:', data.message?.conversation);
      // Processar mensagem...
      break;

    case 'message.ack':
      console.log('Status atualizado:', data.status);
      // 1=enviado, 2=entregue, 3=lido
      break;

    case 'connection.update':
      console.log('Conexão:', data.state);
      // 'open', 'close', 'connecting'
      break;

    default:
      console.log('Evento:', event);
  }

  // Sempre responda com 200 rapidamente
  res.status(200).json({ received: true });
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});
```

### Exemplo de Servidor (Python/Flask)

```python theme={null}
from flask import Flask, request, jsonify
import hmac
import hashlib

app = Flask(__name__)
WEBHOOK_SECRET = 'seu_secret_para_validacao'

def validate_signature(payload, signature):
    hash = hmac.new(
        WEBHOOK_SECRET.encode(),
        payload.encode(),
        hashlib.sha256
    ).hexdigest()
    return hash == signature

@app.route('/webhook/wapizap', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Webhook-Signature')

    # Validar assinatura (recomendado)
    if not validate_signature(request.get_data(as_text=True), signature):
        return jsonify({'error': 'Invalid signature'}), 401

    data = request.json
    event = data.get('event')

    if event == 'message':
        message_data = data.get('data', {})
        print(f"Nova mensagem de: {message_data.get('pushName')}")
        print(f"Conteúdo: {message_data.get('message', {}).get('conversation')}")

    elif event == 'message.ack':
        print(f"Status atualizado: {data.get('data', {}).get('status')}")

    elif event == 'connection.update':
        print(f"Conexão: {data.get('data', {}).get('state')}")

    return jsonify({'received': True}), 200

if __name__ == '__main__':
    app.run(port=3000)
```

***

## Validação de Assinatura

Para garantir que os webhooks vêm realmente da Wapizap, valide a assinatura:

1. O header `X-Webhook-Signature` contém um HMAC-SHA256
2. É calculado usando o `secret` que você definiu ao criar o webhook
3. O payload é o corpo JSON da requisição

<Warning>
  **Sempre valide a assinatura em produção** para evitar que terceiros enviem requisições falsas para seu endpoint.
</Warning>

***

## Testar Webhook

Teste se seu endpoint está recebendo corretamente:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.wapizap.com/api/v2/webhooks/{webhookId}/test" \
    -H "Authorization: Bearer SEU_TOKEN" \
    -d '{
      "instanceId": "sua-instancia"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch(
    `https://api.wapizap.com/api/v2/webhooks/${webhookId}/test`,
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer SEU_TOKEN'
      },
      body: JSON.stringify({
        instanceId: 'sua-instancia'
      })
    }
  );

  const result = await response.json();
  console.log('Teste:', result.data.success ? 'OK' : 'Falhou');
  ```
</CodeGroup>

***

## Atualizar Webhook

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH "https://api.wapizap.com/api/v2/webhooks/{webhookId}" \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer SEU_TOKEN" \
    -d '{
      "instanceId": "sua-instancia",
      "url": "https://novo-servidor.com/webhook",
      "events": ["message", "message.ack"]
    }'
  ```
</CodeGroup>

***

## Listar Webhooks

<CodeGroup>
  ```bash cURL theme={null}
  curl -X GET "https://api.wapizap.com/api/v2/webhooks?instanceId=sua-instancia" \
    -H "Authorization: Bearer SEU_TOKEN"
  ```
</CodeGroup>

***

## Deletar Webhook

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://api.wapizap.com/api/v2/webhooks/{webhookId}?instanceId=sua-instancia" \
    -H "Authorization: Bearer SEU_TOKEN"
  ```
</CodeGroup>

***

## Melhores Práticas

<CardGroup cols={2}>
  <Card title="Responda Rápido" icon="bolt">
    Sempre responda com HTTP 200 em menos de 5 segundos. Processe dados de forma assíncrona.
  </Card>

  <Card title="Valide Assinaturas" icon="shield">
    Use o `secret` para validar que a requisição vem da Wapizap.
  </Card>

  <Card title="Use HTTPS" icon="lock">
    Sua URL de webhook deve usar HTTPS em produção.
  </Card>

  <Card title="Seja Idempotente" icon="repeat">
    Webhooks podem ser reenviados. Use o `messageId` para detectar duplicatas.
  </Card>
</CardGroup>

### Tratamento de Falhas

Se seu servidor não responder com 2xx:

* **1ª tentativa**: Imediata
* **2ª tentativa**: Após 1 minuto
* **3ª tentativa**: Após 5 minutos
* **4ª tentativa**: Após 30 minutos
* Após 4 falhas, o webhook é marcado como inativo

***

## Desenvolvimento Local

Para testar webhooks em desenvolvimento local, use um túnel:

### ngrok

```bash theme={null}
# Instalar ngrok
npm install -g ngrok

# Criar túnel
ngrok http 3000

# Use a URL gerada (ex: https://abc123.ngrok.io)
```

### Cloudflare Tunnel

```bash theme={null}
# Instalar cloudflared
brew install cloudflared

# Criar túnel
cloudflared tunnel --url http://localhost:3000
```

***

## Debugging

### Verificar Logs

No dashboard, você pode ver o histórico de webhooks enviados:

* Status de entrega
* Payload enviado
* Resposta recebida
* Tempo de resposta

### Problemas Comuns

| Problema            | Solução                                         |
| ------------------- | ----------------------------------------------- |
| Webhook não chega   | Verifique se a URL é acessível publicamente     |
| Timeout             | Processe de forma assíncrona, responda em \< 5s |
| Assinatura inválida | Verifique se o secret está correto              |
| Eventos duplicados  | Use messageId para deduplicação                 |

***

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Enviar Mensagens" icon="message" href="/guides/sending-messages">
    Responda mensagens recebidas via webhook
  </Card>

  <Card title="Tratamento de Erros" icon="bug" href="/guides/error-handling">
    Lide com erros de forma elegante
  </Card>
</CardGroup>
