Webhooks
Webhooks
Sección titulada «Webhooks»Los webhooks permiten que tu sistema reciba notificaciones HTTP automáticas cuando ocurren eventos importantes en Redcumbre. En lugar de consultar periódicamente nuestra API (polling), configurás una URL y nosotros te avisamos cuando algo sucede.
Flujo de Webhooks
Sección titulada «Flujo de Webhooks»Tu Sistema Redcumbre Evento │ │ │ │── Configura webhook URL ─────▶│ │ │ (POST /config/webhooks) │ │ │◀── Secret HMAC ──────────────│ │ │ │ │ │ │◀─────── Ocurre evento ─────│ │ │ (BHE emitida, etc) │ │ │ │ │◀── POST webhook ─────────────│ │ │ (JSON + firma HMAC) │ │ │ │ │ │── 200 OK ────────────────────▶│ │ │ │── Log: WEBHOOK_SENT │Características:
- Procesamiento asíncrono (no bloquea la operación principal)
- Reintentos automáticos con backoff exponencial
- Firma HMAC-SHA256 para validar autenticidad
- Headers personalizados para autenticación
Configuración de Webhooks
Sección titulada «Configuración de Webhooks»La configuración de webhooks se realiza desde el panel de administración de Redcumbre:
Administración → Configuración → Webhooks
Opciones de Configuración
Sección titulada «Opciones de Configuración»| Campo | Descripción |
|---|---|
| URL del Webhook | URL HTTPS donde recibirás las notificaciones |
| Headers Personalizados | Headers HTTP adicionales para autenticación (ej: Authorization: Bearer token) |
| Eventos Habilitados | Selecciona qué eventos quieres recibir |
| Activo | Habilitar/deshabilitar el envío de webhooks |
Secret HMAC
Sección titulada «Secret HMAC»Al crear la configuración, el sistema genera automáticamente un secret de 64 caracteres hexadecimales. Este secret se usa para firmar los webhooks con HMAC-SHA256.
Catálogo de Eventos
Sección titulada «Catálogo de Eventos»Eventos DTE (Documentos Tributarios)
Sección titulada «Eventos DTE (Documentos Tributarios)»| Evento | Descripción |
|---|---|
tokenizacion.completada | Emisor autorizado exitosamente vía SII |
emisor.revocado | Emisor revocado (DTE o Tributario) |
bhe.emitida | Boleta de Honorarios emitida al SII |
bhe.emision_terminada | PDF SII disponible (modos SINC_PARCIAL/ASINCRONO) |
bhe.pdf_sii_fallido | PDF SII falló después de 7 días de reintentos |
bhe.emision_fallida | Emisión asíncrona falló después de 7 horas |
Eventos ONEXO
Sección titulada «Eventos ONEXO»| Evento | Descripción |
|---|---|
onexo.postulacion-completada | Postulante completó el flujo de entrevista |
onexo.postulacion-aprobada | Revisor aprobó la postulación |
onexo.postulacion-rechazada | Revisor rechazó la postulación |
onexo.aclaracion-solicitada | Revisor solicitó aclaraciones adicionales |
onexo.curso-aprobado | Curso completado y aprobado |
Eventos ValidaFirma
Sección titulada «Eventos ValidaFirma»| Evento | Descripción |
|---|---|
validafirma.documento-completado | Documento firmado exitosamente |
Payloads de Eventos
Sección titulada «Payloads de Eventos»tokenizacion.completada
Sección titulada «tokenizacion.completada»Se envía cuando un usuario completa el flujo de autorización de credenciales SII.
{ "event": "tokenizacion.completada", "tenantId": "8", "sessionId": "c6c53392-bdb0-4053-8b9d-5b34296d63a3", "code": "83aK0esV0V21u8-krvuMiXx1OqheSVy56E6tBG3OjX8", "emisorId": "cmikf6ei00001sek0mxzcf668", "rut": "77438768-4", "tipoAutenticacion": "CLAVE_TRIBUTARIA", "tipoEmisor": "tributario", "correlationId": "mi-referencia-123", "lookupData": { "razonSocial": "EMPRESA EJEMPLO SPA", "giro": "SERVICIOS INFORMATICOS", "direcciones": [ { "ciudad": "SANTIAGO", "comuna": "PROVIDENCIA", "direccion": "AV. PROVIDENCIA 1234" } ] }, "timestamp": "2025-12-10T15:30:00Z"}emisor.revocado
Sección titulada «emisor.revocado»Se envía cuando un emisor es revocado (por el usuario o administrador).
{ "event": "emisor.revocado", "data": { "emisorId": "cmikf6ei00001sek0mxzcf668", "emisorType": "tributario", "rut": "77438768-4", "razonSocial": "EMPRESA EJEMPLO SPA", "tenantId": "8", "revokedBy": "USER", "motivoRevocacion": null }, "timestamp": "2025-12-10T15:30:00Z"}| Campo | Descripción |
|---|---|
emisorType | tributario o dte |
revokedBy | USER (usuario final) o ADMIN (administrador) |
motivoRevocacion | Motivo de revocación (solo cuando revokedBy: ADMIN) |
bhe.emitida
Sección titulada «bhe.emitida»Se envía inmediatamente después de emitir una BHE exitosamente.
{ "event": "bhe.emitida", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "emisor": { "rut": "78012039-8", "razonSocial": "JUAN PÉREZ GONZÁLEZ" }, "destinatario": { "rut": "12345678-9", "nombre": "EMPRESA CLIENTE SA", "sinDestinatario": false }, "montos": { "bruto": 225000, "ppm": 30938, "liquido": 194062 }, "tipoRetencion": "RETRECEPTOR", "canalEmision": "API_SYNC", "correlationId": "mi-referencia-123", "sandbox": false, "timestamp": "2025-12-10T15:30:00Z"}bhe.emision_terminada
Sección titulada «bhe.emision_terminada»Se envía cuando el PDF SII está disponible (modos SINC_PARCIAL y ASINCRONO).
{ "event": "bhe.emision_terminada", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "pdfInternoUrl": "https://storage.googleapis.com/.../interno.pdf", "pdfSiiUrl": "https://storage.googleapis.com/.../sii.pdf", "estadoPdfSii": "DISPONIBLE", "timestamp": "2025-12-10T15:35:00Z"}bhe.pdf_sii_fallido
Sección titulada «bhe.pdf_sii_fallido»Se envía después de 7 días de reintentos fallidos para descargar el PDF SII.
{ "event": "bhe.pdf_sii_fallido", "tenantId": "8", "bheId": "cm5abc123", "folioSii": "12345678", "intentosRealizados": 30, "primerIntento": "2025-12-01T15:30:00Z", "ultimoIntento": "2025-12-08T15:30:00Z", "ultimoError": "SII_PDF_NO_DISPONIBLE", "timestamp": "2025-12-08T15:30:00Z"}bhe.emision_fallida
Sección titulada «bhe.emision_fallida»Se envía cuando una emisión asíncrona falla después de ~7 horas de reintentos.
{ "event": "bhe.emision_fallida", "tenantId": "8", "correlationId": "mi-referencia-123", "intentosRealizados": 15, "primerIntento": "2025-12-08T10:00:00Z", "ultimoIntento": "2025-12-08T17:00:00Z", "ultimoError": "SII_SERVICE_UNAVAILABLE", "timestamp": "2025-12-08T17:00:00Z"}onexo.postulacion-completada
Sección titulada «onexo.postulacion-completada»Se envía cuando un postulante completa el flujo de entrevista virtual.
{ "event": "onexo.postulacion-completada", "tenantId": "8", "postulacionId": "cm5xyz789", "procesoId": "cm5proceso123", "procesoTitulo": "Captador de Aportes RM", "persona": { "rut": "12345678-9", "nombreCompleto": "Juan Pérez González", "email": "juan.perez@email.com" }, "timestamp": "2025-12-10T15:30:00Z"}onexo.postulacion-aprobada
Sección titulada «onexo.postulacion-aprobada»Se envía cuando un revisor aprueba una postulación.
{ "event": "onexo.postulacion-aprobada", "tenantId": "8", "postulacionId": "cm5xyz789", "procesoId": "cm5proceso123", "procesoTitulo": "Captador de Aportes RM", "persona": { "rut": "12345678-9", "nombreCompleto": "Juan Pérez González", "email": "juan.perez@email.com" }, "revisor": { "userId": "zitadel-user-123", "nombre": "María García" }, "timestamp": "2025-12-10T16:00:00Z"}onexo.postulacion-rechazada
Sección titulada «onexo.postulacion-rechazada»Se envía cuando un revisor rechaza una postulación.
{ "event": "onexo.postulacion-rechazada", "tenantId": "8", "postulacionId": "cm5xyz789", "procesoId": "cm5proceso123", "procesoTitulo": "Captador de Aportes RM", "persona": { "rut": "12345678-9", "nombreCompleto": "Juan Pérez González", "email": "juan.perez@email.com" }, "revisor": { "userId": "zitadel-user-123", "nombre": "María García" }, "motivoRechazo": "Documentación incompleta", "timestamp": "2025-12-10T16:00:00Z"}onexo.aclaracion-solicitada
Sección titulada «onexo.aclaracion-solicitada»Se envía cuando un revisor solicita aclaraciones adicionales.
{ "event": "onexo.aclaracion-solicitada", "tenantId": "8", "postulacionId": "cm5xyz789", "procesoId": "cm5proceso123", "procesoTitulo": "Captador de Aportes RM", "persona": { "rut": "12345678-9", "nombreCompleto": "Juan Pérez González", "email": "juan.perez@email.com" }, "revisor": { "userId": "zitadel-user-123", "nombre": "María García" }, "mensaje": "Por favor adjunte copia de su certificado de antecedentes", "timestamp": "2025-12-10T16:00:00Z"}onexo.curso-aprobado
Sección titulada «onexo.curso-aprobado»Se envía cuando un alumno completa y aprueba un curso.
{ "event": "onexo.curso-aprobado", "tenantId": "8", "cursoId": "cm5curso123", "cursoTitulo": "Inducción Básica", "alumno": { "rut": "12345678-9", "nombreCompleto": "Juan Pérez González", "email": "juan.perez@email.com" }, "puntaje": 85, "aprobado": true, "timestamp": "2025-12-10T18:00:00Z"}validafirma.documento-completado
Sección titulada «validafirma.documento-completado»Se envía cuando un documento es firmado exitosamente en ValidaFirma.
{ "event": "validafirma.documento-completado", "tenantId": "8", "documentoId": "vf-doc-123", "procesoId": "cm5proceso123", "postulacionId": "cm5xyz789", "firmantes": [ { "rut": "12345678-9", "nombre": "Juan Pérez González", "email": "juan.perez@email.com", "firmadoEn": "2025-12-10T15:30:00Z" } ], "documentoUrl": "https://storage.googleapis.com/.../contrato-firmado.pdf", "timestamp": "2025-12-10T15:30:00Z"}Seguridad: Validación HMAC
Sección titulada «Seguridad: Validación HMAC»Cada webhook incluye una firma HMAC-SHA256 en el header X-Webhook-Signature que debes validar para asegurar que el webhook es auténtico.
Ejemplo en Node.js
Sección titulada «Ejemplo en Node.js»const crypto = require('crypto');
function validateWebhookSignature(payload, signature, secret) { // Calcular HMAC del payload const hmac = crypto.createHmac('sha256', secret); hmac.update(JSON.stringify(payload)); const expectedSignature = hmac.digest('hex');
// Comparar con signature recibida (timing-safe) return crypto.timingSafeEqual( Buffer.from(signature), Buffer.from(expectedSignature) );}
// Uso en endpoint receptorapp.post('/webhooks/redcumbre', express.json(), (req, res) => { const signature = req.headers['x-webhook-signature']; const secret = process.env.REDCUMBRE_WEBHOOK_SECRET;
if (!validateWebhookSignature(req.body, signature, secret)) { return res.status(401).json({ error: 'Invalid signature' }); }
// Procesar webhook... const { event, ...data } = req.body; console.log(`Received ${event}:`, data);
res.status(200).json({ success: true });});Reintentos y Manejo de Errores
Sección titulada «Reintentos y Manejo de Errores»Estrategia de Reintentos
Sección titulada «Estrategia de Reintentos»El sistema reintenta automáticamente con backoff exponencial:
| Intento | Delay | Acumulado |
|---|---|---|
| 1 | Inmediato | 0s |
| 2 | +1 segundo | 1s |
| 3 | +2 segundos | 3s |
| 4 | +4 segundos | 7s |
| 5 | +8 segundos | 15s |
| 6 (final) | +16 segundos | 31s |
Total: ~31 segundos desde el primer intento hasta el último.
Respuestas Esperadas
Sección titulada «Respuestas Esperadas»| Código HTTP | Resultado |
|---|---|
| 200-299 | Webhook recibido correctamente |
| 4xx | Error cliente - Se reintentará |
| 5xx | Error servidor - Se reintentará |
| Timeout | Sin respuesta en 30s - Se reintentará |
Mejores Prácticas
Sección titulada «Mejores Prácticas»Para tu Sistema Receptor
Sección titulada «Para tu Sistema Receptor»-
Responde rápido (< 5 segundos)
- Timeout máximo: 30 segundos
- Procesa en background si necesitas más tiempo
-
Retorna HTTP 200-299 siempre que recibas el webhook
{ "success": true, "receivedAt": "2025-12-10T15:30:00Z" } -
Implementa idempotencia
- Los reintentos pueden enviar el mismo webhook múltiples veces
- Usa
timestampo un campo único para detectar duplicados
-
Valida la firma HMAC
- Nunca proceses webhooks sin validar la firma
- Usa comparación timing-safe
-
Logea todos los webhooks recibidos
- Ayuda al debugging
- Permite detectar problemas de entrega
Testing
Sección titulada «Testing»Usando webhook.site
Sección titulada «Usando webhook.site»webhook.site es una herramienta gratuita para testear webhooks:
- Ve a https://webhook.site
- Copia tu URL única (ej:
https://webhook.site/abc-123) - Configura esa URL en tu tenant
- Realiza una operación que genere webhook (ej: emitir BHE)
- Verifica en webhook.site que recibiste el POST
Probando Reintentos
Sección titulada «Probando Reintentos»Para testear la lógica de reintentos, puedes usar URLs que retornan errores:
# Retorna siempre HTTP 500https://httpstat.us/500
# Retorna HTTP 503https://httpstat.us/503
# Delay de 35 segundos (causa timeout)https://httpbin.org/delay/35Testing (Sandbox)
Sección titulada «Testing (Sandbox)»En modo sandbox, los webhooks funcionan normalmente pero los datos son de prueba:
- API Keys con
isSandbox: trueenvían webhooks con datos simulados - No hay llamadas reales al SII
- Útil para validar tu integración antes de producción
RUTs de prueba:
| RUT | Resultado |
|---|---|
78012039-8 | Empresa completa (FIRERAISE SPA) |
77425402-1 | Empresa con múltiples direcciones |
99999999-9 | Simula error |
API Reference
Sección titulada «API Reference»Para detalles técnicos completos y especificaciones de todos los endpoints: