Ir al contenido

Antes de ir a producción

Todo lo de esta lista rompe integraciones reales.

  • El phone del beneficiario se carga siempre, también cuando pagas por transferencia. El alta no lo exige; el riel sí. →
  • El bankCode se valida contra el catálogo del instrumento que vas a usar (GET /payouts/banks?method=…). Las dos listas no coinciden: 31 vs. 24 bancos.
  • El accountNumber son 20 dígitos y empieza por el bankCode.
  • El fullName va tal como lo tiene el banco destino, no como lo tienes tú: el rechazo bancario más frecuente es de titularidad.
  • Mandas el bloque sender, o tienes configurado el remitente por defecto de tu programa. Sin ninguno, la dispersión falla antes de salir. →
  • Todos los importes viajan como enteros en unidades menores, y los parseas de vuelta con enteros de precisión arbitraria, no con Number. →
  • Ningún importe queda al borde del mínimo del riel (~925 Bs hoy, y se mueve con la tasa). →
  • Sabes tu tope por operación y has pedido subirlo si tu caso de uso lo necesita (pago móvil: 100.000,00 Bs por defecto).
  • Cotizas justo antes de dispersar: el TTL es de ~60 segundos y la cotización es de un solo uso. →
  • Toda llamada a POST /payouts lleva Idempotency-Key, con una clave única por operación. →
  • Un timeout o una conexión cortada se reintenta con la misma clave.
  • Un status: "unknown" no se reintenta nunca.
  • Un status: "failed" se reintenta con una cotización nueva, después de corregir la causa de reason.
  • Tu cliente HTTP respeta Retry-After en un 429.
  • Tu sistema marca el pago como pagado con el webhook payment.settled, no con la respuesta de POST /payouts. →
  • Tu receptor verifica la firma HMAC sobre los bytes crudos y rechaza timestamps de más de 5 minutos. →
  • Tu handler deduplica por id: la entrega es at-least-once.
  • Tu receptor responde 2xx en menos de 5 segundos y procesa en segundo plano.
  • Tienes una alerta sobre GET /v1/events?status=dead: si tu receptor estuvo caído, ahí está lo que no llegó.
  • Tratas payment.reversed: el banco puede devolver un pago días después.
  • Tu código programa contra error.code, nunca contra message, y tiene un default para códigos desconocidos. →
  • Distingues error.code (error HTTP) de reason (rechazo del riel dentro de una respuesta 201). Son dos taxonomías distintas.
  • Registras el request_id de cada error: es lo que necesita soporte.
  • Repartes las claves: una con payments:write para el backend que dispersa, otra sólo de lectura para el dashboard. →
  • Sabes si operas prefondeado o con cierre diario, y qué cifra vigilar (prefundingBalance o creditDrawn). →
  • Tu proceso de cuadre usa from/to sobre settled_at, no la fecha de creación. →
  • Guardas bank_reference de cada pago: es el comprobante del beneficiario.
  • Cambias sk_test_… por sk_live_… y confirmas con GET /v1/tenant/me que mode es live.
  • Tu webhookUrl de producción está registrada y su secreto guardado aparte de la API key.
  • Has hecho una dispersión real, pequeña pero por encima del mínimo, y la has seguido hasta settled con su bank_reference.