Mercado Pago plugin for Better Auth - Simple payments, subscriptions and split payments
npm install better-auth-mercadopago
Mercado Pago plugin for Better Auth
Simple payments, subscriptions and split payments integration for your Better Auth application
---
- What is this?
- Features
- Installation
- Environment Variables
- Server Configuration
- Client Configuration
- Database Schema Generation
- Usage Examples
- API Reference
- Error Handling
- Roadmap
- Contributing
- License
---
better-auth-mercadopago is a plugin that seamlessly integrates Mercado Pago payments into your Better Auth authentication system. It provides a type-safe API for handling payments, subscriptions, and webhooks, all within the Better Auth ecosystem.
---
| Feature | Description |
|---------|-------------|
| One-time payments | Create payment preferences with automatic checkout URLs |
| Webhook handling | Secure webhook processing with signature verification |
| Type-safe API | Full TypeScript support for both client and server |
| Prisma integration | Automatic database schema generation via Better Auth CLI |
| Security features | Rate limiting, idempotency keys, webhook signature verification |
| Payment validation | Amount verification to prevent tampering |
---
``bash`
npm install better-auth-mercadopago
Or using pnpm:
`bash`
pnpm add better-auth-mercadopago
Or using yarn:
`bash`
yarn add better-auth-mercadopago
---
| Variable | Required | Description |
|----------|----------|-------------|
| MP_ACCESS_TOKEN | Yes | Your Mercado Pago access token |MP_WEBHOOK_SECRET
| | No (recommended) | Secret for webhook signature verification |NEXT_PUBLIC_APP_URL
| | No | Public app URL (for Next.js) |APP_URL
| | No | Base URL for redirects and webhooks |
Example .env file:
`envRequired
MP_ACCESS_TOKEN=your_mercado_pago_access_token
---
Server Configuration
Create or update your
auth.ts file:`typescript
import { betterAuth } from "better-auth";
import { prismaAdapter } from "better-auth/adapters/prisma";
import { mercadoPagoPlugin } from "better-auth-mercadopago";
import { prisma } from "./prisma";const env = process.env;
export const auth = betterAuth({
database: prismaAdapter(prisma, { provider: "postgresql" }),
plugins: [
mercadoPagoPlugin({
accessToken: env.MP_ACCESS_TOKEN!,
baseUrl: env.APP_URL || "http://localhost:3000",
webhookSecret: env.MP_WEBHOOK_SECRET, // Optional but recommended
// Optional callbacks
onPaymentUpdate: async ({ payment, status, mpPayment }) => {
console.log(
Payment ${payment.id} updated to ${status});
// Send email, update user status, etc.
},
}),
],
});
`---
Client Configuration
Create or update your
auth-client.ts file:`typescript
import { createAuthClient } from "better-auth/react";
import { mercadoPagoClientPlugin } from "better-auth-mercadopago";const env = process.env;
export const authClient = createAuthClient({
baseURL: env.NEXT_PUBLIC_APP_URL,
plugins: [mercadoPagoClientPlugin()],
});
export const { signIn, signUp, signOut, useSession, mercadoPago } = authClient;
`---
Database Schema Generation
After configuring the plugin, generate the Prisma schema:
`bash
pnpm dlx @better-auth/cli@latest generate
`This creates the necessary database tables for the plugin to function.
$3
The plugin defines the following table:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
|
id | string | Yes | Internal UUID |
| externalReference | string | Yes | Unique reference for MP |
| userId | string | Yes | Link to auth user |
| mercadoPagoPaymentId | string | No | MP's payment ID |
| preferenceId | string | Yes | MP's preference ID |
| status | string | Yes | pending, approved, rejected, etc. |
| statusDetail | string | No | Detailed status |
| amount | number | Yes | Payment amount |
| currency | string | Yes | Currency code (ARS, USD, etc.) |
| paymentMethodId | string | No | visa, master, pix, etc. |
| paymentTypeId | string | No | credit_card, debit_card, etc. |
| metadata | string | No | JSON stringified metadata |
| createdAt | date | Yes | Creation timestamp |
| updatedAt | date | Yes | Last update timestamp |---
Usage Examples
$3
`typescript
import { authClient } from "./auth-client";async function createPayment() {
const { data, error } = await authClient.mercadoPago.createPayment({
items: [
{
id: "prod_123",
title: "Premium Plan",
quantity: 1,
unitPrice: 99.99,
currencyId: "ARS",
},
],
back_urls: {
success: "https://yourdomain.com/payments/success",
failure: "https://yourdomain.com/payments/failure",
pending: "https://yourdomain.com/payments/pending",
},
metadata: {
orderId: "order_456",
customerNote: "Please gift wrap",
},
});
if (error) {
console.error("Payment creation failed:", error);
return;
}
// Redirect to Mercado Pago checkout
window.location.href = data.checkoutUrl;
}
`$3
The plugin automatically handles webhooks at
/api/auth/mercado-pago/webhook. Configure this URL in your Mercado Pago Dashboard.`typescript
// The plugin handles this automatically, but you can add custom logic:
mercadoPagoPlugin({
// ... config
onPaymentUpdate: async ({ payment, status, mpPayment }) => {
if (status === "approved") {
// Grant access, send confirmation email, etc.
await grantUserAccess(payment.userId);
await sendConfirmationEmail(payment.userId);
}
},
});
`---
API Reference
$3
| Method | Description | Parameters |
|--------|-------------|------------|
|
mercadoPago.createPayment(params) | Creates a payment preference and returns checkout URL | CreatePaymentParams |$3
| Option | Type | Required | Description |
|--------|------|----------|-------------|
|
accessToken | string | Yes | Your Mercado Pago access token |
| baseUrl | string | Yes | Base URL for redirects and webhooks |
| webhookSecret | string | No | Secret for webhook signature verification |
| onPaymentUpdate | function | No | Callback when payment status changes |
| onSubscriptionUpdate | function | No | Callback when subscription status changes |
| onSubscriptionPayment | function | No | Callback when subscription payment is processed |$3
#### CreatePaymentParams
`typescript
interface CreatePaymentParams {
items: PaymentItem[];
metadata?: Record;
back_urls?: {
success?: string;
failure?: string;
pending?: string;
};
idempotencyKey?: string;
}
`#### PaymentItem
`typescript
interface PaymentItem {
id: string;
title: string;
quantity: number;
unitPrice: number;
currencyId?: string;
}
`#### CreatePaymentResponse
`typescript
interface CreatePaymentResponse {
checkoutUrl: string;
preferenceId: string;
payment: MercadoPagoPaymentRecord;
}
`---
Error Handling
The plugin uses Better Auth's error handling. Common errors:
`typescript
import { authClient } from "./auth-client";const { data, error } = await authClient.mercadoPago.createPayment({
items: [...],
});
if (error) {
switch (error.status) {
case 401:
// User not authenticated
break;
case 429:
// Rate limit exceeded (too many payment attempts)
break;
case 400:
// Invalid parameters
console.error(error.message);
break;
}
}
`$3
| Code | Description |
|------|-------------|
|
UNAUTHORIZED | User is not authenticated |
| TOO_MANY_REQUESTS | Rate limit exceeded |
| BAD_REQUEST | Invalid parameters or validation failed |
| INTERNAL_SERVER_ERROR` | Server error occurred |---
- [x] One-time payments
- [x] Webhook handling with signature verification
- [x] Rate limiting and security features
- [ ] Subscriptions (preapproval plans)
- [ ] Split payments / Marketplace
- [ ] OAuth for seller account connections
- [ ] Advanced webhook configurations
- [ ] Payment refunds
---
Please read CONTRIBUTING.md for details on our code of conduct and development process.
---
MIT © IvanTsxx