Skip to main content
Esta guía es para desarrolladores que implementan la integración del plugin Bank Transfer. Cubre los patrones y las decisiones que van más allá de las llamadas a endpoints individuales: idempotencia, estrategia de reintentos, manejo de estados y validación de webhooks. Para los parámetros de los endpoints y los esquemas de respuesta, consulta la Referencia de API.

Idempotencia


Cada solicitud que modifica datos (initiate, process, cancel) requiere un encabezado X-Idempotency. Si envías la misma clave dos veces, el plugin devuelve la respuesta original sin crear una operación duplicada. Reglas:
  • Usa un UUID v4 o un identificador de negocio único (p. ej. el ID de pedido de tu sistema)
  • Longitud máxima: 255 caracteres
  • El plugin limita cada clave a la organización efectiva. La misma clave desde dos organizaciones cuenta como dos solicitudes distintas.
  • El plugin devuelve una respuesta en caché durante la ventana de idempotencia configurada (IDEMPOTENCY_RETRY_WINDOW_SEC, predeterminado 300 segundos)
  • Una respuesta repetida es idéntica byte a byte a la original: mismo código de estado, mismo cuerpo. La respuesta no tiene ningún encabezado que marque una repetición, así que diseña tu cliente para que sea seguro en cualquiera de los dos casos.
No reutilices claves de idempotencia entre operaciones distintas. No reutilices una clave de initiate para hacer process o cancel de la misma transferencia.

Detección de duplicados

Más allá de las claves de idempotencia, el plugin detecta duplicados basados en el contenido. Construye una huella a partir de:
  • senderAccountId
  • los datos del receptor (ISPB, sucursal, cuenta, documento del titular)
  • el monto
  • el propósito
El plugin guarda la huella en Redis durante 5 minutos. El valor predeterminado es 300 segundos. Los operadores lo ajustan por tenant a través del ajuste del systemplane idempotency.duplicate_guard_ttl_seconds. La organización no forma parte de la huella. El aislamiento entre tenants viene del prefijo de la clave de Redis. El plugin rechaza la solicitud con 409 BTF-0012 si el cliente ya envió una transferencia coincidente dentro de la ventana. Esto detecta los casos en que el cliente envía la misma transferencia con una clave de idempotencia distinta. Un ejemplo es un reintento después de un timeout, cuando el cliente no recibió la respuesta original.

Estrategia de reintentos


Usa backoff exponencial para los errores transitorios. No reintentes todos los errores. Programa de backoff recomendado para 5xx/503: 0s, 5s, 25s, 60s, 120s (5 intentos en total).
Cuando JD SPB no está disponible, la respuesta es HTTP 503. El campo error.code lleva entonces el código propio del proveedor JD, por ejemplo TRANSPORT para fallas de transporte o ACE95 para timeouts. El plugin no envuelve las fallas de la cadena de JD en un código BTF-. Marca la transferencia para conciliación manual cuando se agoten los reintentos. No reintentes sin límite. La red de JD SPB tiene un horario de operación definido.

Manejo de estados


Máquina de estados de TED OUT

Las transferencias siguen una progresión estricta. No puedes cancelar una transferencia después de que sale de CREATED o PENDING.
Máquina de estados de TED OUT
Qué hacer en cada estado:

Máquina de estados del inicio

El endpoint initiate crea una entidad PaymentInitiation. Esta entidad tiene su propio ciclo de vida antes de que el plugin cree una Transfer.
Máquina de estados del inicio

Máquina de estados de TED IN

Máquina de estados de TED IN

Máquina de estados de P2P

P2P no tiene un estado PENDING. La liquidación es atómica e instantánea.
Máquina de estados de P2P

Polling frente a webhooks

Prefiere los webhooks para el estado en tiempo real. Si todavía no configuraste webhooks, consulta GET /v1/transfers/{transferId}. Usa como máximo 10 intentos con el mismo programa de backoff que los reintentos. Marca la transferencia para revisión manual después de 10 minutos sin un estado terminal (COMPLETED, REJECTED, FAILED, CANCELLED). Consulta Get Transfer y Webhooks.

Integración de webhooks


Para los esquemas de payload de los eventos y la lista completa de eventos, consulta Webhooks.

Validación de la firma

Cada solicitud de webhook incluye encabezados que tu endpoint usa para verificar la autenticidad:
  • X-Webhook-Signature: firma HMAC-SHA256 versionada con la forma v1,sha256=<hex>
  • X-Webhook-Timestamp: marca de tiempo Unix en segundos (UTC) del momento en que el plugin construyó la solicitud
  • X-Webhook-Event: el tipo de evento (por ejemplo, transfer.completed). Este encabezado no forma parte de la firma.
El plugin calcula la firma así:
La cadena firmada tiene cuatro partes en orden: el prefijo v1:, el valor de la marca de tiempo de X-Webhook-Timestamp, un punto ASCII (.), y luego los bytes del cuerpo de la solicitud sin procesar. Usa los bytes del cuerpo exactamente como llegan por la red. No los analices ni los vuelvas a codificar antes. Para validar:
  1. Lee X-Webhook-Signature y X-Webhook-Timestamp de los encabezados de la solicitud.
  2. Construye la cadena firmada: "v1:" + timestamp + "." + rawBody.
  3. Calcula HMAC-SHA256 sobre la cadena firmada con tu WEBHOOK_SIGNING_SECRET, y luego codifica el resultado en hexadecimal.
  4. Antepón v1,sha256=, y luego compáralo con X-Webhook-Signature con una función de igualdad de tiempo constante.
  5. Rechaza la solicitud si la marca de tiempo queda fuera de una ventana de frescura aceptable (una tolerancia de 5 minutos es lo típico) para evitar repeticiones.
Aparte de X-Webhook-Signature y X-Webhook-Timestamp, el plugin define solo X-Webhook-Event (el tipo de evento). No envía X-Webhook-Event-Type, X-Webhook-Routing-Key ni X-Webhook-Delivery-Attempt.

Procesamiento idempotente de webhooks

Tu endpoint puede recibir el mismo evento más de una vez (entrega al menos una vez). Usa transferId + event como clave compuesta para deduplicar.

Patrones de manejo de errores


Asigna los códigos de error de la API a acciones de cara al usuario. Consulta la lista completa de errores para todos los códigos. Las respuestas de error siguen esta estructura:

Lista de verificación para salir a producción


Antes de habilitar la integración en producción:
  • Envía X-Idempotency en cada solicitud de initiate, process y cancel
  • Lógica de reintentos implementada con backoff exponencial para los errores 5xx/503
  • Endpoint de webhook desplegado y que devuelve 200 en menos de 5 segundos
  • Validación de la firma activa en el endpoint de webhook
  • Deduplicación de eventos de webhook implementada con transferId + event
  • Horario de operación validado del lado del cliente antes de llamar a initiate (reduce los 422 innecesarios)
  • transferId y confirmationNumber almacenados para la conciliación
  • Estados terminales (COMPLETED, REJECTED, FAILED, CANCELLED) manejados en la interfaz
  • Expiración del inicio (24h) manejada: pide al usuario que reinicie cuando pase la ventana
  • Preparación del servicio monitoreada en tu sistema de alertas para los despliegues BYOC
  • Redis alcanzable y monitoreado: el servicio rechaza solicitudes cuando Redis está caído
  • PLUGIN_AUTH_ENABLED=true configurado en producción, con un PLUGIN_AUTH_ADDRESS válido (HTTPS)