# Webhooks
## ¿Qué son los webhooks?
Son **notificaciones automáticas** que el sistema envía a una URL externa cuando ocurre un evento.
Permite que **otros sistemas reaccionen en tiempo real** a lo que pasa en gestionUltimate.
Ejemplo: cuando hay una venta, el sistema "llama" a un endpoint tuyo con los datos.
## Acceso
Menú → **Configuración → API → Webhooks**
## Configurar un webhook
**Webhooks → Nuevo webhook**
| Campo | Valor |
|-------|-------|
| **Nombre** | Descriptivo |
| **URL del endpoint** | `https://tusistema.com/recibir-webhook` |
| **Eventos a escuchar** | (lista de checkboxes) |
| **Estado** | Activo / Inactivo |
| **Secret** | String secreto para verificar el origen |
## Eventos disponibles
| Evento | Cuándo se dispara |
|--------|-------------------|
| `sale.created` | Se confirma una venta |
| `sale.updated` | Se modifica una venta |
| `sale.cancelled` | Se anula una venta |
| `product.created` | Se crea un producto |
| `product.updated` | Se modifica un producto |
| `stock.low` | Stock baja del umbral de alerta |
| `purchase.received` | Se recibe una compra |
| `payment.received` | Se cobra un pago |
| `contact.created` | Se crea un cliente/proveedor |
## Formato del payload
Cuando ocurre el evento, el sistema envía un POST con JSON:
```json
{
"event": "sale.created",
"timestamp": "2026-05-15T14:23:45Z",
"data": {
"sale_id": 12345,
"invoice_number": "0001-00045678",
"total": 1500.00,
"customer": {
"id": 88,
"name": "Juan Pérez",
"rut": "210333770017"
},
"items": [
{ "product_id": 100, "qty": 2, "price": 750 }
]
},
"signature": "sha256=abc123..."
}
```
## Verificar autenticidad
Para confirmar que el webhook viene del sistema (y no de un atacante):
1. Tu endpoint recibe el header `X-Signature`
2. Calcular HMAC-SHA256 del body con el `secret` configurado
3. Comparar con el header
4. Si coincide: legítimo. Si no: rechazar
Ejemplo en PHP:
```php
$body = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SIGNATURE'];
$expected = hash_hmac('sha256', $body, $secret);
if (hash_equals($expected, $signature)) {
// Procesar webhook
} else {
http_response_code(401);
exit;
}
```
## Reintentos
Si tu endpoint **no responde** o devuelve error:
- El sistema reintenta a los 30 seg, 1 min, 5 min, 15 min, 1 hora
- Después de 5 fallas, marca el webhook como inactivo y avisa al admin
- Las requests fallidas quedan en logs para reenviar manualmente
## Buenas prácticas para tu endpoint
- Responder **rápido** (< 5 seg) con HTTP 200
- Si el procesamiento es lento, **encolar** y procesar async
- **Idempotencia**: si llega el mismo evento 2 veces, procesar solo una (usar `sale_id` como dedupe key)
- **Logging** completo para debug
- **Validar firma** siempre