2026-01-08
Par Ana Olivia Todesco
PagosStripeMercado PagoLaravelSaaSMultitenancy

Cómo integrar Stripe y Mercado Pago en un sistema multitenancy

Cómo integrar Stripe y Mercado Pago en un sistema multitenancy

Integrar pagos en una aplicación web es una de esas tareas que parece sencilla hasta que te metés de lleno. Un botón de pago en una landing page es una cosa. Un sistema de facturación en un SaaS multi-tenant con dos pasarelas de pago distintas — una para USA, otra para Latinoamérica — es otra completamente diferente.

En Nebula lo hemos construido en proyectos reales. Acá explicamos el modelo que usamos y los problemas que aprendimos a evitar.


El escenario: un SaaS que vende en USA y Latinoamérica

El caso más común que encontramos: un SaaS con clientes en Estados Unidos (pagan con tarjeta vía Stripe) y clientes en Argentina, México o Brasil (pagan con Mercado Pago). El sistema tiene que manejar ambos flujos sin que el usuario sienta la diferencia.

La complejidad real aparece cuando sumás multi-tenancy: cada empresa cliente del SaaS puede tener sus propias suscripciones, sus propios ciclos de facturación y, potencialmente, sus propias configuraciones de pago.


El error más común: lógica de pago mezclada con lógica de negocio

El primer error que vemos en sistemas que crecieron sin planificación: la lógica de pago está mezclada con la lógica de negocio. Un controlador que llama directamente a la API de Stripe, sin ninguna capa intermedia.

Eso funciona cuando solo tenés una pasarela. Cuando querés agregar una segunda, tenés que reescribir o duplicar código en múltiples lugares — y rezar para no olvidarte de ninguno.


La solución: una capa de abstracción de pagos

La solución es crear una capa de abstracción propia: una interfaz de pago del sistema que luego se conecta con Stripe o Mercado Pago según corresponda. El resto del sistema solo conoce esa interfaz, no la pasarela específica.

En Laravel, esto se implementa como clases que responden a una interfaz común. El sistema llama a processPayment() y la implementación concreta decide si el request va a Stripe o a Mercado Pago según la configuración del tenant.

Cambiar de pasarela, agregar una tercera, o modificar el comportamiento de una sola pasa a ser un cambio localizado en la implementación correspondiente, sin tocar el resto del sistema.


¿Cómo decide el sistema qué pasarela usar?

Generalmente por combinación de factores:

  • **Moneda del plan**: USD va a Stripe, ARS/BRL/MXN va a Mercado Pago
  • **País del cliente**: detectado durante el registro o configurado explícitamente
  • **Preferencia del tenant**: en SaaS multi-tenant, cada organización puede tener configurada su pasarela preferida
  • Esta lógica vive en la capa de abstracción, no dispersa por el código.


    El modelo de datos para multi-tenancy con pagos

    Las tablas mínimas que necesitás:

    TablaPara qué sirve
    tenantsCada empresa cliente del SaaS
    subscriptionsSuscripción activa por tenant (plan, ciclo, estado)
    payment_methodsMétodos de pago guardados por tenant
    invoicesHistorial de facturación
    payment_gateway_configsConfiguración de pasarela por tenant

    Cada suscripción referencia un external_id en la pasarela correspondiente. Ese ID es lo que usás para gestionar renovaciones, cancelaciones y cambios de plan desde el sistema.


    Los webhooks: el núcleo que no podés ignorar

    Ni Stripe ni Mercado Pago funcionan bien sin webhooks. Los pagos asíncronos, las renovaciones automáticas y los eventos de disputa o fallo se notifican via webhook. Si no los procesás correctamente, tu sistema tiene estados inconsistentes — suscripciones que parecen activas pero fallaron, pagos que se procesaron pero no se registraron.

    Los errores más comunes:

    No verificar la firma del webhook. Stripe y Mercado Pago incluyen una firma en cada request que demuestra que viene de ellos. Verificarla es lo primero que hay que hacer. Si no lo hacés, cualquiera puede enviar requests falsos a tu endpoint.

    Procesar el mismo evento dos veces. Los webhooks pueden llegar repetidos. Hay que guardar el ID de cada evento procesado y verificar si ya fue procesado antes de actuar.

    Bloquear el procesamiento con lógica pesada. El endpoint de webhook debe responder 200 OK inmediatamente y delegar el procesamiento real a una queue. Si tarda más de unos segundos, la pasarela va a reintentar el envío y vas a procesar el mismo evento múltiples veces.


    Renovaciones y ciclos de facturación

    Stripe maneja renovaciones automáticamente si usás sus suscripciones. Mercado Pago tiene soporte para pagos recurrentes con más variaciones según el país.

    En sistemas donde queremos control total sobre el ciclo, implementamos la lógica de renovación directamente en Laravel: un scheduled job que revisa cada día las suscripciones próximas a vencer y dispara el cobro en la pasarela configurada para ese tenant.

    Esto da más control y permite personalizar el comportamiento: períodos de gracia, notificaciones previas al vencimiento, downgrade automático por falta de pago, y reintentos con intervalo configurable.


    Un aprendizaje de proyectos reales

    En MyOfficeTaxes, la integración de Stripe y Square (no Mercado Pago, pero el mismo concepto) fue uno de los módulos que más tiempo de diseño requirió antes de escribir una línea de código. Ese tiempo de diseño fue la mejor inversión del proyecto.

    Cuando el cliente quiso agregar un nuevo plan con facturación diferente, tomó horas — no semanas — porque la arquitectura ya lo contemplaba.


    ¿Estás construyendo un SaaS con pagos o necesitás integrar una pasarela?

    La integración de pagos es uno de los puntos donde más se acumula deuda técnica cuando no se diseña bien desde el inicio. Hacerlo bien ahorra muchos problemas cuando el negocio escala.

    Si tenés dudas sobre cómo estructurar el sistema de pagos de tu proyecto, agendá un diagnóstico. Te damos un análisis concreto de qué necesita tu caso específico.

    PagosStripeMercado PagoLaravelSaaSMultitenancy
    Cómo integrar Stripe y Mercado Pago en un sistema multitenancy | Nebula Solutions | Nebula Solutions