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

EventoDescripción
booking.createdSe creó una reserva
booking.updatedSe actualizó una reserva
client.createdSe creó un cliente
client.updatedSe actualizó un cliente
payment_request.paidSe pagó una solicitud de pago
payment_request.expiredExpiró una solicitud de pago sin completarse
service.updatedSe actualizó un servicio del catálogo (nombre, precio, duración, estado, palabras clave, categoría)

Patrones wildcard:

PatrónDescripció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:

{
  "type": "booking.created",
  "timestamp": "2026-03-27T14:30:00Z",
  "data": {
    "id": 12345,
    "start_time": "2026-03-28T10:00:00-03:00",
    "end_time": "2026-03-28T10:30:00-03:00",
    "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.

{
  "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:

HeaderDescripción
webhook-idIdentificador único del mensaje (evt_...). Se mantiene en los reintentos.
webhook-timestampUnix timestamp (segundos) del envío.
webhook-signatureFirma 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
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
// 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
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.