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

# Webhooks

> Recibí notificaciones en tiempo real cuando pasan cosas en tus agentes.

Los webhooks te avisan cuando ocurren eventos: nuevos mensajes, leads capturados, cambios de estado.

## Configurar un webhook

1. Andá a **Settings** → **Webhooks**
2. Click en **"Nuevo Webhook"**
3. Ingresá la URL de tu endpoint
4. Seleccioná los eventos
5. Guardá

## Eventos disponibles

| Evento                         | Cuándo se dispara  |
| ------------------------------ | ------------------ |
| `conversation.created`         | Nueva conversación |
| `conversation.message.created` | Nuevo mensaje      |
| `conversation.status.changed`  | Cambio de estado   |
| `lead.captured`                | Lead capturado     |

## Formato del payload

```json theme={null}
{
  "id": "evt_abc123",
  "type": "conversation.message.created",
  "timestamp": "2024-01-21T15:30:00Z",
  "data": {
    "conversationId": "conv_abc123",
    "messageId": "msg_xyz789",
    "role": "user",
    "content": "Hola, necesito ayuda",
    "contact": {
      "email": "cliente@ejemplo.com"
    }
  }
}
```

## Ejemplos

### Nuevo mensaje

```json theme={null}
{
  "type": "conversation.message.created",
  "data": {
    "conversationId": "conv_abc123",
    "content": "Hola, necesito ayuda",
    "role": "user"
  }
}
```

### Lead capturado

```json theme={null}
{
  "type": "lead.captured",
  "data": {
    "conversationId": "conv_abc123",
    "contact": {
      "email": "lead@ejemplo.com",
      "firstName": "María",
      "phoneNumber": "+5491123456789"
    }
  }
}
```

## Verificar firma

Cada webhook incluye una firma en `X-Horneross-Signature`:

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

function verificarWebhook(payload, signature, secret) {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return signature === expected;
}

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

  if (!verificarWebhook(req.body, signature, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Firma inválida');
  }

  // Procesar evento
  console.log('Evento:', req.body.type);

  res.status(200).send('OK');
});
```

## Reintentos

Si tu endpoint no responde `200`, reintentamos:

| Intento | Delay      |
| ------- | ---------- |
| 1       | Inmediato  |
| 2       | 1 minuto   |
| 3       | 5 minutos  |
| 4       | 30 minutos |
| 5       | 2 horas    |

## Ejemplo: Notificar a Slack

```javascript theme={null}
app.post('/webhook', async (req, res) => {
  const { type, data } = req.body;

  if (type === 'lead.captured') {
    await fetch(process.env.SLACK_WEBHOOK, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        text: `🎯 Nuevo lead: ${data.contact.email}`
      })
    });
  }

  res.status(200).send('OK');
});
```

## Ejemplo: Sincronizar con CRM

```javascript theme={null}
app.post('/webhook', async (req, res) => {
  const { type, data } = req.body;

  if (type === 'conversation.status.changed' && data.newStatus === 'resolved') {
    await crm.closeTicket(data.conversationId);
  }

  res.status(200).send('OK');
});
```

<Tip>
  Usá [webhook.site](https://webhook.site) para testear sin necesidad de un servidor.
</Tip>
