Blog Arquitectura Neges

Flujo de pago Flow multi-tenant en Neges

Documentación técnica del ciclo completo de pago: creación de orden, reutilización de checkout, llamada a Flow, confirmación, retorno, estados e invariantes operativas.

22 min de lectura

El pago en Neges se divide en dos responsabilidades: la tienda crea o reutiliza una orden, y Strapi crea o reutiliza una intención de pago contra Flow. Flow nunca decide a qué tenant pertenece la compra; esa relación vive en la orden guardada.

Resumen ejecutivo

El pedido se crea antes de enviar al cliente a Flow. Esa decisión permite congelar productos, precios, despacho, cliente, tenant y número de orden antes de cualquier interacción con la pasarela.

La creación del pago es idempotente por orden: si existe un checkout pendiente compatible con la configuración actual, Strapi lo reutiliza. Si la configuración de pago cambió, por ejemplo de sandbox a producción, Strapi crea una nueva intención de pago para evitar redirigir al cliente a un checkout antiguo.

La confirmación financiera ocurre siempre en Strapi. El navegador sólo redirige; no aprueba pagos, no calcula montos finales y no decide el tenant de retorno.

Principios de diseño

  • El navegador no aprueba pagos.
  • neges-store orquesta la experiencia de checkout, crea la orden cuando corresponde y redirige al checkout de Flow.
  • neges-strapi es la autoridad de negocio: crea órdenes, crea pagos, guarda eventos y valida el estado contra Flow.
  • paymentStatus y status operativo son conceptos separados: pagar una orden no significa prepararla automáticamente.
  • El tenant dinámico se obtiene desde la orden guardada, no desde Flow ni desde el navegador.
  • Las credenciales de Flow nunca se exponen al frontend.
  • Cada evento de pago debe dejar trazabilidad suficiente para auditar monto, ambiente, tenant y configuración usada.

Mapa general del flujo

Este diagrama resume el caso normal: el cliente revisa la compra, la tienda crea la orden, Strapi crea una intención Flow, Flow confirma el pago y Strapi redirige al cliente al tenant correcto.

flujo-pago-completo.mmdmermaid
El diagrama se renderiza al cargar la pagina.

Flujo paso a paso

  1. Crear la orden desde la tienda

    El cliente está en una tienda, por ejemplo https://lumiaonline.cl, y neges-store crea la orden vía POST /storefront-api/orders. El proxy reenvía a Strapi con el tenant resuelto.

  2. Congelar datos de la compra

    Strapi guarda la orden asociada al tenant y congela monto, moneda, productos y datos de entrega.

  3. Iniciar pago con Flow

    neges-store pide iniciar el pago con POST /storefront-api/orders/:documentId/payments/flow. Strapi llama a Flow payment/create con apiKey, commerceOrder, subject, amount, email, urlConfirmation y urlReturn.

  4. Redirigir al checkout

    Flow responde con token y URL de checkout. neges-store redirige al cliente a esa URL.

  5. Validar retorno y confirmación

    Flow llama a urlConfirmation y urlReturn con el token. Strapi consulta payment/getStatus(token), valida monto y commerceOrder, y actualiza paymentStatus.

  6. Volver al tenant correcto

    Strapi recupera el tenant desde la orden asociada al token y redirige al cliente a la tienda correcta.

Capas y responsabilidades

Esta separación evita filtrar secretos y deja el estado financiero centralizado en Strapi.
CapaResponsabilidadLo que no debe hacer
neges-storeValidar la experiencia de checkout, mantener la orden finalizada en estado local, llamar al proxy y redirigir al checkout de Flow.No guarda secretos, no consulta Flow directo, no aprueba pagos.
Storefront APIResolver el tenant desde host o contexto, normalizar errores y reenviar la solicitud a Strapi.No contiene reglas financieras ni credenciales Flow.
neges-strapiCrear la orden, congelar snapshots, resolver configuración de pago, crear o reutilizar Flow, recibir callbacks y actualizar estados.No depende del localStorage del cliente ni de datos no validados del navegador.
FlowAutorizar o rechazar el pago y entregar token, checkoutUrl y estado oficial del pago.No resuelve tenants de Neges ni decide URLs de tienda final.
BackofficeConfigurar credenciales, ambiente, modalidad y revisar pedidos después del pago.No debe asumir que cambiar configuración invalida automáticamente checkouts ya emitidos; esa regla vive en Strapi.

Cuándo se crea una orden

