Skip to Content

API de Webhooks

Los webhooks permiten que tu aplicación reciba callbacks HTTP en tiempo real cuando ocurren eventos en Auris. Cuando un evento suscrito se dispara (p. ej., un usuario inicia sesión, se asigna un rol, una cuenta es bloqueada), Auris envía una solicitud POST a tu URL configurada con un payload JSON que describe el evento.

Cada entrega de webhook está firmada con HMAC-SHA256 usando un secreto de firma por webhook. Esto permite a tu servidor verificar que el payload se originó en Auris y no fue manipulado en tránsito.

Todos los endpoints de gestión de webhooks requieren el permiso manage:webhooks y la cabecera x-tenant.

CRUD de Webhooks

Listar Webhooks

GET/api/webhooksRequires: manage:webhooks

Lista todos los endpoints de webhook configurados para el tenant. Devuelve metadatos del webhook incluyendo los eventos suscritos, el estado activo y las estadísticas de fallos. El secreto de firma nunca se devuelve en las respuestas de lista.

Parámetros de consulta

ParámetroTipoDescripción
pageintegerNúmero de página (predeterminado: 1)
limitintegerElementos por página (predeterminado: 20)

Respuesta exitosa

{ "ok": true, "data": { "data": [ { "id": "whk_abc123", "name": "Production Event Handler", "url": "https://api.yourapp.com/webhooks/auris", "events": ["user.created", "user.updated", "login.success", "login.failed"], "isActive": true, "lastDeliveryAt": "2025-02-18T09:45:00Z", "failureCount": 0, "createdAt": "2025-01-15T10:00:00Z" } ], "pagination": { "page": 1, "limit": 20, "total": 3, "totalPages": 1 } } }

Crear Webhook

POST/api/webhooksRequires: manage:webhooks

Crea un nuevo endpoint de webhook. Se genera automáticamente un secreto de firma con el prefijo whsec_. El secreto se devuelve únicamente en la respuesta de creación — guárdalo de forma segura, ya que no puede recuperarse más adelante (solo rotarse).

Cuerpo de la solicitud

{ "name": "Production Event Handler", "url": "https://api.yourapp.com/webhooks/auris", "events": ["user.created", "user.updated", "user.deleted", "login.success"] }
CampoTipoRequeridoDescripción
namestringSíNombre legible para este webhook
urlstringSíURL del endpoint HTTPS que recibirá las solicitudes POST
eventsstring[]SíArray de tipos de evento a suscribir (ver Tipos de Evento)

Las URLs de webhook deben usar HTTPS. Las URLs con HTTP son rechazadas para evitar que los secretos y datos de usuario se transmitan en texto plano.

Respuesta exitosa

{ "ok": true, "data": { "id": "whk_def456", "name": "Production Event Handler", "url": "https://api.yourapp.com/webhooks/auris", "events": ["user.created", "user.updated", "user.deleted", "login.success"], "secret": "whsec_7f3a8b2c4d5e6f0a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f", "isActive": true, "createdAt": "2025-02-18T10:00:00Z" } }

El campo secret solo se devuelve en la respuesta de creación y después de la rotación del secreto. Cópialo y guárdalo inmediatamente en un lugar seguro (p. ej., variable de entorno o gestor de secretos). No puede recuperarse de nuevo.

Códigos de error

CódigoHTTPDescripción
VALIDATION_ERROR400Faltan campos requeridos o los tipos de evento son inválidos
INVALID_URL400La URL no es un endpoint HTTPS válido
INVALID_EVENTS400Uno o más tipos de evento no son reconocidos

Obtener Webhook

GET/api/webhooks/[id]Requires: manage:webhooks

Recupera un webhook individual por ID. Devuelve todos los detalles del webhook excluyendo el secreto de firma.

Respuesta exitosa

{ "ok": true, "data": { "id": "whk_abc123", "name": "Production Event Handler", "url": "https://api.yourapp.com/webhooks/auris", "events": ["user.created", "user.updated", "login.success", "login.failed"], "isActive": true, "failureCount": 0, "lastDeliveryAt": "2025-02-18T09:45:00Z", "createdAt": "2025-01-15T10:00:00Z", "updatedAt": "2025-02-10T14:00:00Z" } }

Actualizar Webhook

PATCH/api/webhooks/[id]Requires: manage:webhooks

Actualiza el nombre, la URL, los eventos suscritos o el estado activo de un webhook. Todos los campos son opcionales — solo se actualizan los campos proporcionados.

Cuerpo de la solicitud

