@jhrnandez/mp-checkout-wrapper
v1.0.0
Published
Isomorphic Mercado Pago Checkout wrapper for Next.js — decoupled server/client layers
Downloads
220
Maintainers
Readme
@jhrnandez/mp-checkout-wrapper
Isomorphic Mercado Pago Checkout wrapper for Next.js — decoupled server/client layers.
Installation
npm install @jhrnandez/mp-checkout-wrapper mercadopagoExports
| Path | Environment | Contents |
|------|-------------|----------|
| @jhrnandez/mp-checkout-wrapper/server | Server only | PreferenceService, WebhookValidator |
| @jhrnandez/mp-checkout-wrapper/client | Client only | MPProvider, MPCheckout, useMercadoPago |
| @jhrnandez/mp-checkout-wrapper/domain | Any | TypeScript interfaces |
Quick Start
1. Environment variables
NEXT_PUBLIC_MP_KEY=APP_USR-... # Mercado Pago public key
MP_ACCESS_TOKEN=APP_USR-... # Mercado Pago access token
NEXT_PUBLIC_BASE_URL=https://... # Your public URL (for back_urls & webhook)2. Server Action — create a preference
// app/actions/mp.ts
"use server";
import { PreferenceService } from "@jhrnandez/mp-checkout-wrapper/server";
export async function createPreferenceAction() {
const service = new PreferenceService(process.env.MP_ACCESS_TOKEN!);
const preference = await service.create({
items: [
{
title: "My product",
unit_price: 1500,
quantity: 1,
currency_id: "MXN",
},
],
back_urls: {
success: `${process.env.NEXT_PUBLIC_BASE_URL}/payment/success`,
failure: `${process.env.NEXT_PUBLIC_BASE_URL}/payment/failure`,
pending: `${process.env.NEXT_PUBLIC_BASE_URL}/payment/pending`,
},
auto_return: "approved",
notification_url: `${process.env.NEXT_PUBLIC_BASE_URL}/api/webhook`,
});
return preference.preferenceId;
}3. Client Component — checkout button
// app/components/Checkout.tsx
"use client";
import { MPProvider, MPCheckout } from "@jhrnandez/mp-checkout-wrapper/client";
import { createPreferenceAction } from "@/app/actions/mp";
export default function Checkout() {
return (
<MPProvider publicKey={process.env.NEXT_PUBLIC_MP_KEY!}>
<MPCheckout fetchPreferenceId={createPreferenceAction}>
{({ open, loading, error }) => (
<>
<button onClick={open} disabled={loading}>
{loading ? "Loading..." : "Pay with Mercado Pago"}
</button>
{error && <p>{error}</p>}
</>
)}
</MPCheckout>
</MPProvider>
);
}4. Webhook — validate notifications
// app/api/webhook/route.ts
import { NextRequest } from "next/server";
import { WebhookValidator } from "@jhrnandez/mp-checkout-wrapper/server";
export async function POST(request: NextRequest) {
const body = await request.json();
const validator = new WebhookValidator(process.env.MP_ACCESS_TOKEN!);
const result = await validator.validate(body);
if (!result.verified) {
return Response.json({ error: "Unverified" }, { status: 401 });
}
if (result.payment?.status === "approved") {
// Handle approved payment
console.log("Payment approved:", result.payment.external_reference);
}
return Response.json({ received: true });
}API Reference
Server
PreferenceService
const service = new PreferenceService(accessToken: string);
const preference = await service.create(options: ICreatePreferenceOptions);
// Returns: { preferenceId, init_point, sandbox_init_point }WebhookValidator
const validator = new WebhookValidator(accessToken: string);
const result = await validator.validate(body: IWebhookNotification);
// Returns: { verified, payment? }Client
<MPProvider>
Wraps your app to load the Mercado Pago JS SDK.
<MPProvider publicKey="APP_USR-...">
{children}
</MPProvider><MPCheckout>
Render-prop component that handles the checkout redirect.
<MPCheckout fetchPreferenceId={() => Promise<string>}>
{({ open, loading, sdkReady, error }) => (
// your UI
)}
</MPCheckout>useMercadoPago()
Hook to access the SDK instance directly.
const { mp, loading, error } = useMercadoPago();Domain Types
import type {
ICheckoutItem,
IPaymentStatus,
IWebhookNotification,
IWebhookValidationResult,
ICreatePreferenceOptions,
IPreferenceResponse,
IMPConfig,
} from "@jhrnandez/mp-checkout-wrapper/domain";License
MIT