La tienda llega a review con carrito, cliente, dirección y método de despacho. Desde ahí decide si debe crear una orden nueva o reutilizar una orden ya finalizada en el flujo actual.

Situación en checkoutAcciónRazón
No existe orden finalizada y el carrito es válidoCrear orden con POST /storefront-api/ordersTodavía no hay documentId ni orderNumber para iniciar Flow.
Existe orden con documentId y paymentStatus pendingNo crear otra orden; iniciar o reutilizar pago de esa ordenEvita duplicar pedidos por doble click, refresh o reintento del usuario.
Existe orden pagada y el carrito sigue con itemsLimpiar la orden actual y crear un pedido nuevoUna orden paid no debe volver a pagarse ni mezclarse con una nueva intención de compra.
Existe orden pagada y el carrito está vacíoCompletar la navegación de éxitoEl flujo ya terminó y sólo falta mostrar el resultado.
El carrito está vacío antes de crear ordenNo crear ordenNo hay base comercial para congelar monto ni productos.
Faltan contacto, despacho o método de entregaNo crear orden; volver al primer paso inválidoLa orden debe nacer con datos mínimos consistentes.

Qué congela Strapi al crear el pedido

La creación del pedido ocurre en Strapi porque ahí se puede validar el tenant, leer productos reales, calcular snapshots y persistir todo en una transacción. La orden inicial queda normalmente con status created, paymentStatus pending, paymentProvider flow y fulfillmentStatus unfulfilled.

  • Tenant: la tienda que originó la compra.
  • Cliente: datos de contacto y métricas asociadas.
  • Items: snapshot de nombre, SKU, cantidad, precio y moneda.
  • Totales: subtotal, despacho, descuentos si aplican y total final.
  • Entrega: dirección, comuna, región, carrier o retiro según método.
  • Identificadores: documentId público y orderNumber humano.
  • Estado inicial: pedido creado, pago pendiente y despacho no preparado.

Cuándo se crea o reutiliza Flow

El endpoint de pago recibe el documentId de la orden. Strapi busca esa orden dentro del tenant, valida que se pueda pagar y decide si reutiliza un checkout pendiente o si crea una nueva intención contra Flow.

decision-crear-o-reutilizar-flow.mmdmermaid
El diagrama se renderiza al cargar la pagina.

Reglas de reutilización del checkout

La comparación de snapshot es clave para evitar checkouts obsoletos después de cambios en Backoffice.
CondiciónSe reutilizaMotivo
La orden ya está pagadaNo se crea Flow nuevoLa operación es idempotente: se devuelve el estado pagado y se evita un segundo cobro.
Existe token pendiente, checkoutUrl y evento flow_payment_created compatibleEl usuario puede reintentar después de refresh o doble click sin abrir múltiples intenciones de pago.
El evento pendiente fue creado con otro ambienteNoUn checkout sandbox no debe reutilizarse si la tienda ahora está en producción.
Cambió paymentMethod, timeout o modalidad de credencialesNoLa intención anterior ya no representa la configuración activa del tenant.
El pago anterior falló o no tiene checkoutUrl confiableNoSe necesita una nueva intención trazable.
La orden fue cancelada o reembolsadaNoNo se permite iniciar cobros sobre órdenes cerradas operacionalmente.

Snapshot de configuración de pago

Cada intención Flow se guarda con una copia mínima de la configuración usada al crearla. Esa copia no contiene secretos, pero sí los campos necesarios para saber si el checkout sigue siendo compatible con la configuración activa del tenant.

payment-config-snapshot.jsonjson
{
  "credentialMode": "tenant_flow",
  "environment": "production",
  "paymentMethod": 9,
  "settingDocumentId": "payment-setting-document-id",
  "timeoutSeconds": 1800
}

Datos enviados a Flow

Strapi arma la solicitud a Flow desde la orden persistida, no desde el payload del navegador. El commerceOrder debe ser único por intento de pago, pero también rastreable al orderNumber interno.

Campo FlowOrigen en NegesConsideración
apiKeyConfiguración segura del tenant o credenciales globalesNo se expone al frontend.
commerceOrderorderNumber más sufijo único del intentoPermite auditar reintentos sin perder vínculo con la orden.
subjectResumen del pedidoDebe ser legible para el comprador.
amountTotal de la ordenDebe ser mayor que cero y validarse al confirmar.
emailEmail del clienteFlow lo usa para la experiencia de pago.
urlConfirmationEndpoint público de StrapiCallback servidor-servidor; no depende del navegador.
urlReturnEndpoint público de StrapiStrapi valida token y redirige a la tienda del tenant.

