Webhooks
Los webhooks proporcionan notificaciones HTTP push en tiempo real cuando ocurren eventos de análisis, eliminando la necesidad de polling. Cuando un análisis se completa, falla o desencadena otros eventos, la plataforma Cert-IX envía una solicitud HTTP POST a su URL registrada con el payload del evento.
¿Por qué usar webhooks?
- Notificaciones instantáneas — Sin retardo de polling
- Reducción de llamadas API — Sin cuota consumida para verificaciones de estado
- Arquitectura basada en eventos — Active automáticamente gates CI/CD, notificaciones, creación de tickets
- Entrega confiable — Reintentos automáticos con backoff exponencial
Registrar un webhook
Endpoint
POST /api/v1/webhooks
Alcance requerido: webhooks:create
Solicitud
curl -X POST https://api.cert-ix.com/scan-api/api/v1/webhooks \
-H "X-API-Key: $CERTIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Notificaciones CI/CD",
"url": "https://su-servidor.example.com/webhooks/certix",
"events": ["scan.completed", "scan.failed"]
}'
Parámetros de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
name | string | Sí | Nombre legible del webhook (máx. 255 caracteres) |
url | string | Sí | Endpoint HTTPS para recibir eventos (máx. 2048 caracteres) |
events | string[] | No | Tipos de eventos a suscribir (predeterminado: scan.completed, scan.failed) |
Respuesta (201 Created)
{
"success": true,
"data": {
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Notificaciones CI/CD",
"url": "https://su-servidor.example.com/webhooks/certix",
"secret": "whsec_a8b2f1d92ffb23344a943df2b6a001fb1028d002e3f4a5b6c7d8",
"events": ["scan.completed", "scan.failed"],
"isActive": true,
"isHealthy": true,
"createdAt": "2026-03-06T10:00:00Z"
}
}
El campo secret se devuelve solo al momento de la creación. Almacénelo de forma segura — lo necesitará para verificar las firmas de webhooks.
Eventos webhook
| Evento | Disparador | Descripción |
|---|---|---|
scan.completed | El análisis termina exitosamente | Los resultados están listos para ser obtenidos |
scan.failed | El análisis encuentra un error fatal | Detalles del error incluidos en el payload |
scan.started | El análisis comienza la ejecución | Transición de queued a running |
scan.cancelled | El análisis es cancelado | Resultados parciales pueden estar disponibles |
Formato del payload
Encabezados
Content-Type: application/json
X-Webhook-Signature: sha256=a1b2c3d4e5f6...
X-Webhook-Event: scan.completed
X-Webhook-Delivery: del-uuid-aqui
X-Webhook-Timestamp: 2026-03-06T10:02:15Z
Cuerpo
{
"event": "scan.completed",
"timestamp": "2026-03-06T10:02:15Z",
"tenantId": "7b5b0610-2947-412f-a869-4683da321fcf",
"data": {
"scanId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"scanType": "nmap",
"name": "Auditoría de red semanal",
"target": "example.com",
"status": "completed",
"progress": 100,
"resultCount": 12,
"durationMs": 135000
}
}
Verificación de firma
Cada entrega de webhook está firmada con su secreto de webhook usando HMAC-SHA256. Verifique siempre las firmas para asegurarse de que la solicitud proviene de Cert-IX y no ha sido alterada.
Algoritmo de verificación
- Extraer el encabezado
X-Webhook-Signature - Obtener el cuerpo crudo de la solicitud (antes de cualquier análisis JSON)
- Calcular
HMAC-SHA256(secreto, cuerpo)y codificar en hexadecimal - Comparar con la firma del encabezado (usar comparación en tiempo constante)
Ejemplo Python
import hmac
import hashlib
def verificar_webhook(cuerpo_solicitud: bytes, encabezado_firma: str, secreto: str) -> bool:
"""Verificar la firma del webhook de Cert-IX."""
if not encabezado_firma.startswith("sha256="):
return False
recibido = encabezado_firma[7:]
esperado = hmac.new(
secreto.encode("utf-8"),
cuerpo_solicitud,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(recibido, esperado)
Ejemplo Go
func verificarWebhook(body []byte, signatureHeader, secret string) bool {
if !strings.HasPrefix(signatureHeader, "sha256=") {
return false
}
recibido := signatureHeader[7:]
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
esperado := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(recibido), []byte(esperado))
}
Ejemplo Node.js
const crypto = require("crypto");
function verificarWebhook(body, signatureHeader, secret) {
if (!signatureHeader.startsWith("sha256=")) return false;
const recibido = signatureHeader.slice(7);
const esperado = crypto.createHmac("sha256", secret).update(body).digest("hex");
return crypto.timingSafeEqual(Buffer.from(recibido), Buffer.from(esperado));
}
Use siempre funciones de comparación en tiempo constante para prevenir ataques de temporización.
Gestionar webhooks
| Operación | Endpoint | Alcance |
|---|---|---|
| Listar | GET /api/v1/webhooks | webhooks:read |
| Obtener | GET /api/v1/webhooks/:webhookId | webhooks:read |
| Actualizar | PATCH /api/v1/webhooks/:webhookId | webhooks:update |
| Eliminar | DELETE /api/v1/webhooks/:webhookId | webhooks:delete |
| Probar | POST /api/v1/webhooks/:webhookId/test | webhooks:create |
| Registros de entrega | GET /api/v1/webhooks/:webhookId/deliveries | webhooks:read |
Lógica de reintentos
Las entregas fallidas se reintentan automáticamente con backoff exponencial:
| Intento | Retraso | Tiempo total transcurrido |
|---|---|---|
| 1 | Inmediato | 0 |
| 2 | 60 segundos | 1 minuto |
| 3 | 120 segundos | 3 minutos |
| 4 (final) | 240 segundos | 7 minutos |
Una entrega se considera fallida si:
- Su endpoint devuelve un código HTTP no 2xx
- La conexión expira (timeout de 30 segundos)
- La resolución DNS falla
- El handshake TLS falla
Monitoreo de salud
La plataforma rastrea la salud de los webhooks basada en el éxito de las entregas:
| Campo | Descripción |
|---|---|
isHealthy | true si las entregas recientes fueron exitosas |
consecutiveFailures | Número de fallos consecutivos |
lastTriggeredAt | Marca de tiempo del último intento |
lastStatusCode | Código HTTP de la última entrega |
Desactivación automática
Si un webhook acumula 10 fallos consecutivos, se desactiva automáticamente (isActive: false). Para reactivarlo:
- Corrija el problema con su endpoint
- Reactive vía
PATCHcon{"isActive": true} - Envíe un evento de prueba para verificar
Mejores prácticas
- ✅ Use solo HTTPS — Las URL de webhook deben usar
https:// - ✅ Verifique las firmas en cada solicitud
- ✅ Devuelva 200 rápidamente — Procese los eventos de forma asíncrona
- ✅ Implemente idempotencia — El mismo evento puede entregarse más de una vez durante reintentos
- ✅ Valide el tipo de evento — Solo procese los eventos esperados
Próximos pasos: