@dariomvg/create
mercadopagosuscripcionespreapprovalwebhooksintegracion

Mercado Pago — Módulo de Suscripciones

Módulo completo para manejar pagos recurrentes a través de Mercado Pago (PreApproval) en un proyecto de Next.js App Router. Está separado del módulo de pagos únicos: no comparte código ni webhook.

Este módulo asume que ya existe un PreApprovalPlan (creado en el dashboard de Mercado Pago o en otro lado). Solo crea y gestiona instancias individuales de suscripción contra ese plan: no gestiona un catálogo de planes.

Dependencia

  • mercadopago (v2) — el mismo SDK oficial que usa el módulo de pagos únicos. Una excepción: obtener los pagos autorizados llama directamente a la API REST, ya que el SDK todavía no expone ese sub-recurso.

Estructura de archivos

lib/mercadopago-subscriptions/
  service.ts   Direct Mercado Pago API calls (PreApproval SDK + two raw REST
               calls for authorized payments). Internal only — don't import
               this from components.
  actions.ts   Server-side functions ready to import into server components
               (or call as Server Actions from client components).
  types.ts     Shared TypeScript types for subscriptions, recurring charges,
               and webhook payloads.
  client.ts    The one client-side helper this module needs: redirecting
               the browser to the subscription authorization page.

app/api/webhooks/mercadopago-subscriptions/route.ts
  Receives and validates subscription lifecycle and recurring-charge
  notifications.

.env.local
  Environment variables (see below).

Variables de entorno

VariableDónde encontrarla
MERCADOPAGO_ACCESS_TOKENDeveloper Dashboard → Your application → Production/Test credentials → Access Token (el mismo que usa el módulo de pagos únicos)
MERCADOPAGO_SUBSCRIPTIONS_WEBHOOK_SECRETDeveloper Dashboard → Your application → Webhooks → Signature secret — configurá una URL de webhook separada para este módulo y usá el secret que aparece ahí
NEXT_PUBLIC_APP_URLLa URL base pública de tu propia app

Cómo funciona el flujo

  1. Crear una suscripción — llamá a createSubscription de actions.ts con el preapprovalPlanId, el email del pagador y un backUrl. Devuelve initPoint.
  2. Redirigir al pagador — desde un client component, pasale esa URL a redirectToSubscriptionCheckout en client.ts.
  3. El pagador autoriza la suscripción en la página alojada por Mercado Pago y es redirigido de vuelta a tu backUrl.
  4. Mercado Pago cobra automáticamente en cada ciclo de facturación, y notifica a tu webhook tanto los cambios del ciclo de vida como cada cobro individual.
  5. Leés el estado a demanda con getSubscription / getSubscriptionStatus, o derivás getRenewalInfo / getExpirationInfo cuando necesitás mostrárselo a un usuario.

Notas de nomenclatura y comportamiento (específicas de Mercado Pago)

  • El recurso se llama PreApproval, no "Subscription": ese es el término propio de Mercado Pago para una autorización recurrente.
  • Cancel / Pause / Resume son el mismo endpoint por debajo, solo con un valor de status distinto (cancelled / paused / authorized). La cancelación es terminal: una suscripción cancelada no se puede reanudar.
  • Upgrade, downgrade, change plan y change quantity se exponen todos como una única función, changeSubscriptionAmount. Mercado Pago no permite cambiar el preapproval_plan_id de una suscripción después de crearla: lo único que se puede actualizar en una suscripción activa es su transaction_amount recurrente. Que un cambio de monto cuente como upgrade o downgrade depende por completo de tu propia UI/lógica.
  • El Trial (freeTrial) solo se puede definir al crear la suscripción: no hay un endpoint para agregar o quitar un trial después.
  • Renewal no es un campo que Mercado Pago exponga directamente. getRenewalInfo lo deriva del último pago autorizado procesado de la suscripción más su frecuencia de facturación: estimatedNextPaymentDate es un cálculo que hacemos nosotros, no algo que Mercado Pago garantice.
  • Expiration solo aplica si el plan tiene un auto_recurring.end_date definido. Si no lo tiene, una suscripción solo se detiene por cancelación: getExpirationInfo siempre va a informar expired: false en ese caso.

Configuración del webhook

  1. En el Developer Dashboard, andá a tu application → Webhooks.
  2. Agregá una URL de notificación: https://yourdomain.com/api/webhooks/mercadopago-subscriptions (una URL distinta a la que usa el módulo de pagos únicos).
  3. Suscribite a ambos topics: subscription_preapproval y subscription_authorized_payment.
  4. Copiá el signature secret que aparece ahí en MERCADOPAGO_SUBSCRIPTIONS_WEBHOOK_SECRET.

El route handler valida x-signature en cada request y luego ramifica según type:

  • preapproval → obtiene la suscripción y es donde sincronizarías tus propios registros con su estado del ciclo de vida.
  • subscription_authorized_payment → obtiene ese cobro específico (su data.id es el id del pago, no el de la suscripción) y es donde registrarías una renovación o reaccionarías a un cobro fallido/reintentado.

Completá tu propia lógica dentro de los bloques comentados en app/api/webhooks/mercadopago-subscriptions/route.ts.

Manejo de errores

Cada función de service.ts y actions.ts devuelve un objeto de resultado en lugar de lanzar errores:

{ success: true, data: T } | { success: false, error: string, code?: string }

Verificá siempre result.success antes de usar result.data.