Introducción
Webhooks
Los webhooks de Venflow te permiten recibir notificaciones HTTP en tiempo real cuando ocurren eventos importantes en tu organización, como pagos exitosos, creación de suscripciones o fallas en cobros.
¿Cómo Funcionan?
Cuando un evento ocurre (por ejemplo, un pago exitoso), Venflow envía una solicitud POST con el payload del evento en formato JSON a cada URL de webhook configurada en tu organización.
Tu Servidor ← POST (JSON payload) ← VenflowConfiguración
Los webhooks se configuran desde el panel, en Desarrolladores → Webhooks. No hay un endpoint público para darlos de alta: la API de Venflow no expone este recurso, así que se configuran una vez desde el panel y tu integración solo se ocupa de recibir los eventos.
Cada webhook incluye:
| Campo | Descripción |
|---|---|
url | URL de tu endpoint que recibirá los eventos |
events | Array de tipos de eventos a recibir (vacío = todos) |
secret | Secreto para verificar la autenticidad de los eventos |
enabled | Habilitar o deshabilitar el webhook |
Filtrado de Eventos
Puedes configurar qué eventos recibe cada webhook usando el campo events:
- Array vacío o
["*"]: recibe todos los eventos - Eventos específicos: solo recibe los tipos indicados
{
"url": "https://tu-api.com/webhooks/venflow",
"events": ["PAYMENT_SUCCESS_EVENT", "PAYMENT_FAILED_EVENT"],
"enabled": true
}Seguridad
Si configuras un secret en tu webhook, Venflow usa ese valor para acreditar cada entrega. Hoy conviven dos headers mientras completamos la migración:
| Header | Estado | Qué contiene |
|---|---|---|
X-Webhook-Signature | Nuevo estándar | Firma HMAC-SHA256 del cuerpo junto con la hora de envío: t=<unix_segundos>,v1=<hex> |
X-Webhook-Secret | Obsoleto (deprecado) | El secreto en texto plano. Se dejará de enviar al cerrar la ventana de deprecación |
Si el webhook no tiene secret configurado, no se envía ninguno de los dos headers.
X-Webhook-Signature (recomendado)
La firma prueba dos cosas a la vez: que el evento salió de Venflow y que el cuerpo no fue alterado en el camino. Además incluye la hora de envío, así puedes rechazar una solicitud capturada y reenviada más tarde.
X-Webhook-Signature: t=1789415801,v1=b03900efcfc5b467a9192c1e448a82bd77187fb70cda36cefffc810d7564170cEsta firma se está habilitando organización por organización (despliegue progresivo). Mientras dure el despliegue, tu endpoint puede recibir entregas con el header y otras sin él. Programa a la defensiva: si el header X-Webhook-Signature está presente, verifícalo y rechaza la solicitud cuando no coincida; si no está presente, procesa el evento como hasta ahora. Cuando el despliegue termine, la firma llegará siempre y podrás exigirla.
El paso a paso y el código de verificación están en Verificar la firma.
X-Webhook-Secret (obsoleto)
Este header lleva tu secreto en texto plano, de modo que cualquier proxy o registro de logs intermedio puede verlo. Se sigue enviando junto con la firma durante una ventana de deprecación, para no romper las integraciones que hoy lo comparan, y luego se eliminará.
- No escribas integraciones nuevas contra este header. Usa
X-Webhook-Signature. - Si ya lo usas, migra a la verificación de firma antes de que cierre la ventana. El cambio se anunciará en la documentación antes de aplicarse.
// Forma obsoleta — solo para integraciones existentes.
const secret = req.headers['x-webhook-secret'];
if (secret !== process.env.VENFLOW_WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' });
}Recomendaciones de Seguridad
- Usa HTTPS para tu endpoint de webhook
- Verifica
X-Webhook-Signaturesiempre que venga en la solicitud - Responde con un código
2xxpara confirmar la recepción - Responde rápido: hay un tiempo límite de 5 segundos por intento. Si tu procesamiento es lento, encola el evento y responde de inmediato
- No expongas tu secreto de webhook en código del lado del cliente
Comportamiento de Entrega
| Aspecto | Detalle |
|---|---|
| Método HTTP | POST |
| Content-Type | application/json |
| Envío | A todos los webhooks habilitados que estén suscritos al evento |
| Tiempo límite | 5 segundos por intento (conectar y responder) |
| Reintentos | Hasta 3 intentos, separados por 5 minutos |
| Éxito | Cualquier respuesta 2xx. El primer intento exitoso detiene los reintentos |
| Tras agotar los intentos | Venflow envía un correo de aviso a la organización y deja de intentar ese evento |
Reintentos
Si tu endpoint no responde con un código 2xx dentro de los 5 segundos, Venflow reintenta la
entrega hasta dos veces más, con 5 minutos de espera entre intentos. Agotados los tres, te
enviamos un correo avisando que el endpoint está fallando.
Tu endpoint tiene que ser idempotente. Procesar el mismo evento dos veces no puede cobrar dos
veces, ni duplicar un registro. Y ojo con un caso que sorprende: si tu servidor tarda 6 segundos
en responder 200, para nosotros el intento falló — vas a recibir el evento de nuevo aunque ya lo
hayas procesado correctamente. Responde 200 primero y haz el trabajo pesado después, de forma
asíncrona.
Hoy el payload no trae un identificador de evento, así que para deduplicar tienes que
apoyarte en los datos del propio evento (por ejemplo, el id de la factura o de la transacción
junto con el eventType).
Los eventos de prueba enviados desde el panel son de un solo intento: no se reintentan ni generan el correo de aviso. Ver Probar Webhooks.
Headers Enviados
POST /tu-endpoint HTTP/1.1
Content-Type: application/json
X-Webhook-Signature: t=1789415801,v1=b03900efcfc5b467a9192c1e448a82bd77187fb70cda36cefffc810d7564170c
X-Webhook-Secret: tu_secreto_configuradoCampos Comunes
Los eventos a nivel de cliente (todos menos los GATEWAY_*) incluyen estos campos base:
{
"eventType": "NOMBRE_DEL_EVENTO",
"client": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "cliente@email.com",
"name": "Juan",
"lastName": "Pérez"
}
}| Campo | Tipo | Descripción |
|---|---|---|
eventType | string | Identificador del tipo de evento |
client.id | string (UUID) | ID único del cliente |
client.email | string | Email del cliente |
client.name | string | Nombre del cliente |
client.lastName | string | Apellido del cliente |
Los dos eventos GATEWAY_API_KEY_* son la excepción: corresponden a la organización, no a un
cliente, y no traen el objeto client. En su lugar traen organizationId, configId y
bankId.
Consulta la referencia de eventos para ver los campos específicos de cada tipo de evento.
Qué asumir del payload y qué no
Estas cuatro cosas son las que más rompen una integración de webhooks. Ninguna es obvia leyendo un ejemplo:
- Los objetos opcionales pueden faltar.
subscription,invoice,paymentysessionno vienen en todos los eventos, ni siquiera en todos los casos del mismo evento. Comprueba antes de leer adentro. sessionsolo llega en pagos que nacen de un checkout. Los cobros recurrentes de una suscripción no lo traen.subscription.statusno es una lista cerrada. Deja siempre una rama por defecto.- Agregamos campos nuevos sin avisar. El payload no tiene versión, así que tu parser tiene que ignorar lo que no conoce en vez de fallar. Nunca quitamos ni renombramos un campo existente.
Archivar un medidor DELETE
Archiva un medidor de uso. Un medidor archivado no acepta nuevos eventos de uso, pero los eventos históricos y el consumo facturado se conservan. Esta operación no puede deshacerse.
Verificar la firma
Cómo validar el header X-Webhook-Signature para confirmar que un evento viene de Venflow y no fue alterado