Ir al contenido

Cuando algo falla

Lo que ves ¿Reintentas? Cómo
status: "submitted" No Espera el webhook. Ya está en curso
status: "unknown" NUNCA Se resuelve solo. Reintentar aquí es como se paga dos veces
status: "failed" + reason de datos Sí, tras corregir Corrige el beneficiario y pide otra cotización
status: "failed" + reason de riel Sí Otra cotización, sin cambiar nada más
502 provider_error Sí Reintenta con la misma Idempotency-Key
503 no_provider_available Sí, más tarde No hay riel ahora mismo para ese banco/instrumento
429 rate_limited Sí, más despacio Respeta Retry-After
4xx de validación No sin corregir El mismo cuerpo va a fallar igual

Qué hacemos mientras el pago está en duda:

  1. No se compensa nada. El asiento queda como está.

  2. Se consulta al riel con nuestra referencia, con espera creciente.

  3. Se resuelve: pagó → settled; no reconoce la referencia tras varias consultas → se compensa y queda failed; devuelto → reversed.

  4. Te avisamos por webhook. No hace falta polling.

Para vigilarlo:

Ventana de terminal
curl -s "$BASE/v1/payments?status=unknown&limit=100" -H "x-api-key: $KEY"

El asiento ya está revertido y no se te ha cobrado nada (feeAmount: "0", compensated: true). Reintenta con otra cotización en cuanto arregles la causa, que está en reason:

reason De quién es el problema Reintento útil
beneficiary_missing_phone Tuyo: falta el móvil (pasa también en transferencia) Tras cargar el phone
beneficiary_missing_account Tuyo: falta la cuenta Tras cargarla
beneficiary_mismatch Tuyo: nombre o cédula no coinciden con el titular Tras corregir. Ningún riel lo aceptaría
invalid_destination_account Tuyo: la cuenta no existe o está mal Tras corregir
sender_required Tuyo: no había remitente Mandando el bloque sender
amount_below_rail_minimum Del importe: por debajo del piso del riel Subiendo el importe
amount_above_rail_limit Del importe: por encima del techo Partiéndolo
bank_unreachable Del riel: no cubre ese banco Ya se intentó otro; revisa el catálogo del instrumento
rail_insufficient_balance Del riel: sin liquidez ahora Más tarde
no_route De la combinación: ningún riel candidato Prueba el otro instrumento

Si el instrumento que pediste no está disponible y methodPolicy es preferred (por defecto), el pago sale por el otro:

{ "status": "submitted", "method": "transferencia",
"methodRequested": "pago_movil", "methodChanged": true }

El estado sigue siendo submitted: el cambio de canal ya ocurrió, pero el envío todavía está liquidando. Con methodPolicy: "strict" la dispersión falla en vez de cambiar de canal.

Días después, el banco puede devolver una transferencia (cuenta cerrada, datos incorrectos). El evento se verifica y se deduplica, se revierte el asiento —el pago pasa a reversed y los fondos vuelven a tu saldo— y recibes payment.reversed con el motivo que reportó el banco. Lo que te toca es avisar a tu usuario.

Reintentamos con espera creciente (5 s → 6 h, 12 intentos). Al agotarlos el evento pasa a tu cola de fallidos, consultable y reentregable.

Ventana de terminal
curl -s "$BASE/v1/events?status=dead" -H "x-api-key: $KEY"
curl -s -X POST "$BASE/v1/events/retry-dead" -H "x-api-key: $KEY"

Ver webhooks.

Cada caso se provoca en el entorno de pruebas: mode: "reject" con method para el cambio de canal, mode: "timeout_after_submit" para el pago en duda, /sandbox/bank/payout-settled y /sandbox/bank/payout-returned para la confirmación tardía y la devolución, y /sandbox/webhooks/failing para tus reintentos.

Ventana de terminal
curl -s -X POST $BASE/sandbox/chaos -H 'content-type: application/json' \
-d '{"mode":"timeout_after_submit"}'