Files
SKEEN-Proyecto/docs/producto/webhooks.md

3.6 KiB

Webhooks salientes

Notificación de eventos de la clínica hacia sistemas externos, con patrón outbox + cron + reintentos + bitácora. Sin webhooks activos suscritos no se crea ninguna fila ni se envía nada (cero impacto).

Modelos

skeen.webhook

Campo Descripción
name, url Nombre y URL destino
eventos Claves separadas por coma; vacío = todos
activo Habilitado
secreto Con este secreto se firma cada entrega
headers Cabeceras extra (JSON, opcional)
notas, creado_por_login Metadatos
ultima_entrega_at Última entrega correcta
fallos_consecutivos Se desactiva tras N fallos (default 20, configurable en skeen.webhooks.fallos_max)

skeen.webhook.evento (outbox)

webhook_id, evento, payload (JSON), estado (pendiente|enviado|fallido|descartado), intentos, proximo_intento, respuesta_codigo, respuesta_texto, enviado_at, clave_unica (idempotencia por evento+objeto).

Catálogo de eventos

Evento Cuándo se emite
cita.creada Al crear una cita
cita.confirmada state → confirmed
cita.cancelada state → cancelled
cita.no_show state → no_show
cita.completada state → done
venta.pagada state → paid
venta.cancelada state → cancelled o refunded
pago.registrado Al crear un skeen.pago
paciente.creado Al crear un res.partner con is_patient
membresia.renovada action_renovar
formulario.llenado estado → llenado
compra.recibida estado → recibida/recibida_parcial

Ejemplo de payload (cita.creada)

{
  "id": 123,
  "reference": "CITA-0123",
  "state": "pending",
  "date": "2026-10-20",
  "patient_id": 55,
  "patient": "María López",
  "service_id": 7,
  "servicio": "Limpieza facial",
  "doctor": "Dra. Pérez"
}

Entrega

Cron cada 5 minutos (skeen.webhook.service._cron_tick) que toma los pendientes vencidos y hace POST JSON con:

Cabecera Valor
X-Skeen-Event Clave del evento
X-Skeen-Delivery UUID de la entrega
X-Skeen-Signature sha256=<HMAC-SHA256 del cuerpo con el secreto>
  • Timeouts cortos (5 s conexión / 15 s lectura).
  • Reintentos con backoff: 1, 5, 30 min, 2 h, 6 h (tope 5 intentos); al agotarlos el evento queda fallido.
  • Tras N fallos consecutivos (default 20) el webhook se desactiva.

Verificar la firma (Python)

import hashlib, hmac
firma = request.headers['X-Skeen-Signature']          # 'sha256=...'
esperada = 'sha256=' + hmac.new(
    SECRETO.encode(), request.body, hashlib.sha256).hexdigest()
assert hmac.compare_digest(firma, esperada)

Verificar la firma (Node.js)

const crypto = require('crypto');
const esperada = 'sha256=' + crypto
  .createHmac('sha256', SECRETO)
  .update(req.rawBody)
  .digest('hex');

Endpoints

Método Ruta Acceso
GET/POST /skeen/frontend/v1/webhooks permiso webhooks.editar (admin/gerencia)
PUT/DELETE /skeen/frontend/v1/webhooks/<id> idem
GET /skeen/frontend/v1/webhooks/<id>/eventos idem (filtra por estado, evento, limit)
POST /skeen/frontend/v1/webhooks/<id>/probar idem (evento de prueba)
POST /skeen/frontend/v1/webhook_eventos/<id>/reintentar idem

UI

Configuración → pestaña Webhooks (admin/gerencia): CRUD, selector de eventos, secreto (generado o propio), visor del payload de ejemplo, log de entregas con estado/código/fecha, reintento manual y "probar".