Venflow API

Referencia de Eventos

Referencia de Eventos

Venflow emite eventos que cubren el ciclo de vida de clientes, suscripciones, facturas y pagos, además de eventos a nivel de organización (como el vencimiento de las credenciales del gateway).

Tipos de Eventos

Eventos a nivel de cliente

EventoDescripción
USER_CREATE_EVENTNuevo cliente creado
SUBSCRIPTION_CREATE_EVENTSuscripción creada
SUBSCRIPTION_UPDATED_EVENTLa suscripción cambió de estado (por ejemplo active → past_due)
SUBSCRIPTION_CANCELLED_EVENTSuscripción cancelada
INVOICE_CREATE_EVENTFactura generada
INVOICE_UPDATE_EVENTEstado de factura actualizado
PAYMENT_SUCCESS_EVENTPago exitoso
PAYMENT_FAILED_EVENTPago fallido
PAYMENT_REMINDER_PRE_EVENTRecordatorio antes de la fecha de cobro
PAYMENT_REMINDER_POST_EVENTRecordatorio después de un cobro fallido o de un pago manual pendiente

Eventos a nivel de organización

A diferencia de los anteriores, estos eventos no incluyen el objeto client porque corresponden a la organización, no a un cliente puntual.

EventoDescripción
GATEWAY_API_KEY_EXPIRING_EVENTLa API key del gateway está por vencer
GATEWAY_API_KEY_EXPIRED_EVENTLa API key del gateway venció y fue desactivada

Campo común: livemode

Además de los campos propios de cada tipo, todo payload incluye livemode:

CampoTipoDescripción
livemodebooleantrue cuando el evento viene de tu organización real. false cuando viene de tu organización sandbox, donde nada movió dinero.

Si tu handler escribe en tu contabilidad, haz que ignore (o registre aparte) todo lo que llegue con livemode: false.


USER_CREATE_EVENT

Se envía cuando se crea un nuevo cliente durante el flujo de checkout. Solo se dispara para clientes nuevos, no cuando se reutiliza un cliente existente.

Payload
{
  "eventType": "USER_CREATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  }
}

SUBSCRIPTION_CREATE_EVENT

Se envía cuando se crea una suscripción durante el flujo de checkout, después de la activación del plan.

Payload
{
  "eventType": "SUBSCRIPTION_CREATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "externalId": "EXT123456"
  }
}

Campos de subscription

CampoTipoDescripción
idstring (UUID)ID único de la suscripción
statusstringEstado: active, inactive, cancelled, pending
externalIdstring | nullID externo de la asociación cliente-organización

SUBSCRIPTION_UPDATED_EVENT

Se envía cuando una suscripción cambia de estado y ese cambio no está cubierto por SUBSCRIPTION_CREATE_EVENT ni por SUBSCRIPTION_CANCELLED_EVENT. El caso habitual es la morosidad: pasa de active a past_due cuando un cobro falla, y vuelve a active cuando se recupera.

Es el único evento que incluye previousStatus, así que puedes saber de dónde venía la suscripción sin guardar el estado anterior por tu cuenta.

Payload
{
  "eventType": "SUBSCRIPTION_UPDATED_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "past_due",
    "previousStatus": "active",
    "externalId": "EXT123456"
  }
}

Campos de subscription

CampoTipoDescripción
idstring (UUID)ID de la suscripción
statusstringEstado al que pasó
previousStatusstringEstado del que venía
externalIdstring | nullID externo de la asociación cliente-organización

Este evento no cubre todas las transiciones. Hoy se emite en los cambios entre active, past_due y pending. Programar una cancelación, deshacerla o reactivar una suscripción no lo disparan, así que no lo uses como fuente única de verdad del estado: consulta GET /v1/subscriptions/{id} cuando necesites el estado exacto.


SUBSCRIPTION_CANCELLED_EVENT

Se envía cuando una suscripción es cancelada. Incluye el motivo de cancelación.

Payload
{
  "eventType": "SUBSCRIPTION_CANCELLED_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "cancelled",
    "externalId": "EXT123456",
    "cancellationReason": {
      "type": "payment_failure",
      "message": "Retry window exceeded"
    }
  }
}

Campos de cancellationReason

CampoTipoDescripción
typestringPor qué se canceló: payment_failure o scheduled_cancellation
scheduledDatestring | undefinedFecha ISO en la que estaba programada la cancelación (solo en scheduled_cancellation)
messagestring | undefinedMensaje descriptivo de la cancelación

Cancelar desde el panel o desde la API no emite este evento. Hoy solo se dispara cuando la cancelación la decide el sistema: porque se agotó la ventana de reintentos de cobro (payment_failure) o porque llegó la fecha de una cancelación programada (scheduled_cancellation). Si necesitas reaccionar a una cancelación hecha a mano, hazlo desde tu propio código en el momento de llamar a POST /v1/subscriptions/{id}/cancel.


INVOICE_CREATE_EVENT

Se envía cuando se genera una factura durante el proceso de pago de suscripción. La factura se crea con estado open.

Payload
{
  "eventType": "INVOICE_CREATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "externalId": "EXT123456"
  },
  "invoice": {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "status": "open",
    "total": "3907.85",
    "amountDue": "3907.85",
    "totalUsd": "5.79",
    "exchangeRate": "674.9305"
  }
}

Campos de invoice

CampoTipoDescripción
idstring (UUID)ID único de la factura
statusstringEstado: open, paid, overdue, uncollectible, cancelled
totalstringMonto total de la factura, en VES (Bs) — lo que el gateway cobra
amountDuestringMonto pendiente de pago, en VES (Bs)
totalUsdstring | nullMismo total en USD (neto = base + IVA − descuento), independiente de la tasa BCV. Puede ser null si la referencia en USD no está disponible
exchangeRatestring | nullTasa BCV (USD→VES) usada para este cobro: total ≈ totalUsd × exchangeRate. Puede ser null en facturas históricas

Los dos viajan juntos: o totalUsd y exchangeRate llegan los dos con valor, o llegan los dos en null. Nunca vas a recibir una tasa sin el monto en dólares al que aplica, ni al revés.


INVOICE_UPDATE_EVENT

Se envía cuando cambia el estado de una factura. Los estados que lo disparan son:

  • paid: la factura fue pagada exitosamente (amountDue pasa a "0")
  • uncollectible: el cobro no pudo completarse después de agotar los reintentos
  • cancelled: la factura fue anulada manualmente, desde el dashboard o por API. En la API de facturas, este estado corresponde a void
  • open: se reabrió manualmente el cobro de una factura que estaba en revisión, desde el dashboard o por API

Este evento llega con formas distintas bajo el mismo nombre. Ramifica por invoice.status antes de leer el resto:

Factura pagadaFactura incobrableFactura anulada o reabierta
invoice.status"paid""uncollectible""cancelled" o "open"
invoice.amountDuesiempre "0"el saldo real que quedó sin cobrarel saldo real de la factura
objeto subscriptionpresente si la factura pertenece a una suscripción; ausente si es un pago úniconunca presente, ni siquiera viniendo de una suscripciónpresente si la factura pertenece a una suscripción; ausente si es un pago único, o si la suscripción está en un estado que este webhook no nombra (por ejemplo, todavía sin activar o en proceso de cancelarse)

Verifica que el objeto subscription exista antes de leer event.subscription.id: no se incluye en las facturas incobrables ni en algunas anuladas o reabiertas. Para asociar una factura con su suscripción, guarda la relación al recibir INVOICE_CREATE_EVENT o consúltala por API con el invoice.id.

El estado overdue aparece en el tipo del campo status pero no genera este webhook hoy.

Factura pagada

Payload
{
  "eventType": "INVOICE_UPDATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "externalId": "EXT123456"
  },
  "invoice": {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "status": "paid",
    "total": "3907.85",
    "amountDue": "0",
    "totalUsd": "5.79",
    "exchangeRate": "674.9305"
  }
}

Factura incobrable

Payload
{
  "eventType": "INVOICE_UPDATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "invoice": {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "status": "uncollectible",
    "total": "3907.85",
    "amountDue": "3907.85",
    "totalUsd": "5.79",
    "exchangeRate": "674.9305"
  }
}

Fíjate en lo que no está: no hay objeto subscription. Es a propósito, y pasa siempre en este estado, aunque la factura sea de una suscripción.

Factura anulada

Payload
{
  "eventType": "INVOICE_UPDATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "externalId": "EXT123456"
  },
  "invoice": {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "status": "cancelled",
    "total": "3907.85",
    "amountDue": "3907.85",
    "totalUsd": "5.79",
    "exchangeRate": "674.9305"
  }
}

amountDue refleja el saldo pendiente al momento de la anulación, ya que anular una factura no la marca como cobrada. A partir de ese momento, la factura no se cobra ni se considera deuda.

Factura reabierta

Se envía cuando una factura en revisión vuelve a estar disponible para cobro:

Payload
{
  "eventType": "INVOICE_UPDATE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "subscription": {
    "id": "550e8400-e29b-41d4-a716-446655440001",
    "status": "active",
    "externalId": "EXT123456"
  },
  "invoice": {
    "id": "550e8400-e29b-41d4-a716-446655440002",
    "status": "open",
    "total": "3907.85",
    "amountDue": "3907.85",
    "totalUsd": "5.79",
    "exchangeRate": "674.9305"
  }
}

Si posteriormente se confirma el cobro pendiente o la factura se cobra en un nuevo intento, recibirás también los eventos de pago habituales: PAYMENT_SUCCESS_EVENT y INVOICE_UPDATE_EVENT con estado paid.

En ambos casos, el objeto subscription puede no incluirse aunque la factura pertenezca a una suscripción (ver la tabla anterior).

Moneda: total y amountDue van en VES (Bs); totalUsd es el mismo total en USD (independiente de la tasa BCV) y exchangeRate es la tasa BCV que los relaciona (total ≈ totalUsd × exchangeRate). totalUsd y exchangeRate pueden ser null si no están disponibles, y en ese caso lo son los dos: nunca llega una tasa sin su monto en dólares, ni al revés.


PAYMENT_SUCCESS_EVENT

Se envía cuando un pago se completa exitosamente. Si el pago se originó desde una sesión de checkout, incluye los datos de la sesión y su metadata.

Payload
{
  "eventType": "PAYMENT_SUCCESS_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "payment": {
    "id": "550e8400-e29b-41d4-a716-446655440003",
    "status": "completed",
    "retries": 1,
    "gatewayUUID": "TXN000000123456",
    "bankReference": "003812449021",
    "errorMessage": null,
    "bank": "Banco Nacional de Crédito",
    "amount": "3907.85",
    "amountUsd": "5.79",
    "exchangeRate": "674.9305",
    "paymentMethod": "domiciliado"
  },
  "session": {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "metadata": {
      "order_id": "ORD-12345",
      "campaign": "summer_promo"
    }
  }
}

Campos de payment

CampoTipoDescripción
idstring (UUID)ID de la transacción
statusstringEstado: pending, completed, failed
retriesnumberNúmero de intentos realizados
gatewayUUIDstringReferencia de la transacción en el gateway de pago
bankReferencestring | nullLa referencia que el banco del pagador imprime en su estado de cuenta — la única que puedes cruzar contra un extracto bancario, y por lo tanto la que usa una conciliación. Es distinta de gatewayUUID, que es el ID interno del procesador. Es null cuando el medio de pago no emitió referencia. En Pago Móvil el gatewayUUID siempre trajo esta misma referencia, porque ese medio no tiene ID de procesador.
errorMessagestring | nullMensaje de error (siempre null en pagos exitosos)
bankstring | nullPagos automáticos: banco del método de pago almacenado del cliente. Pagos manuales: banco seleccionado por el pagador en el formulario (Débito Inmediato) o reportado por el gateway (Pago Móvil). null cuando el banco no pudo resolverse — por ejemplo, si el código no existe en nuestra tabla de bancos o el pago se originó antes de que esta información estuviera disponible.
amountstringMonto cobrado, en VES (Bs) — lo que el gateway debita
amountUsdstring | nullMismo cobro en USD (neto = base + IVA − descuento), independiente de la tasa BCV. Puede ser null si la referencia en USD no está disponible
exchangeRatestring | nullTasa BCV (USD→VES) usada para este cobro: amount ≈ amountUsd × exchangeRate. Puede ser null si no está disponible
paymentMethodstring | nullVía por la que se cobró el pago: domiciliado, debito_inmediato, pago_movil o tarjeta (ver la tabla siguiente). Siempre está presente; es null cuando no se puede saber la vía

