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
| Variable | Dónde encontrarla |
|---|---|
MERCADOPAGO_ACCESS_TOKEN | Developer Dashboard → Your application → Production/Test credentials → Access Token (el mismo que usa el módulo de pagos únicos) |
MERCADOPAGO_SUBSCRIPTIONS_WEBHOOK_SECRET | Developer 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_URL | La URL base pública de tu propia app |
Cómo funciona el flujo
- Crear una suscripción — llamá a
createSubscriptiondeactions.tscon elpreapprovalPlanId, el email del pagador y unbackUrl. DevuelveinitPoint. - Redirigir al pagador — desde un client component, pasale esa URL a
redirectToSubscriptionCheckoutenclient.ts. - El pagador autoriza la suscripción en la página alojada por Mercado Pago y
es redirigido de vuelta a tu
backUrl. - 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.
- Leés el estado a demanda con
getSubscription/getSubscriptionStatus, o derivásgetRenewalInfo/getExpirationInfocuando 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
statusdistinto (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 elpreapproval_plan_idde una suscripción después de crearla: lo único que se puede actualizar en una suscripción activa es sutransaction_amountrecurrente. 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.
getRenewalInfolo deriva del último pago autorizado procesado de la suscripción más su frecuencia de facturación:estimatedNextPaymentDatees un cálculo que hacemos nosotros, no algo que Mercado Pago garantice. - Expiration solo aplica si el plan tiene un
auto_recurring.end_datedefinido. Si no lo tiene, una suscripción solo se detiene por cancelación:getExpirationInfosiempre va a informarexpired: falseen ese caso.
Configuración del webhook
- En el Developer Dashboard, andá a tu application → Webhooks.
- 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). - Suscribite a ambos topics:
subscription_preapprovalysubscription_authorized_payment. - 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 (sudata.ides 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.