Confirmación y retorno

Flow puede avisar por confirmación servidor-servidor y por retorno del navegador. Ambos caminos deben ser defensivos e idempotentes: consultar estado a Flow, validar que corresponde a la orden, actualizar sólo cuando corresponde y no duplicar efectos secundarios.

confirmacion-retorno-flow.mmdmermaid
El diagrama se renderiza al cargar la pagina.

URLs enviadas a Flow

En producción, ambas URLs apuntan a Strapi. Después de validar el token, Strapi construye el retorno final hacia el dominio del tenant.

flow-callbacks.txttext
urlConfirmation:
https://api.neges.cl/api/storefront/payments/flow/confirmation

urlReturn:
https://api.neges.cl/api/storefront/payments/flow/return

Retorno final esperado:
https://<tenant-host>/checkout/success?order=<orderNumber>&payment=paid
https://<tenant-host>/checkout/review?order=<orderNumber>&payment=failed

Resolución multi-tenant

Flow no recibe el tenant como autoridad de negocio. La autoridad es la orden. Cuando Flow vuelve con token, Strapi busca la orden, lee su tenant y recién ahí decide el host final de retorno.

flow-tenant-resolution.mmdmermaid
El diagrama se renderiza al cargar la pagina.

Cómo Strapi sabe a qué tenant volver

Cuando se inicia el pago, Strapi ya conoce la orden y su tenant. El backend guarda en metadata.paymentEvents datos como token, commerceOrder, monto, moneda, checkoutUrl y tenant.slug.

Cuando Flow vuelve con token=abc, Strapi busca la orden con paymentProvider=flow y paymentReference=abc. Desde esa orden recupera tenant.slug y construye la URL final.

redirects-produccion.txttext
Pago aprobado:
https://lumiaonline.cl/checkout/success?order=NS-123&payment=paid

Pago fallido o pendiente:
https://lumiaonline.cl/checkout/review?order=NS-123&payment=failed

Configuración recomendada

production.envbash
FLOW_MODE=production
FLOW_PUBLIC_API_BASE_URL=https://api.neges.cl
FLOW_STOREFRONT_RETURN_BASE_URL=https://{tenant}.neges.cl
FLOW_PAYMENT_METHOD=9
FLOW_PAYMENT_TIMEOUT_SECONDS=1800
FLOW_REQUEST_TIMEOUT_MS=10000
sandbox-local.envbash
FLOW_MODE=sandbox
FLOW_PUBLIC_API_BASE_URL=http://localhost:1337
FLOW_STOREFRONT_RETURN_BASE_URL=http://localhost:4200?tenant={tenant}
FLOW_PAYMENT_METHOD=9

Estados y eventos relevantes

Neges separa el estado financiero del estado operativo. Esa separación evita que un cobro aprobado cambie automáticamente el flujo de preparación, despacho o cancelación.

ElementoValores o eventoUso operativo
order.statuscreated, preparing, ready, fulfilled, cancelledEstado operativo del pedido. Backoffice lo mueve según preparación y entrega.
order.paymentStatuspending, paid, failed, refundedEstado financiero. Lo actualiza Strapi después de consultar a Flow.
order.paymentProviderflowPermite saber qué integración administra el cobro.
order.paymentReferencetoken Flow vigenteLlave principal para encontrar la orden cuando Flow vuelve con token.
metadata.paymentEvents[].typeflow_payment_createdRegistra intento creado, token, checkoutUrl, commerceOrder y snapshot de configuración.
metadata.paymentEvents[].typeflow_payment_statusRegistra cambios o lecturas relevantes de estado desde Flow.
metadata.paymentEvents[].typesimulated_paymentUso de modo fake o pruebas controladas sin proveedor real.

Fallas, reintentos y efectos secundarios

FallaResultado esperadoDato para diagnosticar
Flow responde apiKey not foundLa orden queda pendiente y no se guarda checkout válido nuevo.Ambiente, credentialMode y credenciales configuradas en Backoffice.
El cliente cierra la pestaña en FlowLa orden sigue pending y puede reintentar desde checkout/review.paymentReference y último flow_payment_created.
Flow confirma paid pero el navegador no vuelveStrapi deja paymentStatus paid por callback servidor-servidor.Evento flow_payment_status y email de confirmación.
El navegador vuelve antes de la confirmaciónStrapi consulta Flow en urlReturn y actualiza si el estado ya cambió.Respuesta de payment/getStatus para el token.
Backoffice cambia sandbox a producción con una orden pendienteEl siguiente intento crea un checkout production nuevo.Comparación entre snapshot del evento pendiente y configuración actual.

