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

# Webhooks

> Receba eventos em tempo real da sua conta WhatsApp

Webhooks permitem que você receba notificações em tempo real quando eventos
ocorrem na sua conta WhatsApp, como novas mensagens, atualizações de status e
mudanças de conexão.

## Como Funciona

```mermaid theme={"system"}
sequenceDiagram
    participant WhatsApp
    participant Oxenty API
    participant Seu Servidor
    
    WhatsApp->>Oxenty API: Evento (mensagem recebida)
    Oxenty API->>Seu Servidor: POST /seu-webhook
    Seu Servidor->>Oxenty API: 200 OK
```

Quando um evento ocorre, a Oxenty API envia um `POST` request para a URL
configurada com os dados do evento.

***

## Configurando um Webhook

### Via Dashboard

1. Acesse [oxenty.api.br/login](https://oxenty.api.br/login)
2. Crie/edite uma **sessão**
3. Configure:

* **Webhook URL**: Endpoint que receberá os eventos
* **Webhook Events**: Quais eventos deseja receber

### Via API

Webhooks são configurados **por sessão**.

#### Criar sessão já com webhook

```bash theme={"system"}
curl -X POST "https://api.oxenty.api.br/api/sessions" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "minha-sessao",
    "webhookUrl": "https://seu-servidor.com/webhook",
    "webhookEvents": [
      "message.received",
      "message.sent",
      "message.delivered",
      "message.read",
      "session.connected",
      "session.disconnected"
    ]
  }'
```

#### Atualizar webhook de uma sessão existente

```bash theme={"system"}
curl -X PUT "https://api.oxenty.api.br/api/sessions/{sessionId}" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://seu-servidor.com/webhook",
    "webhookEvents": [
      "message.received",
      "message.sent",
      "session.status_changed"
    ]
  }'
```

**Resposta:**

```json theme={"system"}
{
  "id": "sess_abc123",
  "name": "minha-sessao",
  "status": "DISCONNECTED",
  "webhookUrl": "https://seu-servidor.com/webhook",
  "webhookEvents": ["message.received", "message.sent", "..."],
  "webhookSecret": "whsec_xxxxxxxxxxxxxxxx",
  "hasWebhook": true
}
```

<Warning>
  Guarde o `webhookSecret` em local seguro. Ele é usado para validar a autenticidade
  dos webhooks.
</Warning>

***

## Eventos Disponíveis

### Mensagens

| Evento              | Descrição                       |
| ------------------- | ------------------------------- |
| `message.received`  | Nova mensagem recebida          |
| `message.sent`      | Mensagem enviada com sucesso    |
| `message.delivered` | Mensagem entregue               |
| `message.read`      | Mensagem lida                   |
| `message.failed`    | Falha ao enviar mensagem        |
| `message.revoked`   | Mensagem apagada pelo remetente |

### Sessões

| Evento                   | Descrição                      |
| ------------------------ | ------------------------------ |
| `session.connected`      | Sessão conectou ao WhatsApp    |
| `session.disconnected`   | Sessão desconectou             |
| `session.qr_code`        | QR Code disponível             |
| `session.qr_updated`     | QR Code atualizado/rotacionado |
| `session.status_changed` | Mudança de status da sessão    |

### Grupos

| Evento                      | Descrição                      |
| --------------------------- | ------------------------------ |
| `group.created`             | Grupo criado                   |
| `group.participant.added`   | Participante adicionado        |
| `group.participant.removed` | Participante removido          |
| `group.updated`             | Metadados do grupo atualizados |

### Contatos

| Evento             | Descrição                          |
| ------------------ | ---------------------------------- |
| `contact.updated`  | Dados do contato atualizados       |
| `presence.update`  | Status online/offline do contato   |
| `presence.updated` | Atualização de presença (variação) |

***

## Payload do Webhook

Todos os webhooks seguem este formato:

```json theme={"system"}
{
  "id": "evt_xyz789",
  "type": "message.received",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "sessionId": "sess_abc123",
  "data": {
    // Dados específicos do evento
  }
}
```

### Exemplo: message.received

```json theme={"system"}
{
  "id": "evt_xyz789",
  "type": "message.received",
  "timestamp": "2024-01-15T10:30:00.000Z",
  "sessionId": "sess_abc123",
  "data": {
    "messageId": "msg_123",
    "from": "5511999999999@s.whatsapp.net",
    "fromName": "João Silva",
    "type": "text",
    "text": "Olá, tudo bem?",
    "timestamp": "2024-01-15T10:30:00.000Z",
    "isGroup": false
  }
}
```

### Exemplo: message.status

```json theme={"system"}
{
  "id": "evt_abc456",
  "type": "message.status",
  "timestamp": "2024-01-15T10:31:00.000Z",
  "sessionId": "sess_abc123",
  "data": {
    "messageId": "msg_456",
    "to": "5511888888888@s.whatsapp.net",
    "status": "read",
    "timestamp": "2024-01-15T10:31:00.000Z"
  }
}
```

### Exemplo: session.disconnected

```json theme={"system"}
{
  "id": "evt_def789",
  "type": "session.disconnected",
  "timestamp": "2024-01-15T10:35:00.000Z",
  "sessionId": "sess_abc123",
  "data": {
    "reason": "logged_out",
    "message": "Usuário deslogou do WhatsApp Web"
  }
}
```

***

## Validando Webhooks

Para garantir que o webhook veio da Oxenty API, valide a assinatura:

### Header de Assinatura

```
X-Oxenty-Signature: sha256=abc123...
X-Oxenty-Timestamp: 1704067200
```

### Validação em Node.js

```typescript theme={"system"}
import crypto from 'crypto';

function validateWebhook(
  payload: string,
  signature: string,
  timestamp: string,
  secret: string
): boolean {
  const signedPayload = `${timestamp}.${payload}`;
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(signedPayload)
    .digest('hex');
  
  const receivedSignature = signature.replace('sha256=', '');
  
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(receivedSignature)
  );
}

// Uso no Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const signature = req.headers['x-oxenty-signature'] as string;
  const timestamp = req.headers['x-oxenty-timestamp'] as string;
  const payload = req.body.toString();
  
  if (!validateWebhook(payload, signature, timestamp, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  
  const event = JSON.parse(payload);
  // Processar evento...
  
  res.status(200).send('OK');
});
```

### Validação em Python

```python theme={"system"}
import hmac
import hashlib
from flask import Flask, request

app = Flask(__name__)
WEBHOOK_SECRET = 'whsec_xxxxxxxx'

def validate_webhook(payload, signature, timestamp, secret):
    signed_payload = f"{timestamp}.{payload}"
    expected_signature = hmac.new(
        secret.encode(),
        signed_payload.encode(),
        hashlib.sha256
    ).hexdigest()
    
    received_signature = signature.replace('sha256=', '')
    
    return hmac.compare_digest(expected_signature, received_signature)

@app.route('/webhook', methods=['POST'])
def webhook():
    signature = request.headers.get('X-Oxenty-Signature')
    timestamp = request.headers.get('X-Oxenty-Timestamp')
    payload = request.get_data(as_text=True)
    
    if not validate_webhook(payload, signature, timestamp, WEBHOOK_SECRET):
        return 'Invalid signature', 401
    
    event = request.get_json()
    # Processar evento...
    
    return 'OK', 200
```

***

## Retries e Falhas

Se seu endpoint retornar erro (status >= 400) ou timeout, a Oxenty API fará
retries automáticos:

| Tentativa | Delay      |
| --------- | ---------- |
| 1         | Imediato   |
| 2         | 1 minuto   |
| 3         | 5 minutos  |
| 4         | 30 minutos |
| 5         | 2 horas    |

Após 5 falhas consecutivas, o webhook é marcado como **inativo** e você
receberá um email de notificação.

<Note>
  Responda com `200 OK` o mais rápido possível. Processe eventos de forma
  assíncrona para evitar timeouts.
</Note>

***

## Boas Práticas

<AccordionGroup>
  <Accordion icon="bolt" title="Responda rapidamente">
    Retorne `200 OK` imediatamente e processe o evento de forma assíncrona
    (usando filas como Redis, RabbitMQ, etc.).
  </Accordion>

  <Accordion icon="shield" title="Sempre valide a assinatura">
    Nunca processe webhooks sem validar a assinatura para evitar ataques.
  </Accordion>

  <Accordion icon="database" title="Implemente idempotência">
    Use o `id` do evento para evitar processar o mesmo evento duas vezes
    (pode haver retries).
  </Accordion>

  <Accordion icon="lock" title="Use HTTPS">
    Sempre use URLs HTTPS para receber webhooks. HTTP não é aceito em produção.
  </Accordion>
</AccordionGroup>

***

## Testando Webhooks

### Teste rápido

1. Configure `webhookUrl` em uma sessão (via `POST /sessions` ou `PUT /sessions/{id}`)
2. Dispare um evento (ex.: enviar mensagem via `POST /messages/text`)
3. Verifique se seu endpoint recebeu o payload

### Ferramentas Úteis

* [webhook.site](https://webhook.site) - Endpoint temporário para testes
* [ngrok](https://ngrok.com) - Expor localhost para a internet
* [Hookdeck](https://hookdeck.com) - Proxy e debug de webhooks

***

## Gerenciando Webhooks

### Listar configurações

```bash theme={"system"}
curl -X GET "https://api.oxenty.api.br/api/sessions?page=1&limit=20" \
  -H "X-API-Key: YOUR_API_KEY"
```

### Atualizar Webhook (por sessão)

```bash theme={"system"}
curl -X PUT "https://api.oxenty.api.br/api/sessions/sess_abc123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://seu-servidor.com/webhook",
    "webhookEvents": ["message.received"],
    "regenerateSecret": true
  }'
```

### Desativar Webhook

```bash theme={"system"}
curl -X PUT "https://api.oxenty.api.br/api/sessions/sess_abc123" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": null,
    "webhookEvents": []
  }'
```
