Skip to main content
Un payin es un cobro fiat: tu cliente paga en moneda local y tu cuenta recibe el abono en USDT automáticamente, convertido a tu tasa de payin (payin_rate en GET /v1/rates) menos la comisión fija de payin si tu cuenta la tiene configurada. 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: 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 a tu payin_rate del momento y se acredita neto de la comisión fija de payin. 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 USDT 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.
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.

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

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 vigente al momento de acreditar (ver GET /v1/rates). Tu spread acordado ya viene dentro de la tasa — nunca se itemiza.
Sí — configura default_payin_asset con PUT /v1/settlement. El crédito sigue entrando en USDT y se convierte inmediatamente después a precio real; conversion_status reporta done o pending_retry (se reintenta solo).
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.
La respuesta y GET /v1/payins/{id} persisten un bloque failure con el código y mensaje del riel (por ejemplo, un documento que no calza con el registro bancario del pagador). Corrige el dato y reintenta con clave nueva.
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.
Última modificación el 19 de agosto de 2026