Los dos viajan juntos: o amountUsd y exchangeRate llegan los dos con valor, o llegan los dos en null — la misma regla que en PAYMENT_FAILED_EVENT. Y la tasa viene congelada en la factura, no es la del día: si conviertes amountUsd con la tasa de hoy te va a dar otro número.

Valores de paymentMethod

ValorSignificado
domiciliadoCobro automático contra la cuenta o el teléfono que el cliente registró (domiciliación). También aplica cuando un cobro automático quedó en revisión y luego se marcó como pagado (desde el dashboard o con mark_paid del API): en ese caso se da por bueno ese cobro automático
debito_inmediatoEl cliente pagó con Débito Inmediato
pago_movilEl cliente pagó con Pago Móvil
tarjetaEl cliente pagó con tarjeta de débito o crédito
nullNo se puede saber la vía. Ocurre, por ejemplo, cuando la factura se marcó como pagada a mano y el dinero no entró por un cobro que Venflow haya registrado: sin intentos previos, después de intentos automáticos fallidos o con un cobro automático todavía en curso. Tu integración debe aceptar null

Lista cerrada: trata paymentMethod como una lista de valores fijos. Si en el futuro se agrega una vía nueva, se anunciará antes de empezar a enviarla.

No confundir con el API REST: en el API REST, payment_method es el ID (UUID) del método de pago guardado del cliente. El paymentMethod de este webhook es otra cosa: la vía por la que entró el dinero.

Solo en pagos exitosos: por ahora, paymentMethod solo viene en PAYMENT_SUCCESS_EVENT. PAYMENT_FAILED_EVENT no lo incluye.

Campos de session (opcional)

CampoTipoDescripción
idstring (UUID)ID de la sesión de checkout
metadataobject | nullMetadata personalizada asociada a la sesión

Nota: El campo session solo está presente en pagos que se originan desde una sesión de checkout. Los pagos recurrentes de suscripciones no incluyen este campo.


PAYMENT_FAILED_EVENT

Se envía cuando un pago falla. Puede ocurrir en múltiples etapas del procesamiento (validación, cobro de suscripción, verificación). Es posible recibir múltiples eventos de fallo para la misma transacción si hay reintentos.

Payload
{
  "eventType": "PAYMENT_FAILED_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "payment": {
    "id": "550e8400-e29b-41d4-a716-446655440003",
    "status": "failed",
    "retries": 2,
    "gatewayUUID": "TXN000000123456",
    "bankReference": "003812449021",
    "errorMessage": "Insufficient funds",
    "bank": "Banco Nacional de Crédito",
    "amount": "3907.85",
    "amountUsd": "5.79",
    "exchangeRate": "674.9305"
  },
  "session": {
    "id": "660e8400-e29b-41d4-a716-446655440000",
    "metadata": {
      "order_id": "ORD-12345",
      "campaign": "summer_promo"
    }
  }
}

Nota: Al igual que PAYMENT_SUCCESS_EVENT, el campo session solo está presente cuando el pago se origina desde una sesión de checkout.

Campos del plan de reintentos (solo en cobros recurrentes)

Cuando el fallo ocurre cobrando una suscripción ya activa, el evento trae además estos dos campos. No aparecen en los fallos de checkout ni en los cobros de validación.

CampoTipoDescripción
attemptCountnumberCuántos intentos de cobro lleva este ciclo, contando el que acaba de fallar
nextPaymentAttemptstring | nullCuándo está agendado el siguiente intento (ISO 8601). null significa que no habrá más intentos: la factura se marca incobrable y la suscripción se cancela
Payload con plan de reintentos
{
  "eventType": "PAYMENT_FAILED_EVENT",
  "client": { "...": "..." },
  "payment": {
    "id": "550e8400-e29b-41d4-a716-446655440003",
    "status": "failed",
    "errorMessage": "Insufficient funds",
    "attemptCount": 2,
    "nextPaymentAttempt": "2026-10-04T09:00:00.000Z"
  }
}

Si te interesa avisarle al cliente antes de perder la suscripción, nextPaymentAttempt: null es la señal: es el último fallo antes de la cancelación.

