purpose: "banking" para conservar el fiat local en payouts; fondeo (por defecto) convierte el abono a tu asset principal (USD es el saldo principal). Banking admite solo BO/BOB/bank_transfer, MX/MXN/bank_transfer y AR/ARS/bank_transfer.
Dos clases de destinos fiat locales
Para los corredores fiat locales (BO/BOB, MX/MXN, AR/ARS), cada
destino de payin lleva un purpose que decide dónde aterriza el dinero
entrante:
Crea un segundo destino con
purpose: "banking" para mantener fiat local
para payouts; los destinos creados sin propósito conservan el comportamiento
histórico fondeo. El propósito banking solo se admite en
BO/BOB/bank_transfer, MX/MXN/bank_transfer y AR/ARS/bank_transfer.
Banking por moneda
🇺🇸 USD — dólar estadounidense
Abre una cuenta Banking clásica (rieles ACH, Fedwire y SWIFT) con el flujo perfil → cuentas → operaciones de esta guía (abrir cuentas bancarias). Los USD recibidos por Banking se mantienen para payouts (payouts); los USD enviados a tus saldos CBPay aterrizan en tu asset principal (USD es el saldo principal).🇪🇺 EUR — euro
Todo lo euro pasa por un IBAN virtual: solicita una direcciónfunding_usdt
para convertir los euros entrantes a tu asset principal, o una dirección
banking_eur para mantener BANK_EUR para payouts SEPA
(dirección de fondeo y banca EUR).
Enviar euros a terceros se cubre en
payouts SEPA Instant.
🇧🇴 BOB — boliviano
Recibe bolivianos por cuentas de depósito con unpurpose: fondeo (por defecto) convierte el abono a tu asset principal
(USD es el saldo principal); banking conserva BOB para payouts locales.
Ver Fondeo para el flujo de fondeo.
🇲🇽 MXN — peso mexicano
Recibe pesos por cuentas de depósito con unpurpose: fondeo (por defecto) convierte el abono a tu asset principal
(USD es el saldo principal); banking conserva MXN para payouts locales
(payouts).
Multi-banking para empresas: cuentas operativas
Las cuentas empresa pueden crear múltiples cuentas de depósito conpurpose: "banking" en cada corredor local habilitado:
BO/BOB, MX/MXN y AR/ARS, siempre con method: "bank_transfer".
Usa un Idempotency-Key distinto para cada destino; repetirlo devuelve el
mismo instrumento. El tope operativo blando es de 50 instrumentos banking
por cuenta empresa y corredor (422 deposit_account_limit_reached).
Las cuentas persona mantienen un instrumento banking por corredor.
El label es un apodo local opcional de hasta 60 caracteres y se puede
cambiar o limpiar con PUT /v1/payins/deposit-accounts/{instrumentID}/label.
En AR/ARS, una empresa puede crear la CVU sin bank_alias: queda en
alias_pending y el saldo/movimientos responden 409 alias_pending hasta
completar PUT /v1/payins/deposit-accounts/{instrumentID}/bank-alias.
La persona conserva 400 missing_alias al crear.
Las lecturas operativas son:
currency, funds_model (retained en BO,
centralized en MX/AR), y los montos exactos en minor units:
credited_in, paid_out, refunded_in, refunded_out, other_net,
derived_available y display_available. Movimientos es una unión paginada
de payins y payouts; from y to son obligatorios.
Para payouts BO/BOB puedes enviar source_instrument_id (UUID) en
POST /v1/payouts o POST /v1/payouts/qr/confirm. Fuera de BO/BOB responde
400; un instrumento ajeno responde 404 not_found; uno no bancario o
inactivo responde 422 invalid_source_instrument. Sin UUID, varias fuentes
activas responden 422 ambiguous_source_instrument. MX/AR siguen usando la
madre/centralizador.
🇦🇷 ARS — peso argentino
Recibe pesos por cuentas de depósito con unpurpose: fondeo (por defecto) convierte el abono a tu asset principal
(USD es el saldo principal); banking conserva ARS para payouts locales
(payouts).
Las comisiones de banking vienen en dos formas. Las fijas standalone
(
banking_customer, banking_account, banking_operation) se debitan de tu
asset de settlement por defecto —USD es el saldo principal— al ejecutar cada operación y se reembolsan automáticamente
si falla. Las transaccionales por riel (banking_deposit,
banking_transfer_ach, banking_transfer_swift, banking_transfer_wire,
banking_transfer_sepa) son un porcentaje más un monto fijo cobrado en la
moneda de la operación (tu saldo BANK_USD / BANK_EUR) — ver
comisiones por riel. Con
comisión 0 (el default) el servicio es gratis. Los campos banking_fee y
banking_fee_asset de cada respuesta te muestran lo cobrado y en qué moneda.El flujo completo
- Crea tu perfil bancario (
POST /v1/banking/customer) — una sola vez. - Sube documentos de verificación y envíalo a revisión.
- Cuando quede
approved, abre cuentas por moneda. - Registra beneficiarios (counterparties) para pagos a terceros.
- Envía pagos: cotiza con
preparey ejecuta conoperations.
banking_customer_status_changed y banking_operation_status_changed
(webhooks).
1. Crea tu perfil bancario
Una vez por cuenta. Si no envíastype, name o email, se completan con
los datos de tu cuenta CBPay:
201:
409 banking_customer_exists.
Idempotencia durable. La plataforma deriva un claim determinista en el
core para esta cuenta/perfil. La primera solicitud exitosa responde
201.
Repetir la misma solicitud responde 201 con idempotency_hit: true, sin
crear un segundo perfil ni cobrar dos veces el fee del perfil. Un payload
distinto para la misma cuenta responde 409 idempotency_conflict. Si el
resultado upstream/core es ambiguo, la API responde
503 banking_recovery_pending; no reintentes con una clave nueva.
Operaciones debe reconciliar primero el claim durable.Revisión de solicitudes. Si tu organización activó la revisión de solicitudes banking, esta llamada puede responder
202 Accepted con {"status":"in_review","kind":"banking_application","review_id":"…"} en vez de 201 — el perfil se crea solo cuando compliance aprueba la revisión. El fee del perfil banking se cobra al retener la solicitud y se reembolsa automáticamente si se rechaza. Sigue el resultado con el webhook txn_review_status_changed o en Revisiones de operaciones.EUR usa el flujo directo de vIBAN; el onboarding genérico es solo para USD.
Solicita
{"purpose":"banking_eur"} desde Operar EUR: no requiere un customer
Banking previo y la aprobación crea el vínculo local. El endpoint genérico
devuelve 400 banking_eur_requires_viban para EUR.2. Documentos y verificación
Sube cada documento en base64 (gratis):draft → submitted → under_review →
approved o rejected. El webhook
banking_customer_status_changed te avisa cada cambio — del perfil propio
(customer_kind: self) y de los terceros que registres
(customer_kind: third_party, con su third_party_id):
3. Abre cuentas bancarias
Con el perfilapproved, crea la cuenta del Banking clásico solo para USD (rieles ACH/Fedwire/SWIFT). EUR no se abre aquí: solicita un vIBAN banking_eur directamente en el flujo de vIBAN EUR.
201 — data incluye los datos para recibir (número de
cuenta/IBAN, routing, banco):
GET /v1/banking/accounts/{id}) devuelve la cuenta EN VIVO —
nombre, moneda, estado y bajo data los requisitos para recibir
fondos (rieles wire y locales: banco, número de cuenta/IBAN, routing).
Úsalo para mostrar las instrucciones de depósito de una cuenta específica
sin recorrer el listado:
source indica de dónde salió el detalle: live (el banco respondió en
vivo) o mirror (el banco no pudo servir la cuenta en ese momento y se
devuelve el último snapshot conocido — los requisitos de depósito siguen
disponibles).
El listado expone solo las cuentas habilitadas para tu operación según
la configuración del corredor. Una cuenta no habilitada no aparece en el
listado y sus consultas por id responden
404 not_found.Límite para cuentas persona: una cuenta persona puede tener máximo 1
cuenta bancaria. Al intentar la segunda recibirás
409 banking_account_limit. Las cuentas empresa no tienen límite.Usuarios de terceros (solo empresas)
Si tu cuenta es empresa, además de tus cuentas propias puedes dar de alta usuarios banking de terceros — tus clientes finales (personas o empresas) — cada uno con su identidad y verificación propias y cuentas bancarias a su nombre. Sin límite de terceros ni de cuentas por tercero.Alta del tercero
El alta exige elverification_id de una verificación KYC/KYB
aprobada del tercero — su identidad única en CBPay. El
tipo sale del kind de la verificación (KYC ⇒ INDIVIDUAL, KYB ⇒
COMPANY), los datos (nombre, email, dirección) se completan solos desde
el perfil verificado (lo que envíes explícito gana) y los documentos ya
validados se re-entregan automáticamente al proveedor bancario. Se cobra
el fee de perfil bancario (se reembolsa si el alta falla):
201:
documents_synced cuenta los documentos de la verificación que quedaron
cargados automáticamente en el perfil bancario del tercero. Si alguno no se
pudo sincronizar (o el banco pide categorías adicionales), súbelo por el
flujo manual de documentos de más abajo y luego haz submit.Revisión de solicitudes. Con la revisión de solicitudes banking activada, registrar un tercero también puede responder
202 Accepted (kind: banking_application): el tercero se registra solo cuando la revisión se aprueba, y el fee de registro se reembolsa automáticamente si se rechaza. Síguelo vía txn_review_status_changed o en Revisiones de operaciones.third_party_id: todas las rutas del tercero lo usan. Lista y
consulta (el GET trae el estado de verificación en vivo):
Verificación del tercero (gratis)
Igual que tu propio perfil, pero sobre el tercero:Cuentas del tercero
Con el tercero aprobado, ábrele cuentas (mismo feebanking_account) y
opera igual que con las tuyas:
- Cada tercero es tuyo y solo tuyo: otra cuenta CBPay jamás puede verlo ni
operarlo (responde
404). - Una cuenta persona que intente crear terceros recibe
403 company_required. - Sin
verification_id(o con una verificación no aprobada) el alta responde422 verification_required/422 verification_not_approved. Si envías untypeque no calza con el kind de la verificación,422 verification_kind_mismatch. Los terceros creados antes de esta regla siguen operando con normalidad. - Los terceros dados de alta alimentan la métrica “usuarios nuevos” de tu resumen de cuenta.
4. Registra beneficiarios
Para pagar a terceros, primero registra al beneficiario con sus datos bancarios (gratis; pasa por moderación antes de poder usarse):GET /v1/banking/counterparties y agrega más cuentas a
un beneficiario existente con
POST /v1/banking/counterparties/{id}/accounts.
Euros: dirección de fondeo y banca EUR en un solo lugar
Todo lo de euros vive aquí. Un IBAN virtual (vIBAN) EUR es un instrumento de direccionamiento y ruteo con uno de dos propósitos; no es un saldo separado del proveedor. El procesamiento de ingresos y returns/recalls está implementado para ambos propósitos; el onboarding de customers del proveedor y la activación productiva quedan fuera del contrato público provider-agnostic.Solicitar un vIBAN
La plataforma puede solicitar un IBAN virtual para una cuenta activa y verificada. Solicita la dirección de fondeo con una clave idempotente:funding_usdt es el propósito por defecto. La plataforma construye el
registrant desde el perfil KYC/KYB aprobado. Si el perfil verificado no trae
el país de emisión o el vencimiento del documento, la solicitud de cuenta
puede enviar estos overrides opcionales de nivel superior (se aceptan
aliases snake_case o camelCase):
incorporation_country / incorporationCountry y
incorporation_date / incorporationDate. Se usan solo para completar el
registrant verificado; no saltan KYC/KYB.
La solicitud entra a la cola de aprobación manual:
banking_eur se solicita explícitamente:
{page, page_size, virtual_ibans}. Los estados soportados son pending_approval, pending, active, rejected, failed,
disabled y closed. La cuenta ve el IBAN completo cuando fue asignado; la
lectura de organización lo muestra enmascarado.
Leer, cerrar y operaciones por dirección
Lee una solicitud por su ID:closed); el cierre es idempotente y
la lectura posterior refleja el estado final.
Lista las operaciones Banking de una sola dirección con
GET /v1/banking/virtual-ibans/{id}/operations (misma paginación y ventana
de fechas que el listado global de operaciones).
vIBAN para terceros
Las cuentas empresa pueden solicitar un vIBANbanking_eur para un tercero
propio después de que acepte la invitación y complete KYC/KYB aprobado. El
tercero es el dueño del saldo; la empresa administra la relación:
banking_eur y sigue la misma aprobación manual y
ciclo de estados de la solicitud de cuenta.
Saldo BANK_EUR
Para una solicitudbanking_eur, consulta el saldo conciliado:
asset: "BANK_EUR", available, held, purpose y
source. Para funding_usdt responde 409 balance_not_available, porque
ese propósito entra a la cadena de crédito de payin hacia tu asset principal y no mantiene BANK_EUR.
Enviar euros: payouts y operaciones Banking
Hay dos formas de enviar euros, y ambas leen la misma dirección. Distínguelas por la puerta, no por la dirección:
Lo que comparten ambas puertas:
- La fuente se selecciona en el nivel superior con
source_virtual_iban_id. Si la cuenta tiene exactamente un vIBAN con el propósito que corresponde a la puerta, puedes omitir el campo. Sin una fuente activa responde422 funding_account_required; con varias fuentes activas sin UUID explícito responde422 ambiguous_source_viban. - La plataforma elimina los campos de identidad ordenante enviados por el
caller y estampa
payerserver-side desde elregistrantdel vIBAN seleccionado, salvo que exista un payer de wallet corporativa más específico y también server-side. - En filas activas anteriores sin registrant utilizable, la plataforma deriva
los nombres desde el perfil verificado vigente. Si el perfil es ilegible,
la operación falla con
503 funding_account_unavailable; si la identidad queda incompleta, falla con422 registrant_incomplete. source_virtual_iban_idforma parte de la intención de la operación. Con la misma clave de idempotencia recibes la operación original; una request concurrente en vuelo devuelve409 operation_in_progress— reintenta con la misma clave.- No existe un tope por vIBAN. EUR Banking descuenta del saldo
BANK_EURde la cuenta. - Los holds de operaciones Banking creados antes de esta puerta quedan grandfathered y continúan por su flujo existente de dispatch y reconciliación.
Recibir euros: procesamiento de ingresos
Cuando el proveedor bancario envía un ingreso terminal, el core lo normaliza comobanking_virtual_iban_inbound. La plataforma resuelve el vIBAN dueño
y aplica su propósito:
funding_usdtcrea un payinbanking_fundingen EUR, aplica la tasa marcada EUR→USDT y el fee/spread configurado, y sigue el firewall y la cadena de crédito de payin.banking_eurcrea un espejo Banking enBANK_EUR, usa el camino del ledger, emite KYT/estado de operación y encola el comprobante por email.
completed, success, settled, credited o
succeeded) aplican el efecto financiero. Los estados pending/unknown
quedan reconciliables y no acreditan saldo.
failed y rejected son resultados terminales negativos. No crean un
crédito; un payin de fondeo aún no acreditado queda failed sin un loop de
refund.
Returns/recalls se procesan como eventos terminales
returned, recalled
o reversed. Un return antes del crédito impide que un replay posterior
acredite. Un payin funding_usdt ya acreditado crea el camino determinista
de chargeback/refund; una operación banking_eur ledgerizada recibe un
reverse append-only. Un evento de completion posterior no puede resucitar
una operación devuelta.payment_rail: "SEPA_INSTANT", purpose (funding_usdt o banking_eur)
y la referencia del vIBAN cuando el riel la informa.
Errores EUR
Preguntas frecuentes sobre euros
¿Solicitar un vIBAN crea un saldo BANK_EUR?
¿Solicitar un vIBAN crea un saldo BANK_EUR?
No. El propósito queda guardado en la solicitud, pero el vIBAN no es un saldo independiente del proveedor. Solo las direcciones
banking_eur exponen
un saldo BANK_EUR conciliado; funding_usdt acredita a tu asset principal por la cadena de
payin.¿Puedo reintentar después de un timeout?
¿Puedo reintentar después de un timeout?
Reintenta con la misma clave idempotente. Una clave nueva crea otra
solicitud y no debe usarse para adivinar el resultado de una llamada ambigua.
¿Por qué el estado es pending_approval?
¿Por qué el estado es pending_approval?
Cada asignación requiere aprobación manual de operaciones de la organización antes de llamar al riel bancario.
¿La misma dirección sirve para payouts y operaciones Banking?
¿La misma dirección sirve para payouts y operaciones Banking?
Cada puerta lee el propósito que le corresponde: los payouts SEPA ordenan
desde tu dirección de fondeo y las operaciones Banking desde tu dirección de
Banking. Un UUID explícito en
source_virtual_iban_id siempre gana sobre la
selección automática.Banking para terceros verificados
Una cuenta empresa puede solicitar un destino banking para una submission KYC o KYB aprobada de un tercero. El intento es idempotente por submission y corredor; al aprobarse la verificación se crea automáticamente el destino.intent_id, kind, verification_id, country,
currency, method, status y fulfilled_instrument_id. Los estados son
pending, fulfilled y abandoned; una verificación rechazada deja el
intento abandonado y una repetición responde 409 intent_abandoned.
Referenciar el onboarding propio responde 422 verification_invalid.
5. Envía pagos
Dos tipos de operación:
Cotiza primero (gratis, no mueve dinero):
banking_operation predeterminada cuando el riel no tiene configuración):
202:
banking_fee y banking_fee_asset solo aparecen cuando se cobró una
comisión. Con una comisión por riel el asset es la moneda de la operación
(BANK_USD / BANK_EUR); con el fallback predeterminado es tu asset de settlement por defecto.
- El estado final llega por el webhook
banking_operation_status_changed(completed/failed); también puedes consultarGET /v1/banking/operations/{id}. Cuando la operación queda en estado final, el webhook incluye sureceipt_urly puedes descargar el comprobante PDF conGET /v1/banking/operations/{id}/receipt(comprobantes). - Reintentos con la misma
Idempotency-Keydevuelven la operación original (idempotency_hit: true) sin volver a cobrar la comisión.
Trazabilidad completa. Cada operación bancaria queda registrada en tu
cuenta: aparece en la sección
banking_operations de la
cartola, su dinero cuadra en los saldos espejo
BANK_USD/BANK_EUR (sección assets), y su volumen suma al
gross_volume de analytics. El saldo autoritativo
sigue siendo el del banco: el espejo se reconcilia periódicamente.Toda operación bancaria — incluidos los depósitos entrantes y las comisiones
bancarias descubiertas automáticamente desde el banco — expone su
direction (in / out), amount neto, currency, counterparty y
reference cuando el banco los reporta. Estos campos son opcionales y
aparecen en GET /v1/banking/operations y
GET /v1/banking/operations/{id}.banking_operation_status_changed se mantiene liviano por
diseño: lleva los identificadores y el nuevo estado, nunca los campos
enriquecidos. Cuando llegue, consulta el detalle de la operación para leer
la dirección, el monto, la contraparte y la referencia. Ver
webhooks.
Comisiones por riel (depósitos y transferencias)
Además de las comisiones fijas standalone, banking soporta comisiones transaccionales por riel — un porcentaje más un monto fijo, siempre cobradas en la moneda de la operación (BANK_USD / BANK_EUR), nunca
en USDT:
En las transferencias el saldo disponible debe cubrir
monto + comisión
— si no alcanza, la API responde 402 insufficient_funds y la operación
no se crea. Si la operación es rechazada de forma definitiva justo
después del despacho, la comisión se reembolsa automáticamente (la misma
disciplina de la comisión predeterminada).
Fallback: si el riel no tiene configuración específica (ni a nivel cuenta
ni plataforma), se cobra la banking_operation predeterminada (fija, debitada de tu asset de settlement por defecto). Un
riel configurado con 0% + 0 fijo queda explícitamente gratis — NO cae al
fallback.
Estados de operación
Errores
FAQ
¿El dinero banking aparece en mi saldo USD?
¿El dinero banking aparece en mi saldo USD?
No. El dinero banking vive en tus cuentas bancarias y se consulta con
GET /v1/banking/accounts/{id}/balance. El saldo autoritativo es el del
banco; tu cartola lo concilia en los saldos espejo
BANK_USD/BANK_EUR. Las comisiones por riel se cobran en la moneda de
la operación (tu saldo BANK_USD/BANK_EUR); solo la comisión predeterminada
banking_operation se debita de tu asset de settlement por defecto.¿Qué pasa con la comisión si una operación falla?
¿Qué pasa con la comisión si una operación falla?
Se reembolsa automáticamente — comisiones de perfil, cuenta y operación por
igual, incluidas las comisiones por riel (reembolsadas en el rechazo
definitivo síncrono). Un reintento con la misma
Idempotency-Key devuelve
la operación original (idempotency_hit: true) y jamás cobra dos veces.¿Cuántas cuentas bancarias puedo abrir?
¿Cuántas cuentas bancarias puedo abrir?
Una por moneda (USD, EUR). Además, las cuentas persona pueden tener
como máximo 1 cuenta bancaria en total (
409 banking_account_limit); las
cuentas empresa no tienen límite.¿Por qué una de mis cuentas no aparece en el listado?
¿Por qué una de mis cuentas no aparece en el listado?
El listado solo expone las cuentas habilitadas para tu operación según
la configuración del corredor. Una cuenta no habilitada no aparece y sus
consultas por id responden
404 not_found — contacta a tu equipo CBPay si
necesitas habilitarla.¿Una cuenta persona puede registrar usuarios terceros?
¿Una cuenta persona puede registrar usuarios terceros?
No — los terceros son una capacidad de empresa (
403 company_required). El
registro además exige el verification_id de una verificación KYC/KYB
aprobada del tercero.¿Cómo sé cuándo un pago llegó a su estado final?
¿Cómo sé cuándo un pago llegó a su estado final?
Suscríbete a
banking_operation_status_changed: se dispara en completed
/ failed e incluye el receipt_url una vez final. También puedes
consultar GET /v1/banking/operations/{id}.Banking creation claims and recovery
Creation claims are durable records, not permission to send a second provider request. The platform storesbanking_creation_claims with kind,
idempotency_key, request_hash, status, attempts and refund state. Migration
105 creates this table and its single-flight lock; migration 106 stores
transaction-firewall fee-refund recovery. Migration 074 persists the resolved
core provider on customer idempotency claims.
Recovery rules
- A completed account recovery compares the provider account ownership with
the claimed customer’s
ProviderID. - A terminal provider authentication response (
401or403) does not by itself prove that the creation failed; the claim remains recoverable. - Reusing the same idempotency key with a different request hash is rejected.
- A completed claim can be replayed with HTTP
200andidempotency_hit: true; recovery does not call the provider again. POST /v1/org/banking/creation-claims/refundretries a pending fee refund forkind=customerorkind=account.POST /v1/org/txn-firewall/fee-refunds/{resourceID}/retryretries the durable firewall-fee refund. A completed refund replays as HTTP200.
POST /v1/ops/banking/account-creations/reconcile verifies the provider
account and finalizes the local mirror. The org-admin routes list claims,
reconcile customer claims, and retry refunds. These operations are locked so
concurrent reconciliation cannot originate duplicate money movement.