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... } }.

EventoCuándodata
checkout.createdSe creó un checkoutEl checkout
checkout.paidEl cliente pagóEl checkout, con successful_object y su FK
checkout.canceledLo cancelasteEl checkout
checkout.expiredVenció sin pagarseEl checkout
checkout.refundedSe reembolsó (total o parcialmente; se emite en cada reembolso)El checkout, con refunded_amount acumulado
payment.createdSe creó un intento de pagoEl pago
payment.authorizedEl pago quedó autorizadoEl pago
payment.capturedEl pago quedó capturado (el cobro se hizo efectivo)El pago
payment.failedLa autorización fallóEl pago, con status_reason
payment.canceledSe canceló una autorización sin capturarEl pago
payment.refundedSe reembolsó el pagoEl pago
refund.created / refund.pending / refund.succeeded / refund.failedCiclo de vida de cada devoluciónEl refund
coupon.createdSe creó un cupónEl cupón
📘

Para la mayoría de las integraciones basta con escuchar los eventos de checkout.*: son el resumen de negocio. Los eventos de payment.* y refund.* 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_objectFK presenteQué significaImpacto en tu balance
paymentpayment_idMedio de pago externo (tarjeta, transferencia, etc.)Abono al capturarse
loanloan_idCompra en cuotas BNPL de VentiAbono por el total de la venta
account_entryaccount_entry_idCuenta de crédito de Cuentas VentiSin 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 negocioObjetoTransacciones de balance
Venta pagada con medio externoPayment capturadopayment (+), fee (−), tax_fee (−), payout_fee (−) si aplica
Venta pagada en cuotas BNPLLoan exitosoloan (+), fee (−), tax_fee (−)
Venta pagada con Cuentas VentiAccountEntryNinguna (la cobranza abona después)
ReembolsoRefund exitosorefund (−); fee_reimbursement / tax_fee_reimbursement (+) solo si tu comercio reembolsa comisiones
ContracargoDisputedispute (−)
Pago a tu bancoPayoutConsume 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_... o GET /balance_transactions filtrando por tipo; el neto de una venta es payment − fee − tax_fee.
  • Usa external_id al 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 2xx se reintenta durante 3 días; después el intento se descarta. Responde 200 rápido y procesa en segundo plano.
  • Los eventos pueden llegar más de una vez y fuera de orden: deduplica por el id del evento (evt_...) y usa el status del objeto en data como fuente de verdad, no el orden de llegada.
  • checkout.refunded se emite por cada reembolso parcial: usa refunded_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.