Moneda: amount es lo que se intentó cobrarle al banco, en VES (Bs). amountUsd es ese mismo monto en USD, tal como quedó guardado en la factura. exchangeRate es la tasa BCV que los relaciona: amount ≈ amountUsd × exchangeRate.

La tasa viene congelada en la factura, no es la del día. Es la tasa con la que se calculó ese cobro. Si conviertes amountUsd con la tasa de hoy te va a dar otro número: usa siempre el exchangeRate que llega en el evento. Esto es a propósito.

Cuándo llegan en null: amountUsd y exchangeRate vienen en null en tres casos. Uno, facturas viejas creadas antes de que existiera la columna en dólares. Dos, los cobros de validación — el cargo de prueba de Bs 1,00 que confirma que una cuenta bancaria existe, que no tiene factura ni precio en dólares detrás. Tres, un fallo tan temprano que la factura todavía no existía; ahí amount llega en "0". Nunca llega una tasa sin su monto en dólares, ni un monto en dólares sin su tasa: o vienen los dos con valor, o vienen los dos en null.

Corrección — amount en el primer cobro de un checkout de suscripción. Ese caso puntual traía el precio del plan, que está en dólares, mientras todos los demás traían bolívares. Era un error y quedó corregido: amount ahora trae bolívares siempre.

Esto no cambia ningún cobro. No cambia cuánto se le cobra al cliente, ni los correos que recibe, ni el evento de pago exitoso. Cambia un solo dato, de este evento, en este escenario.

Qué hacer: si tu integración lee amount como dólares en un fallo de checkout, ajústala — una suscripción de USD 5,79 pasa de "5.79" a "3907.85". Si ya lo tratabas como bolívares, no tienes nada que hacer: hasta ahora recibías un dato incorrecto en ese caso y ahora recibes el correcto. El monto en dólares no se pierde, viaja en amountUsd, y con exchangeRate al lado puedes reconstruir el valor anterior dividiendo.


PAYMENT_REMINDER_PRE_EVENT

Se envía cuando Venflow le recuerda al cliente que se acerca la fecha de cobro, según los recordatorios configurados en tu organización, y solo si ese recordatorio tiene activado el canal de webhook. Sirve para avisarle al cliente también por tus propios canales.

A diferencia del resto de los eventos de cliente, no incluye el objeto subscription: el recordatorio describe una fecha de cobro, no un cambio en la suscripción.

Payload
{
  "eventType": "PAYMENT_REMINDER_PRE_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "reminder": {
    "type": "pre_payment",
    "daysOffset": 3,
    "billingDate": "2026-10-01 00:00:00+00"
  }
}

PAYMENT_REMINDER_POST_EVENT

Mismo formato que el anterior, pero para recordatorios posteriores: después de un cobro fallido, o para un pago manual que sigue pendiente.

Payload
{
  "eventType": "PAYMENT_REMINDER_POST_EVENT",
  "client": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "cliente@email.com",
    "name": "Juan",
    "lastName": "Pérez"
  },
  "reminder": {
    "type": "post_failure",
    "daysOffset": 2,
    "billingDate": "2026-10-01 00:00:00+00"
  }
}

Campos de reminder

CampoTipoDescripción
typestringQué clase de recordatorio es: pre_payment, post_failure o manual_payment
daysOffsetnumberDías de separación respecto a billingDate que configuraste para este recordatorio
billingDatestringFecha de cobro a la que se refiere el recordatorio. Es una marca de tiempo con zona horaria, tal como se guarda, no una fecha suelta

Los dos eventos se distinguen por el eventType, pero el type de adentro es más específico: PAYMENT_REMINDER_POST_EVENT llega tanto con post_failure como con manual_payment. Si tratas esos dos casos distinto, ramifica por reminder.type, no por el eventType.

Estos eventos no incluyen los objetos subscription, invoice ni payment.


GATEWAY_API_KEY_EXPIRING_EVENT

Evento a nivel de organización. Se envía cuando la API key del gateway de pago está próxima a vencer, como recordatorio para que la organización renueve sus credenciales antes de que dejen de funcionar.

Se emite por cada umbral de aviso configurado (por defecto 3 días y 1 día antes del vencimiento). Cada umbral se envía una sola vez por ventana de vencimiento; al renovar la key, los avisos vuelven a habilitarse para el nuevo período.

