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 sk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://mi-app.com/api/webhooks/mercalo",
    "events": [
      "invoice.accepted",
      "invoice.rejected",
      "credit_note.accepted"
    ],
    "secret": "whsec_mi_secreto_seguro"
  }'

Eventos disponibles

EventoDescripción
invoice.acceptedFactura aprobada por la DIAN
invoice.rejectedFactura rechazada por la DIAN
credit_note.acceptedNota crédito aceptada
credit_note.rejectedNota crédito rechazada
debit_note.acceptedNota débito aceptada
debit_note.rejectedNota débito rechazada
payroll.acceptedNómina aceptada
payroll.rejectedNómina rechazada
support_document.acceptedDoc. soporte aceptado

Payload de ejemplo

Cada webhook envía un POST con el siguiente formato JSON:

{
  "id": "evt_abc123",
  "type": "invoice.accepted",
  "createdAt": "2026-03-12T10:30:05Z",
  "data": {
    "id": "inv_abc123",
    "cufe": "a1b2c3d4...",
    "status": "ACCEPTED",
    "companyId": "uuid-empresa",
    "total": 1785000
  }
}

Verificar firma

Cada request incluye el header X-Mercalo-Signature con un HMAC-SHA256. Siempre verifica la firma antes de procesar.

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-mercalo-signature'];
  if (!verifyWebhookSignature(req.rawBody, signature, 'whsec_xxx')) {
    return res.status(401).send('Invalid signature');
  }
  // Procesar evento...
  res.status(200).send('OK');
});

Reintentos

Si tu endpoint no responde con 2xx en 30 segundos, reintentamos automáticamente:

  • • 1er reintento: 1 minuto después
  • • 2do reintento: 5 minutos después
  • • 3er reintento: 30 minutos después
  • • 4to reintento: 2 horas después
  • • 5to reintento: 24 horas después

Después de 5 intentos fallidos, el webhook se desactiva y recibes un email de alerta.