mercadopago-subscriptions
SKILL.md
MercadoPago Subscriptions
Architecture overview
Frontend (React + Vite) Edge Functions (Deno) MercadoPago API
───────────────────────── ───────────────────── ──────────────
CardForm (Secure Fields) → mp-create-subscription → POST /preapproval
↓ card token mp-manage-subscription → PUT /preapproval/{id}
SubscriptionPage / Settings → mp-get-subscription-status → GET /preapproval/{id}
webhook-mercadopago ← Webhook notifications
cron-check-subscriptions → GET /preapproval/{id}
Key principle: Frontend only tokenizes cards (Secure Fields). All MercadoPago API calls happen server-side in Supabase Edge Functions.
Subscription lifecycle
| Action | Edge Function | MP API | DB Effect |
|---|---|---|---|
| Create | mp-create-subscription |
POST /preapproval (status=authorized) |
Insert subscription, update company |
| Cancel | mp-manage-subscription (action=cancel) |
PUT /preapproval/{id} (status=cancelled) |
Set cancelled, keep access until period end |
| Change plan | mp-manage-subscription (action=change_plan) |
PUT /preapproval/{id} (transaction_amount) |
Update plan_key, amount |
| Change card | mp-manage-subscription (action=change_card) |
PUT /preapproval/{id} (card_token_id) |
No DB card storage (MP stores it) |
| Pause | mp-manage-subscription (action=pause) |
PUT /preapproval/{id} (status=paused) |
Set suspended |
| Reactivate | mp-manage-subscription (action=reactivate) |
PUT /preapproval/{id} (status=authorized) |
Set active |
Quick reference
Creating a subscription (happy path)
Frontend: Generate card token via Secure Fields → call edge function.
// 1. Tokenize card (CardForm component)
const tokenResponse = await mp.fields.createCardToken({
cardholderName, identificationType, identificationNumber
});
// 2. Call edge function
const result = await api.mpCreateSubscription({
planKey: 'basic',
companyId,
cardTokenId: tokenResponse.id,
payerEmail: email
});
Edge function: Create preapproval with status: 'authorized' (triggers immediate charge).
const preapproval = await mpFetch<MpPreapproval>(
`${mpConfig.apiBase}/preapproval`,
{
method: 'POST',
headers: getMpHeaders({ 'X-Idempotency-Key': `mp-sub-${companyId}-${planKey}-${Date.now()}` }),
body: JSON.stringify({
preapproval_plan_id: mpPlanId,
payer_email: payerEmail,
card_token_id: cardTokenId,
auto_recurring: {
frequency: 1, frequency_type: 'months',
transaction_amount: planMeta.amount,
currency_id: 'ARS'
},
status: 'authorized',
back_url: `${Deno.env.get('APP_URL')}/settings`
}),
}
);
Managing a subscription
All management goes through a single mp-manage-subscription edge function dispatching on action:
await api.mpManageSubscription({
action: 'cancel', // or 'change_plan' | 'change_card' | 'pause' | 'reactivate'
mpPreapprovalId: subscription.mpPreapprovalId,
newPlanKey: 'premium', // only for change_plan
cardTokenId: token, // only for change_card
reason: 'User requested', // optional
});
Detailed references
- Frontend patterns (CardForm, hooks, API service): See FRONTEND.md
- Edge function patterns (create, manage, status, CRON): See EDGE_FUNCTIONS.md
- Webhook handling (signature validation, event processing): See WEBHOOK.md
- Type definitions & DB schema: See TYPES.md
- Email notifications: See EMAIL_TEMPLATES.md
Environment variables
Frontend (.env)
VITE_MP_PUBLIC_KEY=<mercadopago-public-key>
Edge Functions (Supabase Secrets)
MP_MODE=sandbox|production
MP_ACCESS_TOKEN=<mercadopago-access-token>
MP_WEBHOOK_SECRET=<webhook-signing-secret>
MP_PLAN_ID_BASIC=<preapproval-plan-id>
MP_PLAN_ID_STANDARD=<preapproval-plan-id>
MP_PLAN_ID_PREMIUM=<preapproval-plan-id>
RESEND_API_KEY=<for-email-notifications>
Plans configuration
Plans are defined in supabase/functions/_shared/mp-plans.ts:
const MP_PLAN_METADATA = {
basic: { name: 'Básico', amount: 25000, features: [...] },
standard: { name: 'Estándar', amount: 49000, features: [...] },
premium: { name: 'Premium', amount: 89000, features: [...] },
};
Each plan has a corresponding MercadoPago preapproval plan ID stored in env vars (MP_PLAN_ID_BASIC, etc.). These plans are created once in the MP dashboard and referenced by ID.
Critical rules
- Never store raw card data. Use MercadoPago Secure Fields for tokenization only.
- Always use
status: 'authorized'when creating subscriptions (triggers immediate charge). - Always send
X-Idempotency-Keyon MP API calls to prevent duplicate operations. - Webhooks must return 200 within 22 seconds — MP retries on failure.
- Webhook signature validation is mandatory — use HMAC-SHA256 with
MP_WEBHOOK_SECRET. - Grace period: Cancelled subscriptions keep access until
current_period_end. - Use
mpFetchwrapper for all MP API calls — handles retries (3x for 5xx/429) with exponential backoff. - Use admin Supabase client (service role) for cross-user DB updates in edge functions.
Weekly Installs
11
Repository
duvesalo/appFirst Seen
14 days ago
Security Audits
Installed on
opencode11
gemini-cli11
github-copilot11
codex11
amp11
cline11