Webhooks
Configuración, eventos, firma HMAC, reintentos e historial de webhooks salientes de Sifende.
Los webhooks notifican cambios de documentos y lotes. Se configuran por contribuyente y ambiente desde Webhooks en el panel. Mantené las consultas de estado como respaldo operativo: la entrega es at-least-once y un receptor debe tolerar duplicados.
Eventos
| Tipo | Cuándo se emite |
|---|---|
documento.aprobado | SIFEN aprueba un documento. |
documento.rechazado | SIFEN rechaza un documento. |
documento.cancelado | SIFEN acepta la cancelación de un documento. |
lote.procesado | Todos los documentos de un lote alcanzan un resultado final. |
Cada endpoint elige uno o más eventos y un ambiente inmutable (DEV, PROD o SANDBOX). Un contribuyente puede tener hasta cinco endpoints activos por ambiente. La URL debe usar HTTPS; no se siguen redirects.
Los eventos nuevos se entregan únicamente a endpoints de su ambiente (DEV, PROD o SANDBOX). Ese ambiente queda fijo: para escuchar otro, creá otro endpoint. Podés registrar la misma URL en ambientes distintos; cada endpoint tiene su propio secreto.
En SANDBOX también se entrega documento.aprobado, con un protocolo SBX- seguido del CDC, a los endpoints de SANDBOX suscritos a ese evento. No representa una aprobación de SIFEN.
Sobre del evento
Todos los payloads usan la versión 1:
{
"id": "d44f9f47-380f-4f51-b5c9-4fa335711e18",
"tipo": "documento.aprobado",
"version": "1",
"ocurridoEn": "2026-08-13T15:00:00Z",
"contribuyenteId": 42,
"ambiente": "PROD",
"data": {
"documentoId": "41de310e-1374-4593-bce4-7c27638ee99a",
"cdc": "01800123451001001000000122026042710000000006",
"estado": "APROBADO",
"loteId": 815,
"protocoloAutorizacion": "123456789",
"resultados": []
}
}ambiente identifica el ambiente del documento o lote: DEV, PROD o SANDBOX. Las notificaciones nuevas incluyen este campo en la raíz. Las entregas creadas antes de su incorporación conservan su payload y destinatario originales, incluso en un reintento. Pueden no incluir ambiente y corresponder a un ambiente distinto del que muestra hoy el endpoint.
documento.aprobado y documento.rechazado incluyen documentoId, cdc, estado, loteId, protocoloAutorizacion y resultados. documento.cancelado incluye documentoId, cdc, estado, eventoSifenId, motivo, codigoRespuesta, mensajeRespuesta y protocoloAutorizacion.
El objeto data de lote.procesado contiene:
| Campo | Contenido |
|---|---|
loteId, numeroLote | Identificadores del envío |
estado | "PROCESADO" |
aprobados | Cantidad de documentos aprobados |
aprobadosConObservacion | Cantidad de documentos aprobados con observaciones |
rechazados | Cantidad de documentos rechazados |
documentos | Lista con documentoId, cdc, estado, protocoloAutorizacion y resultados por documento |
Headers
| Header | Contenido |
|---|---|
X-Sifende-Event-Id | UUID estable del evento; usalo para deduplicar. |
X-Sifende-Event-Type | Tipo del evento. |
X-Sifende-Delivery-Id | UUID de la entrega a un endpoint. |
X-Sifende-Timestamp | Unix timestamp en segundos usado en la firma. |
X-Sifende-Signature | v1= seguido del HMAC-SHA256 en Base64. |
Verificar la firma
El secreto whsec_… se muestra sólo al crear o rotar el endpoint. Guardalo en un gestor de secretos. La firma se calcula sobre bytes, no sobre un JSON parseado o reserializado:
mensaje = eventId + "." + deliveryId + "." + timestamp + "." + rawBody
firma = "v1=" + Base64(HMAC-SHA256(secret, mensaje))Ejemplo en Node.js:
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verificarWebhook({ rawBody, headers, secret }) {
const eventId = headers['x-sifende-event-id'];
const deliveryId = headers['x-sifende-delivery-id'];
const timestamp = headers['x-sifende-timestamp'];
const recibida = headers['x-sifende-signature'];
const prefijo = Buffer.from(`${eventId}.${deliveryId}.${timestamp}.`);
const mensaje = Buffer.concat([prefijo, rawBody]);
const esperada = `v1=${createHmac('sha256', secret).update(mensaje).digest('base64')}`;
return recibida.length === esperada.length && timingSafeEqual(Buffer.from(recibida), Buffer.from(esperada));
}Validá también que X-Sifende-Timestamp esté dentro de una ventana razonable y rechazá firmas fuera de esa ventana. Capturá el cuerpo crudo antes de cualquier middleware JSON.
Respuestas y reintentos
Respondé rápido con cualquier estado 2xx. Sifende clasifica los resultados así:
| Resultado | Comportamiento |
|---|---|
200–299 | Entrega completada. |
| Error de red, DNS, TLS o timeout | Se reintenta. |
408, 425, 429, 500–599 | Se reintenta con backoff. |
300–399 | Falla permanente; los redirects están bloqueados. |
Otros 400–499 | Falla permanente. |
Los reintentos pueden durar hasta 24 horas, con backoff entre 10 segundos y una hora. Una entrega puede repetirse; deduplicá por X-Sifende-Event-Id.
Ciclo de vida e historial
Editar la URL, las suscripciones o el secreto afecta también a las entregas pendientes. Desactivar o eliminar un endpoint cancela sus entregas no terminales. El historial muestra estado, HTTP, error e intentos durante 90 días.
Para crear, editar o desactivar endpoints, seguí la guía de webhooks del panel.