Errores
Cada código, su causa, su solución y si se reintenta.
Los errores de la API llegan con una sola forma, salvo las dos excepciones de abajo. Lee code para decidir, muestra message y guarda request_id.
Forma del error
{
"error": {
"code": "invalid_request",
"message": "Petición inválida",
"request_id": "0123456789abcdef0123456789abcdef",
"details": { "fields": { "amount": "Monto decimal inválido" } },
"retryable": false,
"docs_url": "https://merchants.fital.xyz/docs/errores/#invalid_request"
}
}details.fields trae los errores por campo. retryable dice si repetir la misma petición más tarde puede servir, y es el dato de cada respuesta el que manda. Las tablas de abajo dan el valor habitual de cada código: un rechazo ya registrado siempre llega con false, se repite tal cual con esa clave y necesita una nueva. Ver Qué hacer con la clave tras un rechazo. Tu código debe tolerar códigos nuevos.
Excepciones
| Respuesta | Forma | Qué hacer |
|---|---|---|
503 de GET /v1/health | {"status": "down", "api_version": "v1"}, sin error | Decide por status. Es el único error de la API sin esta forma |
404 del simulador público, cuando un escenario no aplica a la operación | application/problem+json | Sólo ocurre ahí. Ver Ambientes |
Un error fuera de la lista de arriba también puede ser de tu proxy o de tu red, no de FITAL: si no trae error.code, trátalo como un timeout.
Códigos
idempotency_key_invalid
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 400 | false | No |
Causa. La clave no mide entre 8 y 200 caracteres, o viene duplicada.
Solución. Envía una sola cabecera con una clave de largo válido.
idempotency_key_required
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 400 | false | No |
Causa. Falta Idempotency-Key en una operación que la exige.
Solución. Envía una clave derivada de tu identificador interno.
invalid_request
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 400 | false | No |
Causa. Algún campo no cumple el esquema, el cuerpo no es JSON válido o supera el tamaño máximo. El detalle por campo llega en details.fields.
Solución. Corrige los campos indicados antes de repetir. Un cuerpo demasiado grande llega con HTTP 413 y este mismo código: ver Límites.
invalid_api_key
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 401 | false | No |
Causa. Llave mal formada, vencida o revocada, o empresa suspendida.
Solución. Revisa la llave en tu gestor de secretos o crea otra en el panel.
invalid_signature
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 401 | false | No, hasta corregir la firma |
Causa. Falta la firma de la petición, es inválida o tiene más de 5 minutos.
Solución. Revisa la cadena firmada en Autenticación y el reloj de tu servidor.
wrong_environment
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 401 | false | No |
Causa. Llave de otro ambiente: sk_test_ en producción, o sk_live_ en un simulador.
Solución. Usa la base y la llave del mismo ambiente. Ver Ambientes.
account_not_active
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. La cuenta no está activa. No dice si un pago previo ocurrió.
Solución. Consulta el pay_ o escribe a soporte.
account_restricted
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. Tu cuenta tiene una restricción.
Solución. Contacta a tu ejecutivo FITAL. No reintentes en bucle.
forbidden_scope
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. La llave no tiene el scope de esta operación.
Solución. Crea en el panel una llave con el scope necesario.
ip_not_allowed
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No, hasta registrar la IP |
Causa. La IP de origen no está en la lista de esa llave.
Solución. Regístrala en el panel. Ver IP permitidas.
kyb_required
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. La empresa no tiene KYB aprobado o aún no está inscrita.
Solución. Completa el KYB en empresa.fital.xyz. Si ya está aprobado, pide la inscripción a FITAL.
live_not_enabled
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No, hasta la inscripción |
Causa. Tu empresa aún no está habilitada para producción: tiene KYB aprobado pero falta la inscripción de FITAL. Lo responde el panel al crear una llave sk_live_fital_…; la cuenta de prueba sigue disponible.
Solución. Completa la inscripción con FITAL. Ver Ambientes.
not_enabled
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. Función sin activar para tu empresa, como PIX sin activación vigente o un método de cobro.
Solución. Consulta con tu ejecutivo FITAL.
rail_not_enabled
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 403 | false | No |
Causa. El riel de pago no está habilitado para esta cuenta. En la cuenta de prueba, cualquier riel que no sea SPEI.
Solución. Pide a FITAL habilitarlo o usa otro riel. En la cuenta de prueba usa mxn_spei.
not_found
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 404 | false | No |
Causa. El recurso no existe o es de otra empresa. La respuesta es la misma en ambos casos.
Solución. Revisa el identificador y el ambiente.
beneficiary_ref_conflict
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | No |
Causa. El identificador del alta choca con un beneficiario que ya existe.
Solución. Consulta GET /v1/beneficiaries antes de repetir.
beneficiary_state_conflict
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | No |
Causa. El estado actual del beneficiario no permite esta operación.
Solución. Consulta su estado con GET /v1/beneficiaries/{id}.
collection_not_ready
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | No |
Causa. El cobro aún no está listo para esta operación.
Solución. Consulta el cobro con GET /v1/collections/{id}.
idempotency_in_progress
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | true | Sí, misma clave |
Causa. Una petición anterior con esa clave sigue en curso.
Solución. Repite con la misma clave tras Retry-After.
not_cancellable
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | No |
Causa. El pago ya no se puede cancelar. Es la respuesta normal cuando ya avanzó.
Solución. Sigue el pago con GET /v1/payments/{id}.
payment_in_flight
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | true | Sí, misma clave, tras resolverse |
Causa. Otra salida de dinero de tu empresa sigue en curso.
Solución. Repite con la misma clave cuando se resuelva.
quote_changed
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | Tras recotizar, con clave nueva |
Causa. El débito superaría max_source_amount o lo cotizado. No se creó ningún pago. También aplica en la cuenta de prueba.
Solución. Pide otra cotización y usa una clave nueva.
quote_expired
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | Tras recotizar, con clave nueva |
Causa. La cotización quote_id venció antes de crear el pago.
Solución. Pide otra cotización y usa una clave nueva.
receipt_not_available
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | Cuando el movimiento sea terminal |
Causa. El movimiento aún no llega a un estado terminal, o no tiene recibo.
Solución. Consulta el movimiento y pide el recibo cuando sea terminal.
receiving_account_in_progress
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | true | Sí, con espera |
Causa. Otra alta de esa moneda sigue en curso.
Solución. Espera unos segundos y reintenta con la misma clave.
sandbox_invalid_transition
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 409 | false | No |
Causa. Sólo cuenta de prueba: advance pidió un cambio que un pago real no puede hacer, como llevar a returned un pago que no está completed.
Solución. Consulta el estado del pago y pide una transición válida. Ver Avanzar un pago.
amount_below_minimum
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | Con otro monto, con clave nueva |
Causa. El monto está por debajo del mínimo aplicable.
Solución. Aumenta el monto y usa una clave nueva.
amount_out_of_range
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | Con otro monto |
Causa. El monto está fuera del rango del método.
Solución. Consulta min_amount y max_amount en GET /v1/collection-methods.
beneficiary_not_approved
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | true | Tras aprobar en el panel, misma clave |
Causa. Beneficiario propio sin aprobar. Uno ajeno o inexistente da not_found.
Solución. Apruébalo en el panel y repite con la misma clave.
collection_rejected
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. El cobro fue rechazado.
Solución. Revisa los datos y conserva el request_id.
currency_not_supported
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. La moneda no aplica a este beneficiario o riel.
Solución. Revisa la moneda de la operación.
deposit_address_rejected
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. La dirección de depósito fue rechazada.
Solución. Revisa chain y currency.
idempotency_key_reused
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. La misma clave se usó con otro cuerpo, también si pasaron más de 7 días. Es un error de programación.
Solución. Corrige tu integración: una clave identifica una sola operación.
in_review
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | true | Según retryable: misma clave con true, clave nueva con false |
Causa. Operación frenada por revisión. No confundir con el estado in_review de un pago que ya existe. Con retryable: true se frenó antes de ejecutar: no se creó nada y no hay pay_. Con retryable: false quedó registrada al ejecutar: el pago queda failed, con failure_code: in_review.
Solución. Espera la revisión. Con retryable: true, repite con la misma clave. Con retryable: false, esa clave repite el rechazo: usa una nueva.
insufficient_funds
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | Tras fondear, con clave nueva |
Causa. Saldo insuficiente.
Solución. Fondea la cuenta y repite con una clave nueva: la misma clave repite este rechazo.
invalid_beneficiary
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. El destino es inválido. En un alta latam, los datos no cumplen lo que pide el país.
Solución. Revisa los datos de la cuenta destino. En latam, compáralos con GET /v1/latam/countries. Usa una clave nueva: la misma repite el rechazo.
limit_exceeded
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | Con otro monto o más tarde, con clave nueva |
Causa. Se rebasó el tope acumulado de la empresa o un límite del riel: ver Límites. En la cuenta de prueba, un tope del ambiente: ver Cuenta de prueba.
Solución. Ajusta el monto o el momento. Usa una clave nueva: la misma repite este rechazo.
method_unavailable
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. El método de cobro no está disponible.
Solución. Consulta GET /v1/collection-methods.
pair_not_supported
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. El par de monedas no está disponible.
Solución. Elige otro par de monedas.
payment_rejected
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No con la misma clave |
Causa. El pago fue rechazado sin un motivo más específico.
Solución. Conserva el request_id y escribe a soporte si persiste. La misma clave repite este rechazo.
rail_unavailable
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | true | Sí, misma clave, más tarde |
Causa. El riel no está disponible por ahora.
Solución. Repite más tarde con la misma clave.
receiving_account_rejected
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | No |
Causa. La cuenta para recibir no se pudo abrir.
Solución. Contacta a tu ejecutivo FITAL y conserva el request_id.
sandbox_real_account_rejected
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 422 | false | Con datos ficticios |
Causa. Sólo cuenta de prueba: la CLABE no empieza con 999 o el titular no incluye la palabra FICTICIO.
Solución. Usa una CLABE 999 y un titular con FICTICIO. Ningún dato real entra a este ambiente.
rate_limited
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 429 | true | Sí, tras Retry-After |
Causa. Superaste un límite de peticiones.
Solución. Espera lo que indique Retry-After.
sandbox_limit
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 429 | false | Al día siguiente |
Causa. Sólo cuenta de prueba: alcanzaste el tope diario de pagos y cobros, o de reinicios de datos.
Solución. Repite al día siguiente. El tope de pagos y cobros se puede liberar reiniciando los datos desde el panel.
internal_error
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 500 | true | Sí, misma clave |
Causa. Fallo nuestro.
Solución. Repite con la misma clave. Si persiste, escribe a soporte con el request_id.
service_unavailable
| HTTP | retryable | ¿Reintentar? |
|---|---|---|
| 503 | true | Sí, misma clave |
Causa. El servicio no está disponible por ahora.
Solución. Repite con la misma clave y espera exponencial.
Errores comunes
- Decidir por el texto de
message. Puede cambiar;codeno. - Reintentar un error con
retryable: falsesin corregir la causa.