Webhooks salientes
Abaco puede notificar a tu sistema cuando ocurren eventos de negocio (documentos, productos, socios, pagos). Configuras la URL en Configuración → Integraciones → Webhooks; Abaco envía un POST firmado con HMAC-SHA256.
El payload es compacto: usa tu API key para hidratar el detalle (GET /documents/:id, etc.).
Configuración
- Inicia sesión en abaco.
- Ve a Configuración → Integraciones → Webhooks.
- Crea un webhook con nombre, URL HTTPS y los eventos suscritos.
- Guarda el signing secret (solo se muestra una vez). Úsalo para verificar
X-Abaco-Signature.
En desarrollo (no producción) se aceptan URLs http:// para pruebas locales.
Eventos
| Evento | Cuándo |
|---|---|
document.created | Documento creado |
document.confirmed | Documento confirmado (o auto-confirmado al crear) |
document.dte_accepted | DTE El Salvador aceptado por Hacienda |
document.cancelled | Documento cancelado |
product.created / product.updated | Producto creado o actualizado |
business_partner.created / business_partner.updated | Socio de negocio creado o actualizado |
payment.created / payment.confirmed | Pago registrado o confirmado |
webhook.test | Solo vía botón Probar en la UI |
Payload
json
{
"event": "document.created",
"companyId": 42,
"resourceType": "document",
"resourceId": 1001,
"occurredAt": "2026-09-24T18:00:00.000Z",
"data": {
"IdFactura": 1001,
"type": "01",
"number": "00000123",
"total": 150.5,
"businessPartnerId": 77,
"isConfirmed": false,
"codigoGeneracion": null
}
}Para documentos, data.IdFactura es el mismo valor que Document.id / resourceId.
Headers
| Header | Descripción |
|---|---|
Content-Type | application/json |
User-Agent | Abaco-Webhooks/1.0 |
X-Abaco-Event | Nombre del evento |
X-Abaco-Delivery-Id | ID del intento de entrega |
X-Abaco-Signature | sha256=<hex> HMAC del cuerpo exacto |
Verificar la firma
Calcula HMAC-SHA256 del body crudo (bytes UTF-8 del JSON recibido) con el signing secret y compara con el valor tras sha256= en X-Abaco-Signature (comparación en tiempo constante).
Ejemplo Node.js:
js
const crypto = require('crypto');
function verifyAbacoSignature(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody, 'utf8')
.digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(String(signatureHeader || ''));
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// Express: usar express.raw({ type: 'application/json' }) en esta ruta
app.post('/webhooks/abaco', express.raw({ type: 'application/json' }), (req, res) => {
const ok = verifyAbacoSignature(req.body, req.get('X-Abaco-Signature'), process.env.ABACO_WEBHOOK_SECRET);
if (!ok) return res.status(401).send('invalid signature');
const payload = JSON.parse(req.body.toString('utf8'));
// ... procesar payload.event
res.status(200).json({ received: true });
});Entrega y reintentos
- Timeout: 10 segundos.
- Éxito: HTTP 2xx.
- Reintentos: hasta 3 con backoff exponencial (BullMQ).
- Puedes ver el historial en Envíos en la UI.
Seguridad
- Usa siempre HTTPS en producción.
- Trata el secret como una contraseña; rótalo si se filtra.
- Responde rápido (2xx) y procesa de forma asíncrona si el trabajo es pesado.
- Idempotencia: usa
X-Abaco-Delivery-Ido(event, resourceId, occurredAt)para evitar duplicados.