Toda respuesta de error tiene la misma forma:
" type " : " invalid_request_error " , " code " : " limit_exceeded " ,
" message " : " Supera el límite por operación de pago móvil " ,
" request_id " : " req_8a0312ba896772bc441134cd " ,
" meta " : { " limit " : " per_tx_max " , " max " : " 10000000 " , " scope " : " platform " } } }
Campo
Qué es
code
Código estable. Programa contra esto
type
Familia del error: te dice si tiene sentido reintentar
message
Texto legible. Puede cambiar o traducirse: no lo parsees
request_id
También viaja en la cabecera x-request-id. Inclúyelo al abrir un ticket
meta
Contexto estructurado cuando lo hay: qué límite se superó, qué campo es inválido, cuánto saldo había. Ausente en errores internos
Tu switch sobre error.code necesita un default para códigos desconocidos.
type
HTTP
Significa
¿Reintentar?
invalid_request_error
400 · 404 · 409 · 422
Algo de la petición está mal
No sin corregir
authentication_error
401 · 403
Credenciales o permisos
No
rate_limit_error
429
Vas demasiado rápido
Sí, más despacio
provider_error
502 · 503
Fallo de un riel
Sí, con la misma Idempotency-Key
api_error
≥ 500
Fallo nuestro
Sí
Código
HTTP
Qué hacer
api_key_missing
401
Falta el header x-api-key
api_key_invalid
401
Revisar credenciales
api_key_revoked
401
Esa clave se revocó
api_key_expired
401
Pedir una nueva
tenant_suspended
403
Contactar a soporte
insufficient_scope
403
Usar una clave con el scope de meta.required
Código
HTTP
Qué hacer
validation_failed
400
Corregir el cuerpo o la query. El message dice qué campo; a veces también meta.field
invalid_amount
400
Monto ≤ 0, fuera de rango, o tan pequeño que la comisión se lo comería
unsupported_asset
400
Activo o par no soportado
Los errores de validación vienen en un solo `message`
No hay array de errores por campo: los mensajes de todas las reglas que
fallaron se concatenan con ; en error.message. No lo parsees.
Código
HTTP
Qué hacer
idempotency_key_reused
409
Clave nueva: el cuerpo cambió
idempotency_request_in_flight
409
La original sigue en curso; reintentar en segundos
Código
HTTP
Qué hacer
quote_not_found
404
No existe, o es de otro programa
quote_expired
422
Pedir una cotización nueva
quote_already_consumed
409
Esa cotización ya la usó otra dispersión
Código
HTTP
Qué hacer
beneficiary_not_found
404
El beneficiaryId no es tuyo o no existe
beneficiary_blocked
422
Está bloqueado: ni se lee ni se le dispersa
beneficiary_instrument_missing
422
Sin teléfono para pago móvil, o sin cuenta para transferencia. meta trae beneficiaryId e instrument
Código
HTTP
Qué hacer
insufficient_tenant_funds
422
Tu saldo no alcanza. Sólo si operas prefondeado
credit_limit_exceeded
422
Agotaste la línea del cierre diario
limit_exceeded
422
meta dice qué límite (per_tx_max, daily_max, monthly_max, daily_count_max), el tope y el consumo
invalid_state_transition
409
La operación no aplica al estado actual del pago
payment_not_found, quote_not_found, beneficiary_not_found y
event_not_found → 404 , igual que un recurso de otro programa.
Código
HTTP
Qué hacer
no_provider_available
503
No hay riel para ese banco/instrumento ahora mismo. Reintentar más tarde
provider_error
502
Fallo del proveedor. Reintentar con la misma Idempotency-Key
rate_limited
429
Bajar el ritmo. Respetar Retry-After
internal_error
500
Fallo nuestro. Reintentable; manda el request_id si persiste
Un error que no encaje en los códigos anteriores llega con un código genérico
por familia: not_found (404), conflict (409), unprocessable (422) o
invalid_request (400). Trátalos como el resto de su familia.
Dos taxonomías distintas, y no se mezclan
Cuando una dispersión se rechaza en el riel, la API responde 201 Created
con status: "failed" y el motivo en el campo reason . No es un error
HTTP: la operación se procesó, se registró y se compensó.
beneficiary_missing_phone o amount_below_rail_minimum nunca aparecen en
error.code.
{ " id " : " 89920401-26da-4f69-b57d-bc20e0366ce2 " , " status " : " failed " ,
" reason " : " beneficiary_missing_phone " ,
" asset " : " BS " , " amount " : " 5000000 " , " feeAmount " : " 0 " }
reason
Qué pasó
beneficiary_missing_phone
Falta el móvil del beneficiario. Ocurre también en transferencia
beneficiary_missing_account
Falta el número de cuenta para transferencia
beneficiary_mismatch
Nombre o cédula no coinciden con el titular de esa cuenta o teléfono
invalid_destination_account
La cuenta destino no existe o está mal formada
sender_required
No había remitente por ninguno de los tres caminos
amount_below_rail_minimum
Por debajo del piso del riel
amount_above_rail_limit
Por encima del techo del riel
amount_not_positive
Importe ≤ 0
amount_precision_loss
El importe no se puede representar sin perder céntimos
bank_unreachable
Ese riel no cubre el banco destino
instrument_unsupported
Ese riel no ofrece ese instrumento
rail_insufficient_balance
El riel no tiene liquidez de dispersión ahora mismo
rail_rejected
Rechazo genérico del riel
provider_timeout
No sabemos si pagó → el pago queda en unknown, no en failed
no_route
Ningún riel candidato para esa combinación
El mismo valor queda en status_reason del pago y en el reason de la
transición dentro de events[]. Qué hacer con cada uno: cuando algo
falla .
Un pago con status: "unknown" responde 200/201 , no un error: el riel no
confirmó, y el pago está en duda. Ver estados de un
pago .