---
updatedAt: 2026-10-30T15:06:07.000Z
agentTools:
  projectIndex: https://developers.agendapro.com/llms.txt
---

# Webhooks

Recibe notificaciones en tiempo real cuando ocurren eventos en tu cuenta de AgendaPro.

## Descripción

Los webhooks te permiten recibir notificaciones HTTP POST cuando ocurren eventos en tu cuenta de AgendaPro (por ejemplo, cuando se crea una reserva o se actualiza un cliente).

## Configuración

Puedes registrar y administrar webhooks desde **Configuraciones > Integraciones** en tu cuenta de AgendaPro.

Al crear un webhook necesitas:

* **URL**: el endpoint que recibirá las notificaciones (debe aceptar POST).
* **Eventos**: los tipos de eventos que quieres recibir.

## Eventos disponibles

| Evento                    | Descripción                                                                                         |
| ------------------------- | --------------------------------------------------------------------------------------------------- |
| `booking.created`         | Se creó una reserva                                                                                 |
| `booking.updated`         | Se actualizó una reserva                                                                            |
| `client.created`          | Se creó un cliente                                                                                  |
| `client.updated`          | Se actualizó un cliente                                                                             |
| `payment_request.paid`    | Se pagó una solicitud de pago                                                                       |
| `payment_request.expired` | Expiró una solicitud de pago sin completarse                                                        |
| `service.updated`         | Se actualizó un servicio del catálogo (nombre, precio, duración, estado, palabras clave, categoría) |

Patrones wildcard:

| Patrón              | Descripción                              |
| ------------------- | ---------------------------------------- |
| `*`                 | Todos los eventos                        |
| `booking.*`         | Todos los eventos de reservas            |
| `client.*`          | Todos los eventos de clientes            |
| `payment_request.*` | Todos los eventos de solicitudes de pago |
| `service.*`         | Todos los eventos de servicios           |

## Formato del payload

Cada notificación se envía como un POST con un JSON body:

```json
{
  "type": "booking.created",
  "timestamp": "2026-03-27T14:30:00Z",
  "data": {
    "id": 12345,
    "start_time": "2026-03-28T10:00:00Z",
    "end_time": "2026-03-28T10:30:00Z",
    "service_id": 10,
    "client_id": 42,
    "location_id": 1
  }
}
```

### Payload de `service.updated`

El campo `data` trae los mismos campos escalares que `GET /v3/services/{id}` (incluye `keywords` y `category` con `id` y `name`). Los campos calculados `type`, `online_payment`, `images` y `providers` no vienen en el evento: consulta `GET /v3/services/{id}` si los necesitas.

```json
{
  "type": "service.updated",
  "timestamp": "2026-09-25T14:30:00Z",
  "data": {
    "id": 10,
    "uuid": "svc-uuid-1",
    "name": "Corte clasico",
    "active": true,
    "price": 15000.0,
    "discount": 0.0,
    "has_discount": false,
    "duration": 30,
    "description": "Classic haircut service",
    "keywords": ["Corte", "Corte de pelo"],
    "online_booking": true,
    "outcall": false,
    "is_video": false,
    "category": { "id": 1, "name": "Hair" },
    "location_id": 1,
    "company_id": 100,
    "favorite": false,
    "created_at": "2026-01-01T12:00:00Z",
    "updated_at": "2026-09-25T14:30:00Z"
  }
}
```

## Verificación de firma (HMAC-SHA256)

Cada webhook tiene un **secret** único (prefijo `whsec_`) que se muestra solo una vez al crearlo. Usa este secret para verificar que las notificaciones provienen de AgendaPro.

Cada request incluye tres headers:

| Header              | Descripción                                                                 |
| ------------------- | --------------------------------------------------------------------------- |
| `webhook-id`        | Identificador único del mensaje (`evt_...`). Se mantiene en los reintentos. |
| `webhook-timestamp` | Unix timestamp (segundos) del envío.                                        |
| `webhook-signature` | Firma con formato `v1,<base64>`.                                            |

La firma es el HMAC-SHA256 del string `{webhook-id}.{webhook-timestamp}.{body}` usando el secret como clave, codificado en Base64. Para verificarla, reconstruye ese string con el body **crudo** (sin re-serializar) y compara el resultado con el valor que sigue a `v1,`:

```ruby
# Ruby
msg_id    = request.headers['webhook-id']
timestamp = request.headers['webhook-timestamp']
content   = "#{msg_id}.#{timestamp}.#{request.raw_post}"
expected  = Base64.strict_encode64(OpenSSL::HMAC.digest('SHA256', webhook_secret, content))
if request.headers['webhook-signature'] == "v1,#{expected}"
  # Notificación verificada
end
```

```javascript
// Node.js
const crypto = require('crypto');
const content = `${req.headers['webhook-id']}.${req.headers['webhook-timestamp']}.${rawBody}`;
const expected = crypto.createHmac('sha256', webhookSecret).update(content).digest('base64');
if (req.headers['webhook-signature'] === `v1,${expected}`) {
  // Notificación verificada
}
```

```python
# Python
import base64, hmac, hashlib
content = f"{request.headers['webhook-id']}.{request.headers['webhook-timestamp']}.".encode() + request.body
expected = base64.b64encode(hmac.new(webhook_secret.encode(), content, hashlib.sha256).digest()).decode()
if request.headers.get('webhook-signature') == f"v1,{expected}":
    # Notificación verificada
```

Rechaza notificaciones cuyo `webhook-timestamp` esté muy lejos de la hora actual (por ejemplo, más de 5 minutos) para evitar replays.

## Reintentos

Si tu endpoint no responde con un status `2xx`, AgendaPro reintentará la entrega con backoff exponencial.

Después de múltiples intentos fallidos, el webhook se desactiva automáticamente. Puedes reactivarlo desde la configuración.

## Buenas prácticas

* **Responde rápido**: retorna `200 OK` lo antes posible. Procesa el evento de forma asíncrona si necesitas hacer trabajo pesado.
* **Verifica la firma**: siempre valida el header `webhook-signature` para asegurar que la notificación es legítima.
* **Maneja duplicados**: en casos excepcionales, un evento podría entregarse más de una vez. Usa el header `webhook-id` para idempotencia.