Conceptos
Todos los errores tienen el mismo cuerpo: una frase en error, un code para tu código y un request_id para soporte.
Forma de un error
{
"error": "Este comercio todavía no puede cobrar con ese medio de pago",
"code": "payment_method_unavailable",
"details": "Los que tiene habilitados son: card, pse.",
"request_id": "b7d1c6f0-…"
}error describe el problema y está pensado para tu log, no para mostrárselo al comprador. code es lo que conviene leer desde tu código: cuando el error no tiene uno propio, es el nombre del código HTTP (bad_request, not_found, conflict…). details viene solo cuando hay algo más que decir, y request_id identifica la petición si nos escribes por ella.
| Código | Significa | ¿Reintentar? |
|---|---|---|
400 | El cuerpo no cumple el contrato: falta un campo, sobra otro o el tipo no corresponde. | No, hasta corregirlo |
401 | La llave falta, no existe o venció. Ver Llaves y entornos. | No |
402 | El emisor o la red no aprobaron el cobro. En POST /v1/payments, el cobro queda creado con status: "failed": la respuesta trae su payment_id y un objeto decline con status_detail y advice_action (ver Cobros). details, cuando viene, es una frase corta con el motivo. | Según decline.advice_action |
403 | La llave es válida pero no puede hacer eso. Para una plataforma: not_a_platform u on_behalf_not_supported (ver Plataformas). | No |
404 | La ruta no existe. También cuando el recurso no es de tu organización. | No |
409 | La operación choca con el estado de las cosas. Con idempotency_key_in_use, la primera petición con esa clave todavía se está procesando. | Solo idempotency_key_in_use: en unos segundos, con la misma clave |
422 | El contrato está bien pero la operación es imposible: monto fuera del tope de un medio instantáneo, por ejemplo. Con idempotency_key_reused, esa clave ya se usó con otra petición. Con payment_method_unavailable, el comercio no tiene habilitado ese medio de pago. Con operation_not_supported_for_method, ese medio no admite la operación (un reembolso de PSE). Con extra_items_not_supported, mandaste extra_items sin ser una plataforma. Con contact_rejected, la red de tarjetas no aceptó el sitio web o el teléfono de un comercio. | No |
429 | Con rate_limited: más de 300 peticiones en un minuto con la misma llave. La cabecera Retry-After dice cuántos segundos esperar. | Sí, después de Retry-After |
500 | Algo se rompió de nuestro lado. | Sí, con la misma Idempotency-Key y espera creciente |
502 | La conexión de Lane con el procesador falló (sus credenciales, no tu llave), y trae provider_status. Cuando el procesador rechaza una operación, el error conserva su código (400, 402, 422…) con provider_status y, si su motivo es una frase corta, details. Si no responde a tiempo, es 504. | Sí, con la misma Idempotency-Key |
504 | Con charge_unconfirmed: el procesador no respondió a tiempo y no se sabe si el cobro pasó. La respuesta trae payment_id. | No. Consulta ese cobro o espera su webhook |
Un recurso ajeno responde 404, no 403. Si pides un cobro que existe pero es de otra organización, la API contesta404. Es a propósito: un403confirmaría que ese identificador existe.
Llegan como 400, en español. Un campo con el tipo equivocado responde error: "Los datos enviados no son válidos" y la lista de problemas en details, separados por ;. Una combinación que no se puede cobrar responde la frase directamente en error.
| Mensaje | Qué corregir |
|---|---|
amount debe ser un entero positivo en la unidad mínima de la moneda | Manda centavos, como entero. Ver Montos. |
Falta instrument_id o provider_instrument_id | Un cobro contra tarjeta guardada necesita saber qué tarjeta. |
cvv es obligatorio cuando initiator es customer… | Si el cliente está presente, el CVV es obligatorio. |
No envíes cvv cuando initiator es merchant… | En un cobro automático no hay quien lo escriba: no lo mandes. |
parent_transaction_data es obligatorio para continuar una serie… | Un cobro recurrente tiene que apuntar al primero de la serie. |
installments.quantity debe ser un entero mayor o igual a 2… | Para un pago sin cuotas, omite el objeto installments. |
success_url debe ser una URL válida | Tiene que ser http o https absoluta. |
Una petición que se corta por un timeout te deja sin saber si pasó. Para poder mandarla otra vez sin riesgo, ponle nombre: una cabecera Idempotency-Key con un valor tuyo, único para esa operación. Si llega dos veces con la misma clave, se ejecuta una sola vez y la segunda recibe la respuesta de la primera, con la cabecera Idempotent-Replayed: true.
Un cobro que se puede reintentar
curl -X POST https://api.lane.money/v1/payments \
-H "Authorization: Bearer sk_test_…" \
-H "Idempotency-Key: pedido-4821-cobro" \
-H "Content-Type: application/json" \
-d '{ "amount": 8900000, "instrument_id": "c1a9f3e0-…" }'| La aceptan | Qué evita |
|---|---|
POST /v1/payments | Cobrar dos veces la misma tarjeta. |
POST /v1/payments/{id}/refund y las demás operaciones sobre un cobro | Devolver, capturar o anular dos veces. |
POST /v1/checkout/sessions y POST /v1/payment_links | Crear dos pantallas de pago para un pedido. |
POST /v1/enrollment/sessions | Crear dos pantallas para guardar la misma tarjeta. |
POST /v1/platform/signup-links | Crear dos enlaces de registro para un comercio. |
422 (idempotency_key_reused). El cvv no cuenta para la comparación, y no se guarda.409 (idempotency_key_in_use); vuelve a intentar en unos segundos.4xx—, el reintento se procesa de nuevo. Un rechazo que llegó como 201 con status: "failed" sí es una respuesta: con la misma clave recibes ese mismo cobro fallido. Para volver a intentar, usa otra clave. Y charge_unconfirmed (504) también se guarda: la misma clave lo devuelve sin cobrar de nuevo.422 (idempotency_key_reused).Un cobro sin confirmar no se reintenta. La excepción a esa última regla es el504concharge_unconfirmed: el procesador no respondió y el cobro pudo haber pasado. Con la misma clave recibes ese mismo error, nunca un segundo cobro. Consulta elpayment_idque trae la respuesta, o espera el webhook, y decide con el estado que veas.
Sin la cabecera, todo funciona como siempre: un POST reintentado es una operación nueva. Por eso conviene mandarla siempre que la operación mueva plata, y guardar además tu identificador en metadata: vuelve en el objeto del cobro tal como lo mandaste (salvo las llaves que empiezan por lane_ o blink_).
Esta página en markdown: /docs/errores.md · Toda la documentación: /docs/llms-full.txt