Saltar al contenido principal

Códigos de error

Toda falla que la plataforma clasifica viene con un código string estable de la familia B2B_* — nunca un número. Esta página es el catálogo completo. Para las formas en que puede llegar un cuerpo de error (hay más de una), ver manejo de errores.

{
"code": "B2B_INSUFFICIENT_BALANCE",
"category": "PERMANENT",
"message": "El balance disponible es insuficiente para completar la operación.",
"correlationId": "b6e1b6f0-0000-4000-8000-000000000000"
}
CampoTipoDescripción
codestringIdentificador estable y legible por máquina (B2B_*). Es seguro ramificar sobre él.
categorystringPERMANENT, TRANSIENT o UNKNOWN — define si un reintento puede llegar a servir.
messagestringExplicación legible por humanos, en español, sea cual sea el idioma en que leas esta doc. Para logs y operadores — nunca ramifiques sobre él.
correlationIdstringPresente cuando había un ID de correlación disponible. Inclúyelo cuando contactes a soporte.
detailsstring[]Solo en B2B_PROVIDER_REJECTED. El veredicto de la red de pagos, una entrada por campo rechazado, textual y en inglés. Te dice qué corregir; no es estable, así que nunca ramifiques sobre él. Ver qué te dice details.

Catálogo completo​

CódigoHTTPCategoríaQué significa¿Reintentar?
B2B_UNAUTHORIZED401PERMANENTCredenciales, token o firma de la request rechazados.No
B2B_COMPANY_NOT_FOUND404PERMANENTNo hay una compañía asociada a las credenciales usadas.No — contacta a soporte
B2B_QUOTATION_NOT_FOUND404PERMANENTLa cotización no existe, o no te pertenece.No
B2B_QUOTATION_EXPIRED422PERMANENTLa cotización expiró antes de que se procesara la operación.No — pide una cotización nueva
B2B_QUOTATION_MISMATCH422PERMANENTEl monto, la moneda, el corredor o el método de pago de la operación no coinciden con la cotización que referencia — p. ej. bank_account sobre una cotización P2P_PHONE_TRANSFER. Compara payment_instructions con el destination.payout_method de la cotización antes de enviar.No — corrige las instrucciones, o pide una cotización nueva con los valores correctos
B2B_QUOTATION_ALREADY_USED409PERMANENTLa cotización ya respalda otra operación. Una cotización es de uso único, para siempre.No — lee la nota de abajo antes de reintentar nada
B2B_INSUFFICIENT_BALANCE422PERMANENTEl balance disponible de la wallet es menor al que requiere la operación.No — carga saldo primero
B2B_BENEFICIARY_INVALID422PERMANENTLos datos del beneficiario son inválidos o incompletos para el payout method elegido.No — corrige las payment instructions
B2B_RATE_NOT_FOUND422PERMANENTNo hay tarifa activa para el corredor pedido (moneda origen/destino, país, payout method).No — revisa GET /me/routes
B2B_ORDER_NOT_FOUND404PERMANENTLa orden no existe, o no te pertenece.No
B2B_IDEMPOTENCY_CONFLICT409PERMANENTEl mismo X-Idempotency-Key ya se usó con un body distinto.No — usa una clave nueva por cada orden distinta
B2B_WALLET_NOT_CONFIGURED409PERMANENTTu compañía todavía no tiene wallet aprovisionada.No — contacta a soporte
B2B_WALLET_NOT_FOUND404PERMANENTLa wallet configurada no existe en el proveedor.No — contacta a soporte
B2B_INVALID_PAGINATION_CURSOR400PERMANENTEl cursor de paginación no se pudo decodificar o no fue emitido por este listado.No — usa el next_cursor de la página anterior, o descarta el cursor para volver a empezar
B2B_RATE_LIMITED429TRANSIENTSuperaste las requests permitidas en este intervalo.Sí — con backoff exponencial
B2B_PROVIDER_REJECTED422PERMANENTLa red de pagos rechazó la operación con un motivo que todavía no catalogamos. Trae details con el mensaje de la propia red.No — lee details y corrige el campo que nombra
B2B_PROVIDER_UNAVAILABLE503TRANSIENTLa red de pagos no está disponible en este momento.Sí — con backoff exponencial
B2B_UNKNOWN500UNKNOWNUna falla inesperada que no pudimos clasificar.Una vez, después escala con el correlationId
B2B_QUOTATION_ALREADY_USED es un 409, no un 422, y es a propósito

Todos los demás errores de cotización son 422. Este es 409 porque ya existe una operación del otro lado. Un cliente que trate "422 + error de cotización" como "re-cotizo y reenvío" emitiría el payout dos veces.

Reconcilia primero contra la operación existente — búscala por el X-Idempotency-Key que usaste — y solo después decide si corresponde una orden nueva. Ver idempotencia.

Lo que NO está en esta página: por qué falló un pago​

Todo lo de arriba es una llamada a la API que fue rechazada — vuelve como la respuesta HTTP de tu request. Un pago que se aceptó y después falló aguas abajo es otra cosa completamente distinta: la llamada salió bien, y la orden reporta más tarde su propio failure_code (la familia RET-*) más failure_reason.

