Webhooks
Eventos en tiempo real desde tu tenant a tus sistemas externos. Firmados HMAC-SHA256, retry exponential backoff.
Modelo
- Endpoint: URL HTTP(S) que recibe POST de eventos
- Secret: 32-byte base64url random,
whsec_*. Solo se muestra al crear el endpoint - Events filter: lista de event keys o
*para todos - Delivery: cada evento que matchea genera una fila en
webhook_deliveriescon statuspending/success/failed
Eventos estándar
contact.created,contact.updatedappointment.created,appointment.confirmed,appointment.canceledinvoice.issued— factura emitida con NCF asignado. Payload:invoiceId, ncf, ncfType, amount, tax, total, currency. POS también dispara este evento consource='pos'+paymentMethod+branchId.invoice.paid— factura marcada pagada. Payload:invoiceId, ncf, total, currency, paidAt.invoice.void— factura anulada. Payload:invoiceId, ncf, reason, voidedAt.
Crear un endpoint
- Superadmin abre tenant detail → Webhooks
- Form: URL HTTP(S), events (CSV con keys o
*) - Submit → response revela el secret una sola vez
- Guardar el secret en tu backend antes de cerrar
Verificar firma
Cada delivery incluye headers:
X-Vertix-Event: nombre del eventoX-Vertix-Signature:sha256=<digest>X-Vertix-Delivery-Id: UUID único del intentoUser-Agent:Vertix-Webhooks/1.0
Validación en tu backend
import crypto from 'crypto';
function verifyVertixWebhook(rawBody, signatureHeader, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader),
);
}Importante: usa timingSafeEqual para evitar timing attacks. Compara el body RAW (no parseado).
Reintentos
Si tu endpoint responde non-2xx o timeout (10s), Vertix reintenta con exponential backoff:
- Intento 2: +2 min
- Intento 3: +4 min
- Intento 4: +8 min
- Intento 5: +16 min
- Tras 5 fallos: status
failed, no más reintentos
Idempotencia
Tu handler debe ser idempotente: usa X-Vertix-Delivery-Id como dedup key. El mismo evento puede llegar 2+ veces si tu acuse fallo intermitentemente.
Disable / pause
UI permite Pausar (no entrega nuevos events) sin borrar el endpoint, o Eliminar (cascade de deliveries). Si failure_count sube alto, considera revisar tu backend o disable temporal.
Cron job dispatcher
Endpoint /api/cron/webhooks procesa pending deliveries. Auth: Authorization: Bearer <CRON_SECRET>. Recomendado ejecutar cada 60s desde Coolify scheduled task.