Configuración operativa

Backoffice configura la modalidad de cobro del tenant: proveedor Flow, ambiente sandbox o producción, modalidad de credenciales, API key, secret key, método de pago y timeout. El backend cifra secretos y sólo expone a la UI los datos no sensibles necesarios para mostrar la modalidad actual.

  • Usar sandbox sólo para pruebas controladas; los checkouts sandbox deben abrir sandbox.flow.cl.
  • Usar producción para tiendas reales; los checkouts productivos deben abrir www.flow.cl.
  • Validar que API key y secret correspondan al mismo ambiente.
  • Después de cambiar ambiente, probar con una orden nueva o reintentar una pendiente y confirmar que se emite un checkout compatible.
  • No documentar ni pegar secretos reales en issues, chats o capturas compartidas.
  • Mantener un timeout explícito para evitar checkouts infinitamente reutilizables.

Observabilidad mínima

Para analizar incidentes de pago, la información mínima debe permitir responder: qué orden era, qué tenant la originó, qué ambiente Flow se usó, qué commerceOrder se envió, qué token volvió, qué monto reportó Flow y qué transición de estado se aplicó.

Pregunta de soporteDónde mirar primero
El cliente fue a sandbox?paymentEvents.flow_payment_created.config.environment y checkoutUrl.
Se cobró dos veces?Cantidad de eventos flow_payment_created, tokens y estados Flow por commerceOrder.
Por qué la orden sigue pending?Última respuesta payment/getStatus y callbacks recibidos.
Qué tenant debe recibir el retorno?Relación order.tenant y storefrontHost guardado.
El monto de Flow coincide?Comparación entre total congelado de la orden y amount reportado por Flow.

Preguntas para análisis crítico futuro

  • Debemos permitir múltiples intentos Flow activos por orden o invalidar explícitamente los tokens anteriores?
  • El paymentReference debe guardar sólo el token vigente o una tabla/evento indexable por todos los tokens históricos?
  • Cuánto tiempo se debe reutilizar un checkout pendiente antes de forzar uno nuevo?
  • Qué SLA de confirmación y alertas necesitamos cuando Flow no llama urlConfirmation?
  • Qué panel necesita soporte para distinguir error de credenciales, rechazo del banco, abandono del usuario y error técnico?
  • Qué datos deben quedar firmados o auditados para conciliación contable posterior?
  • La preparación del pedido debe seguir siendo manual después de paid o conviene una automatización configurable por tenant?

Checklist de prueba end-to-end

  1. Crear una orden desde checkout/review

    Usar un carrito real, contacto válido y método de despacho configurado. La respuesta debe incluir documentId, orderNumber y paymentStatus pending.

  2. Iniciar pago Flow

    Llamar a POST /storefront-api/orders/:documentId/payments/flow. La respuesta debe incluir checkoutUrl del ambiente esperado.

  3. Validar reutilización

    Repetir la llamada sin cambiar configuración. Debe reutilizar el checkout pendiente compatible.

  4. Validar cambio de configuración

    Cambiar sandbox a producción o modificar el método configurado y reintentar. Debe crear un checkout nuevo compatible con el snapshot actual.

  5. Completar pago

    Pagar en Flow y confirmar que Strapi actualiza paymentStatus paid, registra evento y redirige al host correcto.

  6. Revisar Backoffice

    Confirmar que el pedido aparece pagado, pero el estado operativo sigue disponible para preparación manual.

Riesgos y decisiones abiertas

  • Localhost no sirve para validar webhooks servidor-servidor desde Flow; se necesita túnel público.
  • Si un usuario cambia de navegador al volver desde Flow, la store puede no tener el pedido en localStorage.
  • Si se crea una nueva intención Flow para la misma orden, webhooks tardíos de tokens anteriores podrían requerir búsqueda por metadata además de paymentReference.
  • En producción hay que monitorear errores de Flow y registrar paymentEvents para trazabilidad.
  • El cambio de ambiente o credenciales debe probarse con una orden nueva y con una orden pendiente existente.

Recursos relacionados

¿Te fue útil este contenido?

Tu feedback nos ayuda a mejorar la documentación de Neges.

Soporte humano

¿No encuentras lo que buscas?

Conversa con nuestro equipo de soporte en español. Respondemos por WhatsApp, correo o ticket en menos de 24 horas hábiles.

soporte@neges.clLun a Vie · 9 a 18 hrs
+56 9 0000 0000WhatsApp Business