{ "name": "Production Event Handler v2", "events": ["user.created", "user.updated", "user.deleted", "login.success", "login.failed", "role.assigned"], "isActive": true }

Respuesta exitosa

{ "ok": true, "data": { "id": "whk_abc123", "name": "Production Event Handler v2", "url": "https://api.yourapp.com/webhooks/auris", "events": ["user.created", "user.updated", "user.deleted", "login.success", "login.failed", "role.assigned"], "isActive": true, "updatedAt": "2025-02-18T11:00:00Z" } }

Eliminar Webhook

DELETE/api/webhooks/[id]Requires: manage:webhooks

Elimina un endpoint de webhook. Las entregas pendientes para este webhook son canceladas. El historial de entregas se conserva con fines de auditoría.

Respuesta exitosa

{ "ok": true, "data": { "deleted": true } }

Rotación de Secreto

POST/api/webhooks/[id]/rotate-secretRequires: manage:webhooks

Genera un nuevo secreto de firma para el webhook. El secreto antiguo se invalida inmediatamente. El nuevo secreto se devuelve en la respuesta. Todas las entregas posteriores serán firmadas con el nuevo secreto.

Solicitud: No se requiere cuerpo.

Respuesta exitosa

{ "ok": true, "data": { "secret": "whsec_9a8b7c6d5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a" } }

Después de rotar un secreto, actualiza inmediatamente tu manejador de webhook para usar el nuevo secreto. Las entregas en vuelo en el momento de la rotación pueden seguir usando el secreto antiguo. Buenas prácticas: admite la verificación tanto con el secreto antiguo como con el nuevo durante un breve período de gracia durante la rotación.

Pruebas

POST/api/webhooks/[id]/testRequires: manage:webhooks

Envía una entrega de prueba a la URL del webhook. Auris envía un evento webhook.test con un payload de ejemplo. La entrega se registra en el historial de entregas. Úsalo para verificar que tu endpoint es accesible y verifica las firmas correctamente.

Solicitud: No se requiere cuerpo.

Respuesta exitosa

{ "ok": true, "data": { "deliveryId": "del_xyz789", "statusCode": 200, "success": true, "responseTime": 142 } }

Payload del evento de prueba (lo que recibe tu endpoint)

{ "event": "webhook.test", "timestamp": "2025-02-18T10:30:00Z", "tenant": "acme-corp", "data": { "message": "This is a test delivery from Auris.", "webhookId": "whk_abc123" } }

Códigos de error

CódigoHTTPDescripción
DELIVERY_FAILED502El endpoint del webhook devolvió un código de estado no 2xx
ENDPOINT_UNREACHABLE502No se pudo conectar a la URL del webhook (fallo DNS, timeout, etc.)

Historial de Entregas

Listar Entregas

GET/api/webhooks/[id]/deliveriesRequires: manage:webhooks

Lista los intentos de entrega de un webhook, ordenados por fecha descendente. Cada entrega incluye el tipo de evento, el código de estado HTTP, el tiempo de respuesta y si la entrega fue exitosa. Las entregas reintentadas son entradas separadas vinculadas al mismo evento.

Parámetros de consulta

ParámetroTipoDescripción
pageintegerNúmero de página (predeterminado: 1)
limitintegerElementos por página (predeterminado: 20)

Respuesta exitosa

{ "ok": true, "data": { "data": [ { "id": "del_abc123", "event": "user.created", "statusCode": 200, "success": true, "responseTime": 89, "attempts": 1, "payload": { "event": "user.created", "timestamp": "2025-02-18T09:45:00Z", "tenant": "acme-corp", "data": { "userId": "usr_abc123", "email": "[email protected]" } }, "createdAt": "2025-02-18T09:45:00Z", "completedAt": "2025-02-18T09:45:01Z" }, { "id": "del_def456", "event": "login.failed", "statusCode": 500, "success": false, "responseTime": 2034, "attempts": 3, "error": "Server returned 500 Internal Server Error", "payload": { "event": "login.failed", "timestamp": "2025-02-18T09:30:00Z", "tenant": "acme-corp", "data": { "email": "[email protected]", "reason": "INVALID_CREDENTIALS", "ipAddress": "203.0.113.50" } }, "createdAt": "2025-02-18T09:30:00Z", "completedAt": "2025-02-18T09:35:12Z" } ], "pagination": { "page": 1, "limit": 20, "total": 156, "totalPages": 8 } } }

Reintentar Entrega

POST/api/webhooks/[id]/deliveries/[deliveryId]/retryRequires: manage:webhooks

