npm package: @jhrnandez/mp-checkout-wrapper
Description: Isomorphic Mercado Pago Checkout wrapper for Next.js — decoupled server/client layers
Author: jhrnandez
Latest version: 1.0.0

# @jhrnandez/mp-checkout-wrapper

Isomorphic Mercado Pago Checkout wrapper for Next.js — decoupled server/client layers.

## Installation

```bash
npm install @jhrnandez/mp-checkout-wrapper mercadopago
```

## Exports

| 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

```env
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

```ts
// 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

```tsx
// 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

```ts
// 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`

```ts
const service = new PreferenceService(accessToken: string);
const preference = await service.create(options: ICreatePreferenceOptions);
// Returns: { preferenceId, init_point, sandbox_init_point }
```

#### `WebhookValidator`

```ts
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.

```tsx
<MPProvider publicKey="APP_USR-...">
  {children}
</MPProvider>
```

#### `<MPCheckout>`

Render-prop component that handles the checkout redirect.

```tsx
<MPCheckout fetchPreferenceId={() => Promise<string>}>
  {({ open, loading, sdkReady, error }) => (
    // your UI
  )}
</MPCheckout>
```

#### `useMercadoPago()`

Hook to access the SDK instance directly.

```ts
const { mp, loading, error } = useMercadoPago();
```

### Domain Types

```ts
import type {
  ICheckoutItem,
  IPaymentStatus,
  IWebhookNotification,
  IWebhookValidationResult,
  ICreatePreferenceOptions,
  IPreferenceResponse,
  IMPConfig,
} from "@jhrnandez/mp-checkout-wrapper/domain";
```

## License

MIT