Webhooks

Recibe notificaciones automáticas cuando un e-CF cambia de estado.

📡
Desde Sprint 4, cada delivery se persiste en webhook_deliveries, se reintenta con backoff exponencial (1min, 5min, 30min, 2h, 12h) y se puede consultar desde el dashboard.

Cómo funciona

  1. Configura webhook_url en Configuración → Webhooks.
  2. Opcionalmente, define un webhook_secret para firma HMAC-SHA256 (recomendado).
  3. Al cambiar el estado de un e-CF, enviamos un POST firmado a tu URL.
  4. Si responde 2xx → success. Si no → se reintenta hasta 5 veces.

Payload

{
  "event": "ecf.status_update",
  "internalTrackId": "uuid-v4",
  "encf": "E310000000001",
  "estado": "aceptado",
  "dgiiCode": "0",
  "dgiiMessage": "Aceptado",
  "trackId": "dgii-track-id",
  "timestamp": "2026-04-24T12:00:00.000Z"
}

Headers enviados

HeaderDescripción
X-ECF-Tenant-IdTu tenant_id numérico
X-ECF-EventTipo de evento (ej. ecf.status_update, webhook.test)
X-ECF-Delivery-IdID único del intento (usar para idempotencia en tu backend)
X-ECF-Signaturesha256=<hex>. HMAC-SHA256 del body crudo con tu webhook_secret

Verificación de firma (Node.js)

const crypto = require('crypto');

app.post('/webhook/ecf', express.raw({ type: 'application/json' }), (req, res) => {
  const received = req.header('X-ECF-Signature');
  const expected = 'sha256=' + crypto
    .createHmac('sha256', process.env.WEBHOOK_SECRET)
    .update(req.body) // Buffer crudo, sin parsear
    .digest('hex');

  if (!crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) {
    return res.status(401).end();
  }
  const payload = JSON.parse(req.body);
  // Procesar payload...
  res.status(200).end();
});

Endpoints de gestión

Enviar webhook de prueba

curl -X POST https://ecf.frandeone.com/api/webhooks/test \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{}'

Historial de deliveries

curl https://ecf.frandeone.com/api/webhooks/deliveries?status=failed&pageSize=20 \
  -H "Authorization: Bearer $JWT"

Reintentos

Cuando tu endpoint responde con error o timeout (10s), el webhook se marca pending y se reintenta:

  • Intento 1. inmediato
  • Intento 2. 1 minuto después
  • Intento 3. 5 minutos
  • Intento 4. 30 minutos
  • Intento 5. 2 horas
  • Si el 5º intento falla → se marca abandoned y no se reintenta más.