Hay tres capas distintas y conviene no confundirlas:
| Capa | Ejemplo | Qué significa |
|---|---|---|
| HTTP | 422 |
Cómo respondió nuestra API |
| Validación | errors.payment_card.cvv |
Tu petición no cumple las reglas. Se arregla en tu código |
| Código de red | 51, M12, V68 |
La operación llegó a la red y la red decidió. No siempre se arregla reintentando |
Un pago rechazado no es un error de tu integración: la petición fue correcta y el
resultado fue «no». Devuelve 200 u 422 según el caso, y siempre trae el estado de la
transacción para que sepas en qué quedó.
{warning} Nunca reintentes automáticamente un rechazo. Si la razón fue fondos insuficientes o una tarjeta bloqueada, reintentar da el mismo resultado y algunos emisores penalizan los reintentos.
| Código | Cuándo | Qué hacer |
|---|---|---|
200 |
La operación se procesó. Revisa el estado del cuerpo: puede ser un rechazo | Leer status / success |
201 |
Se creó algo (una reserva autorizada, por ejemplo) | Guardar el id |
202 |
Estado indeterminado: no sabemos aún el resultado | No reintentar. Esperar el webhook o consultar |
400 |
Regla de negocio incumplida (por ejemplo, borrar un suscriptor con suscripción activa) | Leer message |
401 |
Falta el token o no es válido | Ver Autenticación |
403 |
Token válido pero sin permiso, comercio deshabilitado, o cobro que ya no acepta pagos | Leer message |
404 |
El recurso no existe, o es de otro comercio, o del otro ambiente | Revisar el id y el tipo de token |
409 |
Conflicto: cobro ya aplicado, o Idempotency-Key reutilizada con otros parámetros |
Leer message |
422 |
Validación, o la red rechazó | Leer errors o el estado |
429 |
Ya hay una operación igual en curso | Esperar el resultado, no reintentar |
5xx |
Error de nuestro lado o de la red | Reintentable con espera |
Siempre tienen la misma forma: un message con el primer error y un objeto errors con
todos, indexados por el nombre del campo.
{danger} Validación code:
422 { "message": "El campo payment_card.cvv es obligatorio.", "errors": { "payment_card.cvv": ["El campo payment_card.cvv es obligatorio."], "customer_payer.email": ["El campo customer_payer.email debe ser un correo válido."] } }
Las claves de errors usan notación de punto para los campos anidados. Úsalas para
marcar el campo exacto en tu formulario en lugar de mostrar un mensaje genérico.
{warning} Una excepción: generar un pago devuelve solo el mapa de errores, sin
messageni la envolturaerrors:{ "payment.amount": ["The payment.amount field is required."] }Y si en esa misma llamada omites
payment.currency_type, la validación se detiene ahí: recibirás ese único error y ninguno más, porque los límites de monto dependen de la moneda.
Las escrituras de suscripciones
aceptan el header Idempotency-Key. Cuando esa clave choca, el cuerpo no tiene la
forma de un error de validación: trae un objeto error con su propio type.
{danger} Misma clave, parámetros distintos code:
409 { "error": { "type": "idempotency_error", "message": "La Idempotency-Key ya fue usada con parámetros distintos." } }
{danger} Misma clave, misma petición todavía en curso code:
409 { "error": { "type": "idempotency_error", "message": "Una solicitud con esta Idempotency-Key aún está en proceso." } }
Cuando en cambio repites exactamente la misma llamada con la misma clave, te
devolvemos la respuesta original con el header Idempotency-Replayed: true y sin volver
a ejecutar el cobro.
| Detalle | Comportamiento |
|---|---|
| Vigencia de la clave | 24 horas |
| Métodos afectados | POST, PUT, PATCH, DELETE |
| Rutas | Las escrituras de /api/v1/subscriptions/*, /api/v1/payment/* y /api/v1/mit/pre-authorizations/*. Ver el detalle en Convenciones |
| Alcance de la clave | Por comercio y usuario del token |
Respuestas 5xx |
No se memorizan, para que puedas reintentar un fallo transitorio |
{success} Úsala en todo cobro. El caso que evita: cobras, tu proceso se cae antes de guardar la respuesta, y al reintentar no sabes si el primer intento llegó. Con la misma
Idempotency-Keyel segundo intento te devuelve la respuesta original en vez de cobrar dos veces.
{info} La clave la eliges tú: una distinta por operación, no por reintento. Un UUID generado al empezar el cobro y reutilizado en todos los reintentos de esa misma operación es lo habitual.
Los más frecuentes. El código llega en response_code de la transacción y, cuando no fue
aprobada, también en error.code con su message, su retryable y su action.
{
"status": "Rechazada",
"status_key": "rejected",
"response_code": "51",
"error": { "code": "51", "message": "…", "retryable": false, "action": "contact_issuer" }
}
{info} El catálogo completo, con todos los códigos y su
retryable, se consulta en vivo enGET /api/v1/resources/mit/response-codes. Léelo de ahí en vez de copiar esta tabla: se mantiene sola.
| Código | Qué pasó | Qué hacer |
|---|---|---|
00 |
Aprobada | — |
05 |
Negada: la tarjeta puede estar bloqueada, o el emisor no respondió | Pedir otro medio de pago |
51 |
Fondos insuficientes | Pedir otra tarjeta o un monto menor |
54 |
Tarjeta vencida | Pedir la fecha correcta u otra tarjeta |
57 |
El emisor no permite este tipo de transacción | Pedir otro medio de pago |
61 |
Excede el límite de la tarjeta | Pedir otra tarjeta o un monto menor |
91 |
El emisor no está disponible | Reintentable más tarde |
error.retryable |
Ejemplos | Qué hacer |
|---|---|---|
false |
05, 51, 54, 57, 61 (fondos, vencida, bloqueada, límite) |
No reintentes. El resultado será el mismo y algunos emisores penalizan la insistencia. Pide otro medio de pago |
true |
91, E99, S01, S10, S11 (la red o un servicio interno falló) |
Reintenta con espera creciente |
| — | T01 y cualquier 202 |
Estado indeterminado: no reintentes. No sabemos si la operación se procesó. Consulta el estado antes de hacer nada |
{danger} La diferencia entre «falló» y «no sé si falló» es la que produce cobros dobles. Ante
T01o un202, consulta con estado de transacción antes de reenviar nada.
Estos son propios de las reservas de cupo.
| Código | HTTP | Qué pasó |
|---|---|---|
MIT_PRODUCTION_KEY_REQUIRED |
422 | Intentaste autorizar con llave de prueba; una reserva retiene fondos reales |
MIT_AMOUNT_EXCEEDS_AUTHORIZED |
422 | El cobro final supera lo reservado |
MIT_EXPIRED |
422 | La reserva venció; hay que crear una nueva |
MIT_ALREADY_CONFIRMED |
409 | Esta reserva ya tiene su cobro aplicado |
MIT_VOID_WINDOW_CLOSED |
422 | Ya cerró la ventana para liberar (24 h antes del vencimiento). Deja que venza |
MIT_FRANCHISE_NOT_ENABLED |
422 | Esa franquicia no está habilitada para reservas en tu comercio |
MIT_INDETERMINATE |
202 | No recibimos respuesta de la red. No reintentes |
MIT_IN_PROGRESS |
429 | Ya hay una autorización en curso para esta reserva |
M01 |
409 | La reserva ya fue confirmada |
M02 |
422 | La operación referenciada no es una reserva pre-autorizada |
M04 |
422 | La reserva está vencida en la red |
M05 |
422 | La reserva no fue aprobada, así que no hay cupo que cobrar |
M06 |
422 | La red no encuentra la operación. Solo conserva 30 días |
M08 / M10 / M11 |
422 | La franquicia o el banco emisor no permiten reservas |
M12 |
422 | El valor del cobro final no corresponde al reservado |
309 |
422 | El tipo de transacción MIT no admite 3DS |
310 |
422 | El ECI enviado no es válido: debe ser 05, 06 o 07 |
319 / 320 |
422 | Enviaste el objeto 3DS de la otra franquicia |
| Código | Qué pasó |
|---|---|
A01 |
Pasó la fecha permitida para anular |
A03 – A06 |
La operación no está en un estado que admita anulación |
A07 |
No se puede anular una operación incremental |
V39 |
No se puede liberar una reserva que ya fue cobrada |
V40 |
La reserva no está en fecha válida para liberarse |
V42 |
La operación indicada no es anulable |
| Código | HTTP | Qué pasó | Qué hacer |
|---|---|---|---|
T01 |
202 | Se agotó el tiempo de espera con la red. No sabemos si la operación quedó registrada | No reintentar. Consultar el estado |
E99 |
502 | Error interno de la red | Reintentable con espera |
S10 / S11 |
500 | Fallo de cifrado con la red | Contactar a soporte |
{danger}
T01yMIT_INDETERMINATEson los dos casos en que reintentar es peligroso: si la operación sí se aplicó, un reintento la duplica. Consulta el estado o espera el webhook.
En lugar de copiar esta tabla a tu código, consúltala:
GET /api/v1/resources/mit/response-codes
Cada entrada trae:
| Campo | Para qué |
|---|---|
| code | El código |
| message | El mensaje pensado para el comercio |
| action | Qué hacer |
| retryable | Si tiene sentido reintentar |
Tenemos dos mensajes para cada código y sirven para cosas distintas:
| Campo | Audiencia | Ejemplo |
|---|---|---|
| Mensaje al pagador | El tarjetahabiente | «Transacción declinada. Fondos insuficientes» |
| Mensaje al comercio | Tu operador o tu log | «Fondos insuficientes. Pídele al cliente otra tarjeta» |
En la respuesta de una transacción, authorization_message_customer y description
traen el mensaje que se le puede mostrar al cliente tal cual.
{warning} No le muestres al cliente el código crudo ni el mensaje interno. Un
M12en pantalla no le dice nada a nadie, y los mensajes internos pueden mencionar tu configuración.