Webhooks y conciliación
Los eventos del flujo de cobro, cómo identificar con qué se pagó cada checkout y cómo cuadrar tus ventas contra tu balance.
Webhooks y conciliación
Los eventos de Pagos usan la infraestructura estándar de webhooks de Venti: mismo formato, misma firma, mismos reintentos. Aquí solo se documenta qué eventos emite este producto y cómo usarlos.
Eventos
Cada evento llega como { "id": "evt_...", "type": "...", "live": true, "data": { ...objeto... } }.
| Evento | Cuándo | data |
|---|---|---|
checkout.created | Se creó un checkout | El checkout |
checkout.paid | El cliente pagó | El checkout, con successful_object y su FK |
checkout.canceled | Lo cancelaste | El checkout |
checkout.expired | Venció sin pagarse | El checkout |
checkout.refunded | Se reembolsó (total o parcialmente; se emite en cada reembolso) | El checkout, con refunded_amount acumulado |
payment.created | Se creó un intento de pago | El pago |
payment.authorized | El pago quedó autorizado | El pago |
payment.captured | El pago quedó capturado (el cobro se hizo efectivo) | El pago |
payment.failed | La autorización falló | El pago, con status_reason |
payment.canceled | Se canceló una autorización sin capturar | El pago |
payment.refunded | Se reembolsó el pago | El pago |
refund.created / refund.pending / refund.succeeded / refund.failed | Ciclo de vida de cada devolución | El refund |
coupon.created | Se creó un cupón | El cupón |
Para la mayoría de las integraciones basta con escuchar los eventos decheckout.*: son el resumen de negocio. Los eventos depayment.*yrefund.*te dan el detalle operacional (intentos, capturas, estado de cada devolución).
Identificar con qué se pagó
En todo checkout.paid, mira successful_object:
successful_object | FK presente | Qué significa | Impacto en tu balance |
|---|---|---|---|
payment | payment_id | Medio de pago externo (tarjeta, transferencia, etc.) | Abono al capturarse |
loan | loan_id | Compra en cuotas BNPL de Venti | Abono por el total de la venta |
account_entry | account_entry_id | Cuenta de crédito de Cuentas Venti | Sin impacto (deuda del cliente) |
Con expand[]=payment, expand[]=loan o expand[]=account_entry (y expand[]=payment_method) traes el detalle en una sola llamada a GET /checkouts/{id}.
Conciliación contable
La regla de oro: el negocio vive en el checkout; el dinero vive en las transacciones de balance. Cada transacción de balance referencia su origen (payment_id, loan_id, refund_id), así que puedes cuadrar línea por línea:
| Evento de negocio | Objeto | Transacciones de balance |
|---|---|---|
| Venta pagada con medio externo | Payment capturado | payment (+), fee (−), tax_fee (−), payout_fee (−) si aplica |
| Venta pagada en cuotas BNPL | Loan exitoso | loan (+), fee (−), tax_fee (−) |
| Venta pagada con Cuentas Venti | AccountEntry | Ninguna (la cobranza abona después) |
| Reembolso | Refund exitoso | refund (−); fee_reimbursement / tax_fee_reimbursement (+) solo si tu comercio reembolsa comisiones |
| Contracargo | Dispute | dispute (−) |
| Pago a tu banco | Payout | Consume el balance disponible |
En la práctica:
- La fecha contable (
accounting_at) es el día hábil de la captura — una venta capturada un sábado cuadra contra el lunes. - Concilia ventas con
GET /payments?payout_id=pou_...oGET /balance_transactionsfiltrando por tipo; el neto de una venta espayment − fee − tax_fee. - Usa
external_idal crear tus checkouts: viaja en cada evento y te permite cruzar contra tus órdenes sin tablas intermedias.
Idempotencia y reintentos
- Un endpoint que no responde
2xxse reintenta durante 3 días; después el intento se descarta. Responde200rápido y procesa en segundo plano. - Los eventos pueden llegar más de una vez y fuera de orden: deduplica por el
iddel evento (evt_...) y usa elstatusdel objeto endatacomo fuente de verdad, no el orden de llegada. checkout.refundedse emite por cada reembolso parcial: usarefunded_amount(acumulado) en vez de sumar los eventos.
Modo test
Todo el flujo funciona con tu API key de test: checkouts, pagos con tarjetas de prueba, webhooks y reembolsos (instantáneos en test). Los objetos de test llevan live: false y nunca se mezclan con los de producción.
Updated 1 day ago