Reintenta manualmente una entrega fallida. El payload original se reenvía con una nueva firma. Crea una nueva entrada de entrega vinculada al mismo evento.

Solicitud: No se requiere cuerpo.

Respuesta exitosa

{ "ok": true, "data": { "deliveryId": "del_ghi789", "statusCode": 200, "success": true, "responseTime": 95 } }

Códigos de error

CódigoHTTPDescripción
NOT_FOUND404La entrega no existe
ALREADY_SUCCESSFUL400La entrega ya fue exitosa y no necesita reintentarse

Tipos de Evento

Auris emite los siguientes eventos de webhook. Suscríbete a los eventos relevantes para tu caso de uso.

Eventos de Autenticación

EventoDescripción
login.successEl usuario se autenticó correctamente (cualquier método)
login.failedEl intento de autenticación falló (credenciales incorrectas, cuenta bloqueada, etc.)
signup.completedNueva cuenta de usuario registrada
logout.completedEl usuario cerró sesión (sesión invalidada)
token.refreshedEl access token fue renovado
password.changedEl usuario cambió su contraseña
password.reset_requestedSe envió el correo de restablecimiento de contraseña
magic_link.sentSe envió el correo con magic link
magic_link.verifiedSe utilizó el magic link para autenticarse

Eventos de Gestión de Usuarios

EventoDescripción
user.createdNueva cuenta de usuario creada (mediante API de administración o registro)
user.updatedSe modificaron campos del perfil del usuario
user.deletedLa cuenta del usuario fue eliminada de forma lógica
user.enabledUn usuario previamente deshabilitado fue reactivado
user.disabledLa cuenta del usuario fue deshabilitada
user.email_verifiedEl usuario verificó su dirección de correo electrónico

Eventos de Roles y Permisos

EventoDescripción
role.createdNuevo rol creado
role.updatedMetadatos o permisos del rol modificados
role.deletedRol eliminado
role.assignedRol asignado a un usuario
role.unassignedRol eliminado de un usuario

Eventos de Seguridad

EventoDescripción
mfa.enabledEl usuario activó un método 2FA (TOTP, SMS o WebAuthn)
mfa.disabledEl usuario desactivó un método 2FA
account.lockedLa cuenta fue bloqueada por detección de fuerza bruta
account.unlockedEl bloqueo de la cuenta fue eliminado
suspicious_login.detectedSe detectó actividad de inicio de sesión sospechosa (nuevo dispositivo, viaje imposible, etc.)

Eventos de Organización

EventoDescripción
organization.createdNueva organización creada
organization.updatedMetadatos de la organización modificados
organization.member_addedUsuario añadido a una organización
organization.member_removedUsuario eliminado de una organización
organization.invitation_sentCorreo de invitación enviado

Eventos del Sistema

EventoDescripción
webhook.testEntrega de prueba disparada desde la Consola o la API

Formato del Payload del Webhook

Cada entrega de webhook envía una solicitud POST con un cuerpo JSON:

{ "event": "user.created", "timestamp": "2025-02-18T10:00:00Z", "tenant": "acme-corp", "data": { "userId": "usr_abc123", "email": "[email protected]", "firstName": "Alice", "lastName": "Smith" } }
CampoTipoDescripción
eventstringEl tipo de evento (p. ej., user.created)
timestampstringMarca de tiempo ISO 8601 de cuándo ocurrió el evento
tenantstringIdentificador del tenant donde ocurrió el evento
dataobjectDatos del payload específicos del evento

La forma de data varía según el tipo de evento. Los eventos de usuario incluyen campos del usuario, los eventos de rol incluyen detalles del rol y los eventos de inicio de sesión incluyen el email y la dirección IP.

Verificación de Firma

Cada entrega incluye dos cabeceras para la verificación de firma:

CabeceraDescripción
X-Webhook-SignatureFirma HMAC-SHA256 del cuerpo de la solicitud
X-Webhook-TimestampMarca de tiempo Unix (segundos) de cuándo se generó la firma

Algoritmo de Verificación

  1. Lee el cuerpo de la solicitud sin procesar como cadena UTF-8 (no analices el JSON primero).
  2. Lee la cabecera X-Webhook-Timestamp.
  3. Concatena: timestamp + "." + body
  4. Calcula el HMAC-SHA256 de la cadena concatenada usando el secreto de firma de tu webhook.
  5. Compara el resultado en hexadecimal con la cabecera X-Webhook-Signature usando una comparación en tiempo constante.
  6. Opcionalmente, rechaza las entregas cuya marca de tiempo sea superior a 5 minutos (para prevenir ataques de repetición).

