Webhooks
Recibe notificaciones en tiempo real cuando la DIAN procesa tus documentos.
Crear un webhook
Registra una URL donde recibirás eventos POST con el resultado de tus documentos.
curl -X POST https://api.mercalo.co/v1/webhooks \
-H "Authorization: Bearer mk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"url": "https://mi-app.com/api/webhooks/mercalo",
"events": [
"document.accepted",
"document.rejected",
"document.error"
],
"secret": "mi-secreto-seguro"
}'Eventos disponibles
| Evento | Descripción |
|---|---|
document.accepted | Documento (factura, nota crédito/débito, doc. soporte, etc.) aceptado por la DIAN |
document.rejected | Documento rechazado por la DIAN — revisa dianResponse para el detalle |
document.error | Error al procesar el documento (no llegó a ser evaluado por la DIAN) |
Payload de ejemplo
Cada webhook envía un POST con el siguiente formato JSON:
{
"documentId": "5f2c7a1e-...",
"number": "SETP990000001",
"cufe": "a1b2c3d4...",
"trackId": "b7e91c...",
"dianStatus": "ACCEPTED",
"type": "invoice"
}Verificar firma
Si configuraste un secret al crear el webhook, cada request incluye el header X-Webhook-Signature con un HMAC-SHA256 del cuerpo del request. Sin secret configurado, este header no se envía. Siempre verifica la firma antes de procesar si dependes de la autenticidad del evento.
También recibes X-Webhook-Event (el mismo valor que el campo type del payload) y X-Webhook-Id con el identificador del webhook que disparó el evento.
import crypto from 'crypto';
function verifyWebhookSignature(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// En tu handler
app.post('/api/webhooks/mercalo', (req, res) => {
const signature = req.headers['x-webhook-signature'];
if (!verifyWebhookSignature(req.rawBody, signature, 'mi-secreto-seguro')) {
return res.status(401).send('Invalid signature');
}
// Procesar evento...
res.status(200).send('OK');
});Reintentos
Si tu endpoint no responde con 2xx en 10 segundos (timeout), o responde con un error, reintentamos automáticamente con backoff exponencial — hasta 5 intentos en total, con la espera entre intentos creciendo en segundos, no en horas.
Puedes ver el historial de entregas (código HTTP, éxito/fallo, duración) de cada webhook desde el panel, y disparar un evento de prueba en cualquier momento sin esperar a un documento real.