Eso vive en detalle de falla. No busques códigos B2B_* ahí, ni códigos RET-* aquí.

Política de reintento por categoría​

category es la respuesta completa, y es el campo sobre el que tienes que construir tu lógica de reintentos — no el código, y nunca el mensaje.

CategoríaPolítica
PERMANENTNo reintentar. La request idéntica devuelve la respuesta idéntica; corrígela primero.
TRANSIENTReintentar con backoff exponencial. Hoy el conjunto transitorio es exactamente B2B_RATE_LIMITED y B2B_PROVIDER_UNAVAILABLE.
UNKNOWNReintentar como máximo una vez. Si persiste, contacta a soporte con el correlationId.

Un reintento de POST /orders solo es seguro con el mismo X-Idempotency-Key del intento original. Cualquier otra cosa arriesga un pago duplicado.

Cómo caen aquí las fallas de la red de pagos​

Las cotizaciones y las órdenes se ejecutan sobre una red de pagos que reporta sus propios códigos de error. Esos se traducen al catálogo de arriba:

  1. Un código conocido — o un reason secundario conocido cuando el código principal es genérico — mapea a su código B2B_* específico.
  2. Un código que todavía no catalogamos cae por HTTP status: 429 → B2B_RATE_LIMITED, cualquier otro 4xx → B2B_PROVIDER_REJECTED, cualquier 5xx → B2B_PROVIDER_UNAVAILABLE.
  3. Una falla sin ningún status usable → B2B_UNKNOWN.

La consecuencia práctica: una falla no catalogada igual llega con una category sobre la que puedes actuar. Por eso ramificar por category nunca te deja sin decisión, y por eso existe el paso 2.

Qué te dice details​

El paso 2 tiene un costo: un código genérico no puede decirte qué campo rechazó la red. Para eso existe details. Cuando el fallback cae en B2B_PROVIDER_REJECTED, la respuesta trae el mensaje de la propia red, campo por campo y textual:

{
"code": "B2B_PROVIDER_REJECTED",
"category": "PERMANENT",
"message": "El proveedor rechazó la operación con un error no catalogado. Verifique los datos enviados; la operación no se reintentará automáticamente.",
"details": ["members.1.receiver.beneficiary documentType must be one of V, E, J, G"]
}

Léelo como leerías un error de validación: nombra el campo y la regla. Está escrito en inglés, por la red, y su redacción no es parte de nuestro contrato — muéstralo en tus logs y a tus operadores, no lo parsees. details está ausente en todos los demás códigos, y nunca aparece en un 5xx: una caída de la red no trae nada que puedas corregir.

El ejemplo de arriba es el que más vemos. El document.type de un beneficiario venezolano tiene que ser V, E, J o G — las categorías de la cédula — no CI, DNI ni PASSPORT. El corredor no acepta otra cosa.

El segundo más común es la cuenta bancaria de un payout BANK_TRANSFER:

"details": ["members.1.receiver.paymentInstructions.bankAccountNumber must be 20 digits"]
"details": ["members.1.receiver.paymentInstructions.bankAccountNumber must start with 0134 for BANCO_BANESCO_VE"]

Un número de cuenta venezolano tiene exactamente 20 dígitos, y los primeros cuatro son el código del banco, así que la red verifica que el prefijo coincida con el bank_name que enviaste. La regla del prefijo aplica a los bancos principales (BANCO_BANESCO_VE → 0134, BANCO_VENEZUELA_VE → 0102, BANCO_BICENTENARIO_VE, BANCAMIGA_VE, 100_BANCO_VE y otros); el resto solo recibe la regla de 20 dígitos por ahora. Antes del 2026-09-10 ambas cosas se aceptaban en silencio — una cuenta mal escrita fallaba después, como falla de pago, en lugar de en la llamada a la API.

Algunas requests nunca llegan a la red. Un POST /orders con payment_instructions vacío, o con bank_account y bank_phone_account a la vez, se rechaza localmente como 422 B2B_BENEFICIARY_INVALID. Un body al que le falta un objeto obligatorio (sender, destination, source, quote…), o una cotización con quote.amount en cero, se rechaza aún antes como 400 de validación — nunca llega a tener un code.

Códigos numéricos heredados​

Si tu integración todavía lee los códigos numéricos de nuestra interfaz B2B anterior, estas son las únicas cinco equivalencias que respalda la plataforma actual. No existe un mapeo 1 a 1 completo de la tabla vieja, y los códigos de abajo ya no se emiten — están aquí para migrar, no para construir sobre ellos.

Código heredadoCódigo actual
3000B2B_UNAUTHORIZED
3003B2B_QUOTATION_NOT_FOUND
3004B2B_QUOTATION_EXPIRED
3007B2B_INSUFFICIENT_BALANCE
3020B2B_BENEFICIARY_INVALID
nota

Este catálogo crece. Ramifica sobre code para los casos que manejas puntualmente, usa category como respaldo para el resto, y nunca asumas que la tabla de arriba es definitiva.