En esta página
Códigos de error
Gestiona los fallos de la Merchant API con códigos estables legibles por máquina, detalle de validación por campo y vías de recuperación documentadas.
Catálogo de códigos
Identificadores estables y legibles por máquina que se devuelven en code (y por campo en errors[].code). Esta es la lista real: cada código lo emite al menos un handler, un validador o un middleware de la API en funcionamiento, no es un superconjunto teórico. Los códigos existentes nunca cambian de significado y se añaden códigos nuevos cuando aparecen escenarios nuevos. Un código se renombra solo en casos raros, y cada cambio de nombre se anuncia en el changelog.
Usa code para la lógica programática. detail llega únicamente en inglés y está pensado para los registros o para una interfaz de reserva; localiza en el cliente a partir de code.
Códigos por campo
Los emite la validación de la petición. Cada código de abajo pone en field el nombre del campo problemático en snake_case. Cuando fallan varios campos a la vez, el code de nivel superior es validation_failed y cada fallo por campo aparece en errors[].
| Code | Cuándo | Qué hacer |
|---|---|---|
validation_failed |
El code de nivel superior cuando fallan varios campos a la vez. Cada fallo por campo lleva su propio code y field dentro de errors[]. |
Revisa errors[] y corrige cada field de la lista. |
field_required |
Un campo obligatorio está vacío, es null o solo contiene espacios. | Envía un valor para ese field. |
field_too_long |
El campo supera la longitud máxima permitida. | Recórtalo al límite documentado para ese endpoint. |
field_out_of_range |
Valor numérico fuera del rango permitido. | Ajusta el valor al rango documentado. |
field_invalid_enum |
El valor no es uno de los admitidos por la enumeración (por ejemplo, currency o network desconocidos, o un token que el proyecto no tiene activado). |
Consulta la referencia de valores admitidos; con los tokens, comprueba que el proyecto tenga activada la pareja token + red. |
field_invalid_format |
El valor no tiene la forma que espera el campo: un ID que no se puede interpretar (por ejemplo, invoice_id sin el prefijo inv_…) o un amount que no es una cadena decimal simple como "10.00". |
Envía el campo en el formato documentado y usa tal cual los IDs que devuelve la API. |
entity_id_empty |
Un ID enviado es un GUID vacío o todo a ceros (00000000-0000-…). field indica cuál es — por ejemplo, invoice_id o withdrawal_id. |
Envía tal cual el ID que devuelve la API; nunca un ID vacío o a ceros. |
field_must_be_positive |
El decimal o entero debe ser mayor que 0. | Envía un valor positivo. |
field_percentage_out_of_range |
El porcentaje debe estar entre 0 y 100, ambos incluidos. | Ajusta el valor a [0, 100]. |
query_parameter_unknown |
Una petición de listado incluye un parámetro de consulta que el endpoint no admite. | Quita el parámetro o usa su nombre documentado en snake_case. |
pagination_cursor_invalid |
El cursor está mal formado, ha vencido, ha sido manipulado, pertenece a otro recurso o se combina con filtros distintos. | Reinicia la paginación sin cursor y luego mantén los mismos filtros mientras sigues next_cursor. |
amount_too_many_decimals |
En facturas con flujo fiat, amount tiene más decimales que la unidad mínima de la moneda (por ejemplo, 23.345 en USD o 23.01 en JPY). |
Redondea a la unidad mínima de la moneda. |
amount_too_large |
El amount al crear una factura o un retiro queda fuera del rango admitido: por encima del tope de 20 dígitos enteros que guarda la API. |
Envía un importe dentro del rango admitido. |
Alternativas genéricas por estado HTTP
Se devuelven cuando el fallo no lleva asociado un código de negocio concreto. Cada uno es la alternativa de un estado HTTP: la petición falló, pero ningún código más específico describía la causa.
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
forbidden |
403 | La petición está autenticada, pero esta credencial no puede realizar la operación: su alcance (capacidad) o su entorno no lo permiten; por ejemplo, una clave de Sandbox llamando a un endpoint que solo existe en producción. | Llama con una credencial cuya capacidad y entorno encajen con la operación. La pertenencia nunca da un 403: un recurso de otro comercio devuelve not_found (404), no forbidden. |
payment_key_required |
403 | El endpoint necesita una clave Payment (pk_), pero la petición usó una Payout (rk_) — por ejemplo, al listar facturas. |
Llámalo con una clave Payment. |
payout_key_required |
403 | El endpoint necesita una clave Payout (rk_), pero la petición usó una Payment (pk_) — por ejemplo, al leer saldos. |
Llámalo con una clave Payout. Ten en cuenta que la clave Payout además necesita una lista blanca de IP para funcionar. |
internal_error |
500 | Un error inesperado o un fallo de nuestro lado. | Reinténtalo una vez. Si sigue fallando, escribe al soporte e indica la hora de la respuesta. |
validation_failed |
400 | La petición no pasó la validación, pero no aplicaba ningún código a nivel de campo. | Lee el campo detail: dice qué se rechazó. |
Autenticación
Se devuelven solo en respuestas 401 Unauthorized del handler de autenticación HMAC. Cada código identifica un punto de fallo concreto para que el cliente muestre un mensaje accionable en lugar de un genérico «auth failed».
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
unauthorized |
401 | Código de reserva cuando no se aplicó ninguno de los códigos siguientes: normalmente, una petición a un endpoint con autenticación obligatoria sin cabecera Authorization (o con un esquema de autenticación desconocido). |
Envía una cabecera Authorization HMAC válida y revisa todo el flujo de firma de principio a fin. |
authorization_missing |
401 | El valor de la cabecera Authorization está vacío (se envía, pero en blanco). |
Envía la cabecera completa Authorization: HMAC-SHA256 {apiKeyId}:{base64signature}. |
authorization_malformed |
401 | La cabecera está presente pero mal formada: el esquema se interpreta bien, pero a la parte de credenciales le faltan los dos puntos, el ID de la clave de API no se puede interpretar o la firma está vacía. | Vuelve a construir la cabecera según Autenticación; la causa más habitual es una errata en el ID de la clave de API. |
timestamp_missing |
401 | Falta la cabecera X-Request-Timestamp o no se interpreta como un entero positivo. |
Ponla con la marca de tiempo Unix actual en segundos. |
timestamp_expired |
401 | La marca de tiempo queda fuera de la ventana permitida de desfase de reloj (5 minutos por defecto). | Sincroniza tu reloj por NTP y vuelve a firmar con una marca nueva. |
invalid_credentials |
401 | La credencial no se puede usar: ID de clave desconocido, clave revocada, un prefijo de entorno o de tipo que no coincide con la clave guardada, o una firma que no verifica. Es un solo código para los cuatro casos a propósito: una respuesta distinguible confirmaría qué IDs de clave existen a quien no tiene el secreto. | Comprueba que el ID de la clave de API es correcto y está activo, y que la firma se calcula con el secreto que le corresponde. La causa más habitual está en la firma: revisa cómo montas el string-to-sign ({ts}\n{METHOD}\n{path}\n{query}\n{bodyHash}) y que bodyHash esté vacío cuando no hay cuerpo (no calcules el hash de una cadena vacía). |
ip_not_allowed |
401 | La clave Payout tiene configurada una lista blanca de IP y la IP que llama no está en ella. Solo las claves Payout llevan comprobación de IP; las claves Payment se pueden llamar desde cualquier IP. Se verifica después de validar la firma, así que una firma correcta desde la red equivocada también falla. | Añade la IP que llama (o su bloque CIDR) a la lista blanca de la clave Payout en el panel. |
payout_whitelist_required |
401 | Una clave Payout recién generada aún no tiene lista blanca de IP. Las claves Payout siguen inactivas hasta que el comercio añade al menos una IP autorizada; es un código distinto de ip_not_allowed para que el cliente pueda separar «falta configurarlo en el panel» de «la IP de origen no es la correcta». |
Abre el panel, ve a la página de claves de API y configura al menos una IP o un CIDR en la lista blanca de la clave Payout. |
Límite de peticiones
Se devuelven en 429 Too Many Requests cuando una petición supera el límite por comercio. El recuento va por ventana de un segundo y suma todas tus claves de API: ninguna tiene cupo propio. Delante de la API actúa otro límite, por dirección IP; el que se describe aquí es el del comercio.
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
rate_limited |
429 | Se superó el límite por comercio. Se aplican dos: un tope global en todos los endpoints (30 peticiones/segundo por defecto) y otro más estricto en la creación de facturas, POST /v1/invoices (5 peticiones/segundo por defecto). La respuesta indica cuál saltó y con qué límite. |
Lee la cabecera Retry-After (la espera en segundos) y reinténtalo cuando pase; la mayoría de clientes HTTP con middleware de reintentos la respetan solos. |
Transporte y framework
Los devuelve el gestor de errores del framework cuando la petición nunca llegó a un handler normal.
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
malformed_request |
400 | El cuerpo de la petición no se pudo interpretar: JSON mal formado. | Comprueba que el cuerpo sea JSON válido. |
payload_too_large |
413 | El cuerpo de la petición supera el límite de 1 MiB. | Envía un cuerpo más pequeño; reparte las cargas grandes en varias peticiones. |
unsupported_media_type |
415 | El Content-Type no es application/json. |
Pon Content-Type: application/json. |
method_not_allowed |
405 | La ruta existe, pero no para este método HTTP. | Usa el método documentado para ese endpoint (por ejemplo, POST para crear). |
route_not_found |
404 | Ningún endpoint coincide con la ruta de la petición. | Revisa la URL contra la referencia de la API. |
Facturas
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
invoice_not_found |
404 | El ID de factura no resuelve a nada, o apunta a una factura de otro comercio. | Usa tal cual el ID que devuelve POST /v1/invoices. |
project_not_found |
404 | El project_id de una petición de creación de factura no resuelve a nada visible para quien llama. |
Usa un ID de proyecto del panel (debe estar activo y pertenecer al mismo comercio que la clave de API). |
invoice_terminal |
410 | Se llamó a confirm-payment sobre una factura expired o cancelled. (Una factura paid devuelve invoice_not_awaiting_client, 409, no este código.) |
Actualiza el estado de la factura; no hay nada más que hacer. |
invoice_deadline_passed |
410 | Se llamó a confirm-payment después del plazo límite de la factura. | Crea una factura nueva. |
requested_amount_invalid |
400 | El amount de la factura falta, está mal formado, queda fuera del rango decimal admitido o no es positivo. |
Envía amount como cadena decimal positiva, junto con la currency elegida y la network opcional. |
invoice_amount_below_minimum |
400 | El valor en USD calculado de la factura está por debajo del mínimo por token o por red del catálogo. | Sube el importe por encima del mínimo que se indica para el token elegido. |
deposit_amount_exceeds_limit |
400 | El valor en USD calculado del pago esperado supera el tope MaxDepositAmount por depósito de la política del comercio. Limita el importe cotizado en la confirmación, no lo que se recibe realmente on-chain. |
Baja el importe de la factura o escribe al soporte para subir el límite. |
currency_not_enabled_for_project |
400 | La criptomoneda solicitada no está en la lista de tokens activados del proyecto (en ninguna red). | Activa la moneda en el proyecto o elige una de las enabled_tokens del proyecto. |
tokens_required |
409 | Creación de factura o confirmación de pago en un proyecto que no tiene ningún token activado. | Activa al menos un token en el proyecto desde el panel. |
acceptance_disabled |
503 | El token solicitado no se está aceptando ahora mismo. | Usa otro token o vuelve a intentarlo más tarde. |
exchange_rate_unavailable |
503 | El proveedor de tipos de cambio no tiene una cotización fresca para la pareja token / fiat. | Reinténtalo; los tipos se refrescan en intervalos cortos. |
network_unavailable |
503 | La confirmación automática no pudo usar la red elegida. | Quita la confirmación automática y deja que el cliente elija el token en la página de pago. |
payment_method_unavailable |
503 | El token o la red elegidos no pueden aceptar un pago en este momento. Sustituye a no_available_address, address_lease_failed y bridge_unavailable desde el 23-08-2026. |
Reinténtalo, o deja que el cliente elija otro token u otra red. |
client_confirmation_failed |
409 | Se rechazó la confirmación del lado del cliente (elección de token, confirmación automática). El campo detail trae el motivo concreto. |
Mira detail; los casos habituales son que la factura ya pasó de awaiting_client o que el token no está permitido. |
invoice_not_awaiting_client |
409 | Se llamó a confirm-payment sobre una factura que ya no está en awaiting_client. |
Actualiza el estado de la factura; el cliente ya pasó de la selección. |
invoice_cannot_be_cancelled |
409 | La factura ya no está en awaiting_client: el cliente ya eligió token, o la factura está pagada o vencida. Cancelar de nuevo una factura ya cancelada devuelve 200, no este error. |
Mira el estado actual; la cancelación solo funciona en awaiting_client. |
simulate_payment_failed |
409 | Se rechazó simulate_payment, disponible solo en sandbox. |
Mira detail; suele ser un estado incorrecto o un importe que no cuadra. |
not_sandbox |
403 | Se llamó a simulate-payment (el simulador de sandbox) sobre una factura de producción. |
Solo se pueden simular facturas de sandbox: usa una factura de sandbox o mueve una factura real con un pago on-chain de verdad. |
Facturas del widget
Los devuelve POST /public/v1/sdk (creación de facturas con el Low-Code SDK).
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
widget_key_missing |
401 | La cabecera X-Sdk-Key falta o está vacía en un endpoint que exige autenticación de widget. |
Envía la clave pública del SDK en X-Sdk-Key. |
widget_key_invalid |
401 | X-Sdk-Key está presente, pero no se interpreta como un ID de clave de API de Paymos. |
Copia la clave desde el panel; revisa espacios sobrantes, un prefijo equivocado o una codificación de URL accidental. |
widget_key_not_found |
401 | La clave se interpreta, pero no corresponde a ninguna credencial activa: revocada, eliminada o de un tipo distinto de Payment (las claves Payout no pueden mover el widget). | Usa una clave Payment en estado Active desde el panel. |
widget_inactive |
403 | El widget del proyecto de destino está apagado, o nunca se inicializó. | Activa el widget en los ajustes del proyecto. |
terminal_not_enabled |
403 | La solicitud llegó con source=terminal, pero el método de integración del proyecto no es Terminal. |
Cree un proyecto de tipo Terminal o envíe source=embed desde un proyecto Low-Code. |
embed_not_enabled |
403 | La solicitud llegó con source=embed, pero el método de integración del proyecto no es Low-Code. |
Use el método de integración del propio proyecto o cree un proyecto Low-Code. |
origin_not_allowed |
401 | El Origin del navegador no coincide con ninguna política de orígenes permitidos. La comprobación ocurre dos veces —la capa de autenticación contrasta el origen con la unión de todos los proyectos de la clave que tienen widget activo, y después el handler lo contrasta con el proyecto de destino exacto—, y las dos responden el mismo 401, el mismo código y el mismo detalle. Es deliberado: un estado distinto en la segunda comprobación le diría a quien tiene la clave pk_ (pública y raspable) que el origen está registrado en otro proyecto del mismo comercio, y así se podrían enumerar hosts de staging y marcas sin lanzar, sonda a sonda. |
Añade el dominio a los orígenes permitidos del widget. Las peticiones del mismo origen —por ejemplo, un terminal POS servido desde el mismo host— se saltan la comprobación. |
Canales de pago
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
payment_channels_disabled |
503 | Los canales de pago no están activados para tu cuenta en este entorno. Responden así todos los endpoints de canales y de depósitos, incluido el simulador de Sandbox. | Escribe al soporte para que te lo activen. Reintentar no cambia la respuesta. |
payment_channel_not_found |
404 | El id pc_ no resuelve a nada que esta credencial pueda ver: no existe, es de otro comercio, vive en el otro entorno o está en un proyecto fuera del alcance de la clave. Los cuatro casos son indistinguibles a propósito. |
Usa tal cual el id que devuelve POST /v1/payment-channels, firmando con una clave del mismo entorno y del mismo proyecto. |
payment_channel_deposit_not_found |
404 | El id pcd_ no resuelve a nada que esta credencial pueda ver. Las mismas cuatro causas de arriba. |
Usa tal cual el id del contenido del webhook o del flujo de sondeo. |
payment_channel_external_id_invalid |
400 | external_id está vacío, en blanco o supera los 128 caracteres, ya sea al crear o como filtro de la lista. |
Envía un identificador no vacío de 128 caracteres como mucho. |
payment_channel_project_has_no_supported_tokens |
409 | El proyecto no activa ningún token que un canal de pago pueda cobrar, así que el canal se quedaría sin ninguna vía. | Activa al menos un token admitido en el proyecto y crea el canal después. |
payment_channel_simulation_sandbox_only |
403 | Se llamó a simulate-deposit sobre un canal de producción. |
La simulación existe solo para canales de Sandbox. Mueve un canal de producción con una transferencia de verdad. |
payment_key_required |
403 | La petición se firmó con una clave Payout (rk_). El acceso a los canales va con la clave Payment, igual que los retiros van con la clave Payout. |
Firma con una clave pk_ del mismo entorno. |
pagination_cursor_invalid |
400 | El cursor de una lista o de un flujo está mal formado, tiene más de 24 horas o está ligado a otros filtros; en el flujo, también a otro comercio, otro entorno u otro alcance de proyectos. | Vuelve a empezar por la primera página. Descartar duplicados por pcd_ deja una resincronización completa en algo inofensivo. |
currency_not_enabled_for_project |
400 | El token que se pasó a simulate-deposit no está en la lista de tokens activados del proyecto. |
Actívalo en el proyecto, o elige uno de los que el canal ya devuelve en sus networks[].tokens. |
acceptance_disabled |
503 | El cobro del token solicitado está desactivado ahora mismo en toda la plataforma. | Usa otro token o espera a que se vuelva a activar la aceptación. |
amount_too_many_decimals |
400 | El importe simulado tiene más decimales de los que admite el token. El dinero de un comercio nunca se redondea en silencio hasta otro número. | Redondea el importe a la precisión del token antes de enviarlo. |
Retiros
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
withdrawal_not_found |
404 | El ID de retiro no resuelve a nada, o apunta a un retiro de otro comercio. | Usa tal cual el ID que devuelve POST /v1/withdrawals. |
insufficient_balance |
409 | El saldo disponible del comercio está por debajo de amount + fee. |
Ingresa más fondos o reduce el importe del retiro. |
whitelist_required |
403 | La dirección de destino no está en la lista blanca de la red elegida. (La red admite listas blancas; esta dirección concreta aún no se ha añadido.) | Añade la dirección a tu lista blanca y vuelve a intentarlo. |
destination_address_invalid |
400 | La dirección no pasa la validación de formato o de suma de control de la red. | Vuelve a comprobar la dirección contra la especificación de la red. |
withdrawal_amount_below_minimum |
400 | El importe está por debajo del mínimo de la política para el token elegido. | Sube el importe por encima del mínimo (viene en detail). |
withdrawal_quota_exceeded |
409 | El número de retiros activos alcanzó el límite de la política del comercio. | Espera a que se liquiden los retiros en curso o escribe al soporte para subir el límite. |
withdrawal_amount_exceeds_limit |
400 | El equivalente en USD del principal del retiro supera el tope MaxWithdrawalAmount por transacción de la política del comercio. |
Reduce el importe o escribe al soporte para subir el límite. |
exchange_rate_unavailable |
503 | El comercio tiene un tope MaxWithdrawalAmount configurado, pero no había una cotización token/USD fresca para contrastar el principal: el límite no se puede verificar, así que la petición se rechaza por seguridad. |
Reinténtalo; los tipos se refrescan en intervalos cortos. |
withdrawal_not_enabled |
400 | Paymos no paga la pareja token/red que has pedido. detail nombra la pareja — por ejemplo, Withdrawals are not available for USDT on TRC20. Qué parejas se pueden pagar depende de nuestra configuración, no de la tuya. |
Retira el token en una red por la que Paymos sí paga, o pregunta al soporte por la pareja que necesitas. |
withdrawal_cannot_be_cancelled |
409 | El retiro ya pasó del estado en el que se puede cancelar. | Mira el estado actual. La ventana se cierra cuando arranca la ejecución, todavía dentro de created y antes de firmar nada. |
withdrawal_simulation_failed |
409 | Se rechazó simulate_completion, disponible solo en sandbox. |
Mira detail. |
merchant_suspended |
403 | La cuenta del comercio está suspendida para operaciones salientes, así que no se puede crear ningún retiro. | Escribe al soporte para levantar la suspensión. |
outbound_frozen |
503 | Las transferencias salientes están congeladas, ya sea en toda la plataforma o para la red y el token con los que retiras. | Espera a que se levante la congelación, prueba con otra red o token, o escribe al soporte. |
withdrawal_network_unavailable |
503 | Los retiros de este token en esta red no se pueden liquidar ahora mismo. | Prueba con otra red de destino o vuelve a intentarlo más tarde. |
Estado del proyecto
Se devuelven al crear una factura o confirmar un pago cuando el estado actual del proyecto no permite emitir facturas.
| Code | HTTP | Cuándo | Qué hacer |
|---|---|---|---|
project_state_invalid |
409 | El proyecto no está Active: está Suspended o Archived. La respuesta no dice cuál de los dos. |
Mira el estado del proyecto en el panel: si está archivado, restáuralo; si está suspendido, actívalo. O envía la petición a un proyecto que ya esté activo. |