Skip to main content
Se requiere identidad aprobada antes de cobrar con la cuenta autenticada. Una cuenta persona necesita KYC aprobado y una cuenta empresa necesita KYB aprobado antes de crear un payin. Aplica a POST /v1/payins (QR, card, checkout, bank_transfer y fintoc), POST /v1/payins/collect/otp, POST /v1/payins/collect y POST /v1/payins/deposit-accounts, además de cobros con tarjeta guardada y POST /v1/subscriptions. Sin aprobación, estas requests responden HTTP 403 verification_required.
Este gate aplica a la creación autenticada de la cuenta. Las páginas públicas de links ya creados siguen cobrables, los abonos pasivos ya recibidos siguen procesables, la asignación operativa de org-admin sigue disponible y los instrumentos de depósito creados por el sistema no se bloquean.
Un payin es un cobro fiat: tu cliente paga en moneda local y una cuenta nueva USD-principal se acredita directamente en USD con 2 decimales. Las cuentas existentes con USDT explícito conservan USDT. Si se configura otro asset, el neto sigue la conversión post-crédito con tu tasa de payin (payin_rate en GET /v1/rates) menos la comisión fija. Sea cual sea la modalidad, todos los caminos terminan igual — abono automático + webhook:

1. Descubre los corredores disponibles

Los países, monedas y modalidades disponibles los define CBPay. Consúltalos siempre por catálogo:
delivery indica cómo se confirma el pago del lado de CBPay (notificación del banco, sondeo o ambos) — no cambia nada en tu integración: tú siempre recibes el webhook payin_credited. Corredores y modalidades de cobro:
Venezuela (VES): el cobro activo está disponible mediante c2p. El pagador genera una claveDinamica en la app de su banco y te la entrega; tu integración la envía en el campo otp del collect. No existe una llamada previa a /collect/otp para C2P. debito_inmediato no es un corredor vivo. Los pagos salientes a Venezuela (pago_movil, bank_transfer) no cambian: ver payouts.
La disponibilidad puede variar; el catálogo (GET /v1/payins/methods) es siempre la fuente de verdad. En todos los casos el abono llega igual: se convierte a USDT al payin_rate cotizado y se acredita neto de la comisión fija de payin. Los lotes payin se consumen FIFO al aplicar el crédito. Si el inventario habilitado no alcanza, la cotización existente sigue siendo autoritativa y el faltante se registra como fallback spot con alerta operativa. Si prefieres quedarte con tus cobros en otro saldo (USDC, BTC o GOLD), configura default_payin_asset — ver el modelo de dinero.

2. Elige la modalidad y crea el cobro

Cada país tiene su propia modalidad de cobro. El request y la respuesta real de cada una:
Página de pago hosted (fintoc) — recomendado: recibes una payment_url; el pagador la abre y transfiere desde cualquier banco o billetera chilena (Banco Estado, Santander, Mach, Tenpo, Mercado Pago…). El pago se detecta y valida automáticamente — sin referencias manuales.
Respuesta 201:
Comparte la payment_url con el pagador (link, redirección o WebView). Cuando el pago se confirma, tu cuenta se acredita en USD y recibes el webhook payin_credited. El monto CLP debe ser entero (el peso chileno no usa decimales) y la sesión de pago vence en 24 horas por defecto. Un retry con la misma idempotency_key devuelve el mismo payin y la misma URL — nunca abre una segunda sesión de pago.Transferencia anunciada (alternativa manual): anuncias el depósito entrante y compartes la referencia con quien transfiere.
Respuesta 201:
Cuando la transferencia llega, se matchea por la referencia en la glosa y tu cuenta se acredita automáticamente. Si la referencia no viaja, el documento del pagador la respalda — ver conciliación de una transferencia anunciada.

Cobro activo (pull)

Algunos corredores ofrecen un cobro pull donde el pagador autoriza un débito. La cuenta debe tener su identidad aprobada antes del request.

C2P de Venezuela

Para VE/VES/c2p, el pagador primero genera una claveDinamica en la app de su banco. Tu integración envía ese valor como otp; no es un OTP que CBPay devuelva y no existe un paso de solicitud de OTP:
El request usa el contrato collect existente. payer_document, payer_phone, payer_bank y otp son los datos que necesita el riel C2P; otp lleva la clave dinámica generada por el banco. La respuesta conserva el shape actual y, si se aprueba en forma síncrona, incluye paid: true, provider_reference y los identificadores del payin acreditado.

Métodos pull basados en OTP

