Webhooks
En lugar de hacer polling a GET /api/v1/invoices/{id}/status, registra una URL y CUCU te notifica en tiempo real cada vez que ocurre un evento relevante: una factura se valida o rechaza, se abre o cierra una contingencia, o cambia el estado de la conexión con el SIAT.
Registrar un endpoint
POST /api/v1/webhooks/endpoints
| Parametro | Ubicacion | Tipo | Req | Descripcion |
|---|
X-API-Key | Header | string | Si | Tu API Key |
url | Body | string | Si | URL https:// que recibirá las entregas |
events | Body | array<string> | Si | Eventos a suscribir. Acepta *, namespace.* (ej. contingency.*) o el tipo exacto |
description | Body | string | No | Nota interna para identificar el endpoint |
curl -X POST https://sandbox.cucu.bo/api/v1/webhooks/endpoints \
-H "Content-Type: application/json" \
-H "X-API-Key: YOUR_API_KEY" \
-d '{
"url": "https://tuservidor.com/webhooks/cucu",
"events": ["invoice.validated", "invoice.rejected", "contingency.*"],
"description": "Sincronizacion con ERP"
}'
Respuesta (201):
{
"success": true,
"data": {
"id": "wh_ep_a1b2c3d4",
"url": "https://tuservidor.com/webhooks/cucu",
"events": ["invoice.validated", "invoice.rejected", "contingency.*"],
"secret": "whsec_...",
"active": true,
"createdAt": "2026-07-01T10:00:00"
}
}
El secret solo se muestra completo en este momento (y al rotarlo). Guárdalo de forma segura — lo necesitas para verificar la firma de cada entrega.
Gestionar endpoints
| Accion | Endpoint |
|---|
| Listar endpoints | GET /api/v1/webhooks/endpoints |
| Ver un endpoint | GET /api/v1/webhooks/endpoints/{id} |
| Actualizar (url, events, activo) | PUT /api/v1/webhooks/endpoints/{id} |
| Eliminar | DELETE /api/v1/webhooks/endpoints/{id} |
| Rotar secreto | POST /api/v1/webhooks/endpoints/{id}/rotate-secret |
Todas requieren el header X-API-Key.
Cada tenant puede registrar un máximo de 20 endpoints. Si necesitas más, contacta a soporte.
Catálogo de eventos
| Evento | Descripción |
|---|
invoice.* | Un evento por cada cambio de estado de una factura (validada, rechazada, anulada), reflejando los mismos estados documentados en el ciclo de vida de la factura |
contingency.opened | Se activó contingencia offline en un punto de venta |
contingency.closed | La contingencia finalizó y las facturas se sincronizaron con el SIAT |
contingency.package_rejected | El SIAT rechazó el paquete de facturas enviado al reconectar |
siat.connection_lost | CUCU detectó que el SIAT dejó de responder |
siat.connection_restored | La conexión con el SIAT se restableció |
siat.token_expiring | El token de sesión SIAT está por expirar |
certificate.expiring | El certificado digital del tenant está por vencer |
cufd.renewal_failed | Falló la renovación automática del CUFD |
cuis.renewal_failed | Falló la renovación automática del CUIS |
Al registrar un endpoint puedes suscribirte a * (todos los eventos), a un namespace completo (contingency.*, siat.*) o a un tipo exacto. La suscripción se valida contra este mismo catálogo, así que nunca puedes suscribirte a un evento inexistente.
Seguridad
- HTTPS obligatorio. Solo se aceptan URLs
https://.
- Anti-SSRF. Al registrar o rotar un endpoint, CUCU resuelve el host y rechaza direcciones en rangos privados o de loopback.
- Firma en cada entrega. Todas las entregas se firman con HMAC-SHA256 siguiendo el estándar Standard Webhooks, para que la verificación sea sencilla y predecible en cualquier lenguaje.
| Header | Descripción |
|---|
webhook-id | UUID único de esta entrega. Úsalo para deduplicar en tu receptor. |
webhook-timestamp | UNIX timestamp del momento del envío. |
webhook-signature | Firma de autenticidad. Formato: v1,<base64(HMAC-SHA256)>. |
webhook-event | Tipo de evento entregado (ej. invoice.validated). |
Verificación de firma
mensaje_a_firmar = "{webhook-id}.{webhook-timestamp}.{raw_body_bytes}"
firma_esperada = base64( HMAC-SHA256(mensaje_a_firmar, tu_secret) )
Compara firma_esperada con el valor de webhook-signature (después del prefijo v1,) usando una comparación de tiempo constante.
Payload de ejemplo
{
"type": "invoice.validated",
"occurredAt": "2026-07-01T10:00:05",
"data": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"cuf": "2872F7294502332E637FABFBC3654EA82202AD48E0969F14EBEB8AF74",
"invoiceNumber": 42,
"state": "VALIDATED",
"amountTotal": 500.00
}
}
Política de reintentos
Tu endpoint debe responder 2xx dentro del timeout configurado para que la entrega se considere exitosa. Si no responde o responde con error, CUCU reintenta con backoff exponencial hasta 8 intentos. Un dispatcher interno procesa la cola de entregas pendientes cada 10 segundos.
Diseña tu receptor para ser idempotente usando webhook-id — el mismo evento puede llegar más de una vez ante un reintento de red.
Auditoría y reenvío manual
| Accion | Endpoint |
|---|
| Listar entregas de un endpoint | GET /api/v1/webhooks/endpoints/{id}/deliveries |
| Forzar el reenvío de una entrega | POST /api/v1/webhooks/deliveries/{deliveryId}/redeliver |
Útil para debugging: revisa el historial de intentos, el código de respuesta recibido y fuerza un reenvío manual sin esperar al backoff automático.