Saltearse al contenido

Webhooks

Sistema de webhooks

Keirost permite registrar endpoints HTTP que reciben notificaciones cuando ocurren eventos en el sistema. Asi puedes integrar Keirost con sistemas externos (ERP externo, CRM, sistemas de contabilidad, etc.) en tiempo real.


Modelo de webhook

interface Webhook {
id: string;
name: string; // "Mi integracion CRM"
url: string; // "https://mi-crm.com/webhook/keirost"
method: 'POST' | 'GET';
events: WebhookEvent[];
headers?: Record<string, string>;
secret?: string; // Para generar firma HMAC
status: 'active' | 'inactive';
retry_policy: RetryPolicy;
created_by: string;
created_at: string;
}
interface RetryPolicy {
max_attempts: number;
retry_delay_seconds: number[];
}
type WebhookEvent =
| 'document.created' | 'document.updated' | 'document.deleted'
| 'document.sent' | 'document.locked' | 'document.cancelled'
| 'payment.received' | 'payment.made'
| 'stock.movement' | 'stock.low'
| 'plugin.installed' | 'plugin.error'
| 'user.created' | 'user.deleted'
| 'automation.triggered' | 'notification.created'
| '*'; // wildcard = todos los eventos

Endpoints

MetodoRutaDescripcion
GET/api/webhooksListar webhooks
POST/api/webhooksCrear webhook
GET/api/webhooks/:idVer webhook
PATCH/api/webhooks/:idActualizar webhook
DELETE/api/webhooks/:idEliminar webhook
POST/api/webhooks/:id/testEnviar evento de prueba
GET/api/webhooks/:id/logsVer logs de envios

Crear webhook

POST /api/webhooks
Authorization: Bearer <token>
Content-Type: application/json
{
"name": "Integracion miERP",
"url": "https://mierp.com/webhook/keirost",
"method": "POST",
"events": ["document.created", "document.sent", "payment.received"],
"headers": {
"Authorization": "Bearer mi_api_key",
"Content-Type": "application/json"
},
"secret": "mi_webhook_secret_123",
"retry_policy": {
"max_attempts": 3,
"retry_delay_seconds": [60, 300, 900]
}
}

Eventos disponibles

EventoDescripcion
document.createdNuevo documento creado
document.updatedDocumento modificado
document.deletedDocumento eliminado
document.sentDocumento enviado por email
document.lockedDocumento asentado/bloqueado
document.cancelledDocumento anulado
payment.receivedPago recibido de cliente
payment.madePago realizado a proveedor
stock.movementMovimiento de stock
stock.lowStock bajo el minimo
user.createdNuevo usuario creado
user.deletedUsuario eliminado
automation.triggeredAutomatizacion ejecutada
notification.createdNueva notificacion creada
plugin.installedPlugin instalado
plugin.errorError en plugin
*Todos los eventos

Payload del webhook

Formato general

{
"id": "evt_001",
"event": "document.created",
"timestamp": "2026-05-08T10:00:00Z",
"tenant_id": "tenant_demo",
"data": { ... }
}

Ejemplo: documento creado

{
"id": "evt_001",
"event": "document.created",
"timestamp": "2026-05-08T10:00:00Z",
"tenant_id": "tenant_demo",
"data": {
"document_type": "sales_invoice",
"document_id": "inv_2026_0012",
"series": "F",
"number": 12,
"partner_id": "bp_cliente1",
"partner_name": "Acme S.L.",
"total": 1210.00,
"currency": "EUR",
"status": "draft",
"created_by": "user_admin",
"created_at": "2026-05-08T10:00:00Z"
}
}

Ejemplo: pago recibido

{
"id": "evt_002",
"event": "payment.received",
"timestamp": "2026-05-08T10:00:00Z",
"tenant_id": "tenant_demo",
"data": {
"payment_id": "pay_in_001",
"partner_id": "bp_cliente1",
"amount": 1210.00,
"payment_date": "2026-05-08",
"payment_method": "transfer",
"linked_document": {
"type": "sales_invoice",
"id": "inv_2026_0012",
"new_status": "paid"
}
}
}

Seguridad: firma HMAC

Si configuras un secret, Keirost firma cada peticion con HMAC-SHA256:

X-Keirost-Signature: sha256=<hmac_hex>
X-Keirost-Timestamp: <unix_timestamp>
X-Keirost-Event: <event_name>

Verificar firma en tu servidor

import crypto from 'crypto';
function verifyWebhookSignature(
payload: string,
signature: string,
timestamp: string,
secret: string
): boolean {
const body = `${timestamp}.${payload}`;
const expected = crypto
.createHmac('sha256', secret)
.update(body)
.digest('hex');
return `sha256=${expected}` === signature;
}

Tambien verifica que el timestamp no sea mayor de 5 minutos para evitar replay attacks.


Logs de webhooks

GET /api/webhooks/:id/logs?from=2026-05-01&to=2026-05-08
{
"data": [
{
"id": "wlog_001",
"event": "document.created",
"document_id": "inv_2026_0012",
"attempt": 1,
"status": "success",
"http_status": 200,
"response_body": "OK",
"response_time_ms": 145,
"sent_at": "2026-05-08T10:00:00Z"
},
{
"id": "wlog_002",
"event": "document.created",
"document_id": "inv_2026_0013",
"attempt": 3,
"status": "failed",
"http_status": 503,
"error": "Service unavailable",
"sent_at": "2026-05-08T10:05:00Z"
}
]
}

Resumen de endpoints

MetodoRutaDescripcion
GET/api/webhooksListar webhooks
POST/api/webhooksCrear webhook
GET/api/webhooks/:idVer webhook
PATCH/api/webhooks/:idActualizar webhook
DELETE/api/webhooks/:idEliminar webhook
POST/api/webhooks/:id/testEnviar evento de prueba
GET/api/webhooks/:id/logsVer logs de envios