La plataforma evalúa al pagador antes de llamar al core. Un hold responde 202 in_review sin cobrar; reintenta el mismo request después de la aprobación. Si la cuenta no está aprobada, el collect responde 403 verification_required antes de ejecutar el corredor. Un timeout o 5xx no autoriza una operación nueva: conserva el mismo contexto de idempotencia y sigue el estado de la operación. Revisa siempre GET /v1/payins/methods, porque la disponibilidad puede cambiar. El link de cobro universal ahora tiene su propia guía, con el cotizador, todos los rieles y los endpoints públicos:

Checkout

Un solo link donde el pagador elige cómo pagar — fiat en todos los países activos, crypto, tarjeta o la app CBPay — liquidado en el saldo que elijas.

Tarjetas guardadas y cobros recurrentes (tarjeta)

Las credenciales guardadas (COF) y las suscripciones agendadas ahora tienen su propia guía:

Tarjetas guardadas y suscripciones

Guarda tarjetas con consentimiento del pagador, cóbralas con un clic o sin el pagador presente, y agenda suscripciones recurrentes.

Devoluciones (tarjeta)

Un cobro con tarjeta ya acreditado se devuelve total o parcialmente desde tu saldo, con su asiento en la cartola, comprobante y webhook:

Devoluciones de cobros

Devuelve total o parcialmente un cobro con tarjeta, anula un cargo del día y entiende cómo se aplica un contracargo.

Conciliación de una transferencia anunciada

Una transferencia anunciada (method: "bank_transfer") no tiene sesión de pago: el pagador mueve la plata desde su propio banco, así que el depósito se reconoce cuando llega. La conciliación corre en este orden y se detiene en el primer acierto:
  1. reference — el código de 12 caracteres en la glosa de la transferencia.
  2. Documento del pagador — el payer_document del anuncio contra el pagador que reporta el banco (puntos, guiones y dígito verificador se ignoran).
  3. Candidato único — exactamente un anuncio pendiente por ese monto y moneda.
Si ninguno de los tres resuelve a un anuncio — dos anuncios pendientes por el mismo monto, sin referencia y sin documento del pagador — el depósito no se acredita por adivinanza: queda unassigned y tu operador CBPay lo enruta. Nada se pierde; la plata ya está en la cuenta recaudadora.

Identificar al pagador (opcional, recomendado)

method: "bank_transfer" acepta los datos del pagador. Todos los campos son opcionales y aditivos — las integraciones existentes siguen funcionando igual:
payer_source viene SIEMPRE en la respuesta para que tu checkout sepa qué pedirle al pagador:
Un documento de menos de 5 caracteres o sin dígitos se descarta como señal (no se puede distinguir de un monto o un código de banco). El anuncio se crea igual y payer_source reporta la cobertura real.

Reintentos e idempotencia

El anuncio acepta idempotency_key (en el body) o el header Idempotency-Key. Un reintento con la MISMA clave devuelve el anuncio original — misma reference — con idempotency_hit: true y HTTP 200, en vez de crear un segundo anuncio.
Dos anuncios vivos idénticos (misma cuenta, moneda, monto y pagador) son justo el caso que la conciliación se niega a resolver: el depósito real calza con ambos y queda unassigned. Por eso un POST sin clave reutiliza un anuncio vivo idéntico en lugar de duplicarlo (también 200 con idempotency_hit: true).Para cobrar dos pagos reales del mismo monto al mismo pagador, manda una idempotency_key distinta en cada uno — cada clave crea su anuncio con su propia reference.
Las claves son únicas por cuenta y por operación lógica: si reutilizas una idempotency_key que ya usaste con OTRO método de payin (QR, checkout, tarjeta), la API responde 409 idempotency_conflict en vez de devolverte un objeto que no corresponde.

Instrucciones de depósito: a dónde transferir

