Mercado Pago
Payment and subscription flows with Mercado Pago
Beztack supports Mercado Pago as a first-class payment provider, including plan sync, subscriptions, checkout preference, direct payment processing, and webhook/event handling.
For an overview of the provider-agnostic payment system, see Payments Core.
When to use Mercado Pago
Use Mercado Pago when you need:
- Native Mercado Pago plans/subscriptions
- Direct card payment processing
- Mercado Pago webhook-driven state updates
- Real-time payment events for frontend UX
See also: Polar
Required environment variables
API (apps/api/.env)
MERCADO_PAGO_ACCESS_TOKEN=APP_USR-...
MERCADO_PAGO_APPLICATION_ID=123456789
MERCADO_PAGO_WEBHOOK_SECRET=... # optional but recommended
MERCADO_PAGO_INTEGRATOR_ID=... # optional
PAYMENT_PROVIDER=mercadopago
APP_URL=http://localhost:3000
DEFAULT_CURRENCY=UYU # your project's currency, e.g. the Mercado Pago site's
DEFAULT_LOCALE=es-UYDEFAULT_CURRENCY and DEFAULT_LOCALE are required for every project (the
create CLI asks for them). Mercado Pago plans are created in the price's own
currency; DEFAULT_CURRENCY only fills in when a price carries none.
MERCADO_PAGO_APPLICATION_ID is required because it is the Mercado Pago-native
Payment integration boundary. Beztack uses it to prevent plans,
subscriptions, webhooks, and Membership cache from one Mercado Pago Application
from being visible or manageable through another Mercado Pago Application.
Do not confuse it with MERCADO_PAGO_INTEGRATOR_ID: the integrator ID is
optional partner tracking and is not an access-control boundary.
For existing installations, get the Application ID from the Mercado Pago
developer application details or from an existing plan/subscription API
response, then set MERCADO_PAGO_APPLICATION_ID before running Mercado Pago in
Beztack.
UI (apps/ui/.env)
VITE_PAYMENT_PROVIDER=mercadopago
VITE_MERCADO_PAGO_PUBLIC_KEY=APP_USR-...
VITE_API_URL=http://localhost:3000
VITE_DEFAULT_CURRENCY=UYU
VITE_DEFAULT_LOCALE=es-UYImplementation references:
- Env schemas:
packages/env/src/api.ts,packages/env/src/ui.ts - Provider factory:
apps/api/lib/payments/index.ts - React provider wiring:
apps/ui/src/app.tsx
API Routes
Unified routes (shared across all providers)
These routes are provider-agnostic and work with whichever provider is active:
GET /api/subscriptions/products— List products/plans from the active provider.POST /api/subscriptions/checkout— Create a checkout session.GET /api/subscriptions— List subscriptions for the current user.GET /api/subscriptions/:id— Get a specific subscription.PATCH /api/subscriptions/:id— Update a subscription.DELETE /api/subscriptions/:id— Cancel a subscription.POST /api/subscriptions/webhooks— Process webhook payloads (unified handler).
MercadoPago-specific route
POST /api/payments/mercado-pago/webhook— Validate and process MercadoPago-specific webhook payloads.
Admin plan management routes
GET /api/admin/plans— List all plans from the local DB.POST /api/admin/plans— Create a new plan.POST /api/admin/plans/import— Import plans from the provider.POST /api/admin/plans/sync— Sync all plans from the provider into the local DB.GET /api/admin/plans/sync-status— Check the current sync status.PATCH /api/admin/plans/:id— Update a plan.DELETE /api/admin/plans/:id— Delete a plan.
Plan sync flow
Beztack keeps a local plan mirror in the plan table (provider-agnostic, with a
providerPlanId field linking to the remote product ID) to make plan selection
and checkout flows predictable in the app.
GET /api/admin/plansreads local plans.POST /api/admin/plans/syncperforms an explicit admin-triggered sync from the provider.POST /api/admin/plans/importimports plans from the provider into the local DB.GET /api/admin/plans/sync-statusreports the current sync state.
Client integration
In UI, Mercado Pago is enabled by environment flags and wrapped with
MercadoPagoProvider.
<MercadoPagoProvider apiBaseUrl={env.VITE_API_URL} publicKey={mpPublicKey}>
{children}
</MercadoPagoProvider>The package @beztack/mercadopago/react exposes:
- Provider + context
- Hooks (
usePlans,useSyncPlans,useSubscriptions, etc.) - Components for subscriptions, status badges, billing history, and bricks
Testing checklist
- Configure sandbox credentials and
VITE_MERCADO_PAGO_PUBLIC_KEY. - Configure
MERCADO_PAGO_APPLICATION_IDfor the Mercado Pago Application used by this integration. - Validate plan sync via admin routes (
/api/admin/plans/sync) and confirm only plans from that Application are visible. - Test checkout via
POST /api/subscriptions/checkoutand confirm the created subscription belongs to the configured Application. - Sign in with a Mercado Pago payer email that has a subscription in another Application and confirm it is not listed.
- Trigger/receive webhook events and verify mismatched Application events are skipped while matching events update local DB state.
- Verify SSE events in the UI (if using the events endpoint).
Troubleshooting
401/403on plan sync/create: verify admin session.- Mercado Pago fails to start: verify
MERCADO_PAGO_APPLICATION_IDis set and matches the Application tied to the access token. - Plans or subscriptions are missing: confirm they belong to the configured Mercado Pago Application, not just the same Merchant account or payer email.
- Missing webhook updates: verify
MERCADO_PAGO_WEBHOOK_SECRETand public URL. - Provider not active in UI: check
VITE_PAYMENT_PROVIDER=mercadopagoand public key presence. - Wrong API base: confirm
VITE_API_URLpoints to the running API.