Ejemplo de Verificación en Node.js

import crypto from 'crypto'; function verifyWebhookSignature(rawBody, signature, timestamp, secret) { // 1. Comprobar la frescura de la marca de tiempo (opcional pero recomendado) const currentTime = Math.floor(Date.now() / 1000); if (Math.abs(currentTime - parseInt(timestamp)) > 300) { throw new Error('La marca de tiempo del webhook es demasiado antigua'); } // 2. Calcular la firma esperada const signedPayload = `${timestamp}.${rawBody}`; const expectedSignature = crypto .createHmac('sha256', secret) .update(signedPayload) .digest('hex'); // 3. Comparación en tiempo constante const expected = Buffer.from(expectedSignature, 'hex'); const received = Buffer.from(signature, 'hex'); if (expected.length !== received.length) { return false; } return crypto.timingSafeEqual(expected, received); } // Manejador Express.js app.post('/webhooks/auris', express.raw({ type: 'application/json' }), (req, res) => { const signature = req.headers['x-webhook-signature']; const timestamp = req.headers['x-webhook-timestamp']; const rawBody = req.body.toString('utf-8'); if (!verifyWebhookSignature(rawBody, signature, timestamp, process.env.AURIS_WEBHOOK_SECRET)) { return res.status(401).json({ error: 'Firma inválida' }); } const event = JSON.parse(rawBody); console.log(`Evento recibido ${event.event}:`, event.data); // Procesar el evento... res.status(200).json({ received: true }); });

Ejemplo de Verificación en Python

import hmac import hashlib import time def verify_webhook_signature(raw_body: bytes, signature: str, timestamp: str, secret: str) -> bool: # Comprobar la frescura de la marca de tiempo current_time = int(time.time()) if abs(current_time - int(timestamp)) > 300: return False # Calcular la firma esperada signed_payload = f"{timestamp}.{raw_body.decode('utf-8')}" expected = hmac.new( secret.encode('utf-8'), signed_payload.encode('utf-8'), hashlib.sha256 ).hexdigest() # Comparación en tiempo constante return hmac.compare_digest(expected, signature)

El SDK @auris/js incluye una utilidad integrada de verificación de webhooks: import { verifyWebhookSignature } from '@auris/js'. Gestiona la validación de la marca de tiempo, el cálculo HMAC y la comparación en tiempo constante. Consulta la documentación del SDK para más detalles.

Comportamiento de Entrega

Tiempos de Espera

Auris espera hasta 30 segundos para recibir una respuesta de tu endpoint de webhook. Si tu endpoint no responde dentro de este período, la entrega se marca como fallida.

Política de Reintentos

Las entregas fallidas se reintentan con retroceso exponencial:

IntentoDemora
1.er reintento1 minuto
2.º reintento5 minutos
3.er reintento30 minutos

Tras 3 intentos de reintento fallidos, la entrega se marca como permanentemente fallida. Aún puede reintentarse manualmente mediante la API o la Consola.

Desactivación Automática

Si un webhook acumula 10 fallos consecutivos (en cualquier entrega), se desactiva automáticamente (isActive: false). Deberás corregir el endpoint y reactivar manualmente el webhook mediante PATCH /api/webhooks/[id] con { "isActive": true }.

Idempotencia

Tu manejador de webhook debe ser idempotente. En casos raros (problemas de red, reintentos), el mismo evento puede entregarse más de una vez. Usa los campos timestamp y event para deduplicar si es necesario.

Buenas Prácticas

  1. Responde rápidamente: Devuelve un código de estado 2xx lo antes posible. Procesa el evento de forma asíncrona (p. ej., usando una cola) en lugar de hacer trabajo pesado en el manejador de la solicitud.
  2. Verifica las firmas: Verifica siempre la firma HMAC-SHA256 antes de procesar el payload. Nunca confíes en un payload de webhook sin verificación.
  3. Usa HTTPS: Auris rechaza URLs de webhook sin HTTPS. Usa un certificado TLS válido.
  4. Gestiona los reintentos: Diseña tu manejador para ser idempotente. El mismo evento puede entregarse más de una vez.
  5. Rota los secretos periódicamente: Usa el endpoint de rotación de secretos para generar un nuevo secreto de firma con regularidad (p. ej., trimestralmente).
  6. Monitorea las entregas: Consulta el historial de entregas en la Consola o mediante la API para asegurarte de que tu endpoint está funcionando correctamente.

Relacionado