En los corredores donde tu organización registró una cuenta de destino para transferencias anunciadas (hoy Chile, Paraguay y Estados Unidos), la respuesta del anuncio incluye un bloque deposit_instructions — la cuenta bancaria exacta a la que el pagador debe transferir, con el monto y la reference ya incrustados en un QR para copiar:
Respuesta 201 (con instrucciones de depósito)
También puedes previsualizar la cuenta de destino antes de crear un payin — útil para mostrarle al pagador a dónde tendrá que transferir una vez que confirme:
Respuesta 200
En el corredor US/USD el preview devuelve dos bloques: el riel doméstico bajo deposit_instructions y, cuando tu organización tiene configurada la variante internacional, el riel SWIFT bajo deposit_instructions_swift (mismo shape, con su propio QR). Los campos de riel están ausentes (no vacíos) en los corredores que no los usan:
Respuesta 200 (US)
El qr_payload del endpoint de preview no lleva las líneas Amount/ Reference (todavía no existe el payin); el que va embebido en un anuncio real siempre las lleva, así el pagador puede pagar sin escribir nada a mano. Ambos bloques del anuncio son una fotografía congelada: si tu operador CBPay actualiza después una cuenta registrada, los anuncios ya vivos siguen apuntando a la cuenta con la que se crearon — solo los nuevos toman el cambio.
Los mismos bloques deposit_instructions (y deposit_instructions_swift, cuando existe) se repiten en GET /v1/payins/{id} y en el listado (GET /v1/payins), así tu front no necesita cachearlo de la respuesta de creación. En corredores sin cuenta de destino registrada, el campo simplemente está ausente — en ese caso muestra la reference y pídele al pagador que use los datos bancarios habituales de tu organización.

Metadatos de cuenta dedicada e identidad del pagador

Los pushes acreditados en una cuenta de depósito dedicada exponen instrument_id, un bloque instrument y el bloque payer del banco — forma completa en la guía de Fondeo. Filtra el historial con ?instrument_id=<uuid>.

3. Recibe el abono

Cuando el pago llega (por cualquiera de las modalidades), tu cuenta se acredita automáticamente y se emite el webhook payin_credited:
fx_rate es tu payin_rate del momento del abono — la conversión se hace exactamente a esa tasa: usdt_gross = 700.00 / 6.91. Cuando aparece, rate_source indica el origen de la cotización (lot o spot); los payins históricos sin cotización cargada omiten el campo. El objeto payin queda con el detalle completo:

Estados

Un depósito que no se puede resolver a un único anuncio queda unassigned hasta que el equipo de CBPay lo asigna a una cuenta (ver conciliación de una transferencia anunciada). Al asignarse, se acredita con la tasa y comisiones de la cuenta destino, y el anuncio al que pertenecía se cierra.
Cuando un cobro activo (QR o checkout) muere sin pago, el payin pasa de pending a expired (o failed) automáticamente y recibes el webhook payin_expired. No se mueve dinero: si quieres reintentar el cobro, crea un payin nuevo.

Consulta e historial

from/to van en YYYY-MM-DD (zona horaria de tu organización); fecha inválida responde 400 invalid_range. method y kind acotan el riel y el tipo de payin, refund_status acepta none, partial o full, y search hace una coincidencia parcial sin distinguir mayúsculas/minúsculas sobre el ID del payin, la referencia o la clave de idempotencia.

Errores frecuentes

GET /v1/payins/deposit-instructions responde 404 not_found cuando el corredor no tiene una cuenta de destino activa configurada — trátalo igual que el 422 de arriba: todavía no puedes mostrarle una cuenta al pagador.

FAQ