Payload
{
  "eventType": "GATEWAY_API_KEY_EXPIRING_EVENT",
  "organizationId": "wc8opaq1y1j5",
  "configId": "550e8400-e29b-41d4-a716-446655440000",
  "bankId": "660e8400-e29b-41d4-a716-446655440000",
  "expiresAt": "2026-07-16T16:16:19.742Z",
  "daysRemaining": 3
}

Campos

CampoTipoDescripción
organizationIdstringID de la organización dueña de la configuración
configIdstring (UUID)ID de la configuración del gateway (gateway_bank_config)
bankIdstring (UUID)ID del banco asociado a la configuración
expiresAtstring (ISO 8601)Fecha y hora exacta de vencimiento de la API key
daysRemainingnumberDías restantes hasta el vencimiento al momento del aviso

Nota: El payload nunca incluye la apiKey ni el apiSecret.


GATEWAY_API_KEY_EXPIRED_EVENT

Evento a nivel de organización. Se envía cuando la API key del gateway ya venció y el sistema la desactivó automáticamente. A partir de este momento, la organización no podrá procesar cobros hasta cargar credenciales nuevas.

Payload
{
  "eventType": "GATEWAY_API_KEY_EXPIRED_EVENT",
  "organizationId": "fse0srailt3v",
  "configId": "550e8400-e29b-41d4-a716-446655440000",
  "bankId": "660e8400-e29b-41d4-a716-446655440000",
  "expiresAt": "2026-06-12T17:47:13.325Z"
}

Campos

CampoTipoDescripción
organizationIdstringID de la organización dueña de la configuración
configIdstring (UUID)ID de la configuración del gateway (gateway_bank_config)
bankIdstring (UUID)ID del banco asociado a la configuración
expiresAtstring (ISO 8601)Fecha y hora en que la API key venció

Nota: El payload nunca incluye la apiKey ni el apiSecret. Además del webhook, la organización recibe un email a sus administradores y el equipo de Venflow recibe un aviso interno por Slack.


Orden de Eventos en un Checkout

Durante un flujo de checkout típico, los eventos se emiten en este orden:

1. USER_CREATE_EVENT          → Cliente creado (solo si es nuevo)
2. SUBSCRIPTION_CREATE_EVENT  → Suscripción activada
3. INVOICE_CREATE_EVENT       → Factura generada
4. PAYMENT_SUCCESS_EVENT      → Pago completado
5. INVOICE_UPDATE_EVENT       → Factura marcada como pagada

Flujo de Error

  • PAYMENT_FAILED_EVENT puede ocurrir en cualquier etapa del procesamiento de pago
  • Se pueden recibir múltiples PAYMENT_FAILED_EVENT para la misma transacción (reintentos)
  • Si el cobro falla definitivamente, se envía INVOICE_UPDATE_EVENT con estado uncollectible seguido de SUBSCRIPTION_CANCELLED_EVENT con razón payment_failure

Valores de Estado

ObjetoCampoValores Posibles
subscriptionstatusactive, past_due, pending, trialing, waiting_start, cancelled
paymentstatuspending, completed, failed
invoicestatusopen, paid, overdue, uncollectible, cancelled

Qué significa cada estado de suscripción

EstadoSignificado
trialingEstá en período de prueba. Todavía no se le ha cobrado nada.
waiting_startTiene fecha de inicio futura. Aún no empieza a cobrarse.
pendingLista para cobrarse, pero todavía sin un cobro exitoso.
activeAl día.
past_dueFalló un cobro y se está reintentando. Sigue siendo cobrable.
cancelledTerminada. No se cobra más.

Trata este campo como texto libre, no como una lista cerrada. La lista de arriba es la que emitimos hoy, pero el estado interno tiene más valores y podemos empezar a exponer alguno nuevo. Si tu código hace switch sobre status, incluye siempre una rama por defecto que no rompa — en vez de asumir que el valor que llegó es uno de los seis.

Programar una cancelación no emite ningún webhook. Cuando cancelas al final del período, el SUBSCRIPTION_CANCELLED_EVENT llega recién el día en que la cancelación se ejecuta, con cancellationReason.type: "scheduled_cancellation". Si necesitas enterarte en el momento en que se agenda, consulta GET /v1/subscriptions/{id} y mira cancel_at_period_end.