Suscríbete a payin_credited: trae la tasa FX aplicada, la comisión y el usdt_credited exacto. También puedes consultar GET /v1/payins/{id}.
El payin_rate cotizado por GET /v1/rates y vigente al momento de acreditar. Revisa payin_rate_source: lot significa que el inventario USDT payin habilitado respaldó la cotización; spot significa que se usó spot. Tu spread acordado ya viene dentro de la tasa — nunca se itemiza.
Sí — configura default_payin_asset con PUT /v1/settlement. Las cuentas nuevas acreditan directo en centavos USD. Las existentes con USDT explícito conservan USDT; otro destino configurado usa el flujo de conversión post-crédito y conversion_status reporta done o pending_retry.
Recibes payin_expired y el payin se cierra sin mover dinero. Crea un cobro nuevo — nada se debitó ni acreditó.
La referencia sigue calzando con el anuncio, pero se acredita el monto que llegó. Una transferencia que no resuelve a ningún anuncio queda unassigned para conciliación; tu equipo CBPay puede asignarla manualmente al payin correcto.
A nadie por azar. Si el documento del pagador no los distingue, ambos anuncios quedan pending y el depósito queda unassigned para que el operador lo enrute. Mandar payer_document en el anuncio es lo que convierte este caso en un abono automático.
No — es opcional y nada se rompe sin él. Si lo omites, se usa el RUT verificado de la cuenta (payer_source: account_identity), que cubre los depósitos del propio titular. Mándalo cuando un tercero pague por tu cliente, y muéstrale SIEMPRE la reference al pagador.
No. Con idempotency_key (body o header Idempotency-Key) el reintento devuelve el anuncio original con idempotency_hit: true. Incluso sin clave, un POST idéntico a un anuncio vivo (misma cuenta, moneda, monto y pagador) lo reutiliza — duplicarlo dejaría el depósito real unassigned por ambigüedad. Manda claves distintas solo cuando de verdad quieras cobrar dos veces.
El corredor publica dos cuentas de destino a propósito, y tu pagador elige el riel que su banco soporta: quienes bancan dentro de EE. UU. usan el riel doméstico (deposit_instructions) con el routing_number (ABA) — un Fedwire o ACH; quienes envían desde fuera de EE. UU. usan el riel internacional (deposit_instructions_swift) con el swift (BIC), el banco corresponsal (intermediary_bank_name / intermediary_bank_swift) y las indicaciones de notes para el formulario del wire. Cualquiera sea el riel, la reference (CB…) en el campo memo / remittance es lo que acredita el depósito automáticamente. Un wire se reporta normalmente el mismo día hábil; un ACH puede tardar de uno a tres días hábiles según el banco emisor — el crédito y el webhook payin_credited ocurren en cuanto el banco reporta el abono.
Los bancos no comparten un estándar de QR común para cuentas de destino arbitrarias (a diferencia de un QR de comercio en un checkout) — cada banco codifica las transferencias de forma distinta, y la mayoría de las apps bancarias no puede auto-completar una transferencia desde un QR de un tercero. qr_png_base64 renderiza los datos de la cuenta como QR únicamente como atajo de copiado en el celular: el pagador lo escanea, obtiene el texto multilínea (banco, cuenta, titular, monto, referencia) y lo pega en el formulario de transferencia de SU banco — la transferencia la confirma él mismo. No construyas un flujo de escanear-y-pagar alrededor de esto; muéstralo junto a los campos en texto plano para que el pagador siempre pueda escribirlos a mano.

Plazo de liquidación de payins con tarjeta

En los payins con tarjeta, settlement_hours controla cuándo queda disponible el saldo después de confirmar el pago. Acepta 0 o un múltiplo de 24: 0 deja el saldo disponible de inmediato, mientras 24 equivale a un día hábil de EE. UU. y 48 a dos. Los días hábiles son de lunes a viernes, excluyendo feriados federales observados de EE. UU., según la zona horaria de tu organización. Por ejemplo, viernes a las 15:00 más 48 horas liquida el martes a las 15:00 si no interviene un feriado; sábado más 48 horas también liquida el martes. Un valor como 27 se rechaza con HTTP 400 invalid_settlement_hours. El pago se confirma de inmediato como credited; solo el saldo espera hasta settle_at. Los valores settle_at existentes y las configuraciones anteriores no múltiplo mantienen la semántica de horas calendario.

Retención de fiat local

Activa fiat_hold_local: true con PATCH /v1/accounts/{accountID} para que los créditos futuros BOB, MXN o ARS permanezcan en su saldo local. Los créditos existentes no se modifican. credit_asset siempre aparece y fiat_credited solo para fiat local; usdt_credited sigue siendo el equivalente USDT. Las tarjetas liquidan en USD y las conversiones, swaps de checkout y ofertas OTC saltan los payins retenidos.
refunded_amount usa las unidades de credit_asset (micro-USDT para USDT y unidades minor de fiat para BOB/MXN/ARS). usdt_credited siempre está en micro-USDT. Ramifica por credit_asset; jamás calcules usdt_credited - refunded_amount cuando el crédito sea fiat.

USD como activo principal del ledger

Las cuentas usan USD como valor predeterminado de settlement_asset y payin_settlement_asset; cámbialo cuando quieras con PUT /v1/settlement. Las operaciones en vuelo nunca se vuelven a cotizar. Los montos del ledger en USD usan centavos (dos decimales). Los créditos y d débitos directos, las comisiones y los flujos de payout, checkout, POS y tarjetas usan USD solo cuando el campo de activo de ese flujo lo acepta. Los swaps entre USD y USDT usan paridad 1:1 y no consultan un oráculo FX. BOB, MXN y ARS siguen siendo activos fiat separados del ledger; los payouts en la misma moneda debitan esos saldos directamente (ver payouts). Un payin acreditado directamente a una cuenta USD-principal expone credit_asset: USD y el monto fiat acreditado en centavos; usdt_credited sigue siendo el equivalente USD para reportes. El hold de una controversia sigue el activo acreditado: los créditos USD usan hold_asset: USD. disputed y held usan las unidades del activo retenido; disputed_usdt y held_usdt son equivalentes normalizados.
Última modificación el 17 de octubre de 2026