> ## Documentation Index
> Fetch the complete documentation index at: https://docs.monad.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# MPP Overview

> Send and accept payments on Monad using the Machine Payments Protocol

The [`@monad-crypto/mpp`](https://www.npmjs.com/package/@monad-crypto/mpp) package implements Monad payments for the [Machine Payments Protocol](https://mpp.dev) (MPP). It enables one-time payment processing through ERC-20 token transfers on Monad.

This guide covers the Monad-specific `@monad-crypto/mpp` package. For general MPP concepts, see the [MPPX documentation](https://mpp.sh/docs).

## Installation

Install the package and its peer dependencies:

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install @monad-crypto/mpp mppx viem
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add @monad-crypto/mpp mppx viem
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add @monad-crypto/mpp mppx viem
    ```
  </Tab>

  <Tab title="bun">
    ```bash theme={null}
    bun add @monad-crypto/mpp mppx viem
    ```
  </Tab>
</Tabs>

## Server

The server defines what payment is required and verifies credentials submitted by clients. Import `monad` from the server entrypoint and pass it to `Mppx.create`.

```ts title="server.ts" theme={null}
import { monad } from "@monad-crypto/mpp/server";
import { Mppx } from "mppx";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.SERVER_PRIVATE_KEY as `0x${string}`);

const mppx = Mppx.create({
  methods: [
    monad({
      account,
      recipient: account.address,
    }),
  ],
});
```

### Gate an endpoint

Use `mppx.charge()` as middleware to require payment before serving a response.

```ts title="server.ts" theme={null}
import { Hono } from "hono";

const app = new Hono();

app.get("/premium", mppx.charge(), async (ctx) => {
  return ctx.json({ message: "Premium content" });
});

export default app;
```

When a client requests `/premium` without a valid payment credential, the server responds with a `402 Payment Required` status and a challenge describing the payment requirements. The client then submits a credential (transaction hash or signed authorization) to complete the payment.

### Testnet

By default, the package connects to Monad mainnet (chain ID `143`). To use testnet, set `testnet: true`.

```ts theme={null}
monad({
  account,
  recipient: account.address,
  testnet: true,
})
```

## Client

The client handles wallet interactions and credential creation. Import `monad` from the client entrypoint.

With a local private key, the client defaults to **pull mode** — it signs an ERC-3009 authorization without broadcasting a transaction.

```ts title="client.ts" theme={null}
import { monad } from "@monad-crypto/mpp/client";
import { Mppx } from "mppx/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.CLIENT_PRIVATE_KEY as `0x${string}`);

const mppx = Mppx.create({
  methods: [monad({ account })],
});

// Make a paid request
const response = await fetch("http://localhost:3000/premium");
const data = await response.json();
console.log(data);
```

### Push vs pull mode

|                  | Push                                | Pull                                     |
| ---------------- | ----------------------------------- | ---------------------------------------- |
| **Who pays gas** | Client                              | Server                                   |
| **Transaction**  | Client broadcasts ERC-20 `transfer` | Server calls `transferWithAuthorization` |
| **Credential**   | Transaction hash                    | Signed ERC-3009 authorization            |
| **Default for**  | JSON-RPC accounts (browser wallets) | Local accounts (private keys)            |
| **Trade-off**    | Client needs gas tokens             | Server needs gas tokens                  |

### Overriding the mode

Use the `mode` option to set the payment mode explicitly, regardless of account type.

```ts theme={null}
monad({
  account,
  mode: "push", // Always broadcast a transaction
})

monad({
  account,
  mode: "pull", // Always sign an authorization
})
```

### Monkey patch

The client `Mppx.create()` function [monkey patches](https://en.wikipedia.org/wiki/Monkey_patch) the Web `fetch` API to use the configured payment method whenever it receives a `402 Payment Required` HTTP response.

You can also use `mppx.fetch` directly.

```ts title="client.ts" theme={null}
import { monad } from "@monad-crypto/mpp/client";
import { Mppx } from "mppx/client";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.CLIENT_PRIVATE_KEY as `0x${string}`);

const mppx = Mppx.create({
  methods: [monad({ account })],
  polyfill: false,
});

const response = await mppx.fetch("http://localhost:3000/premium");
const data = await response.json();
console.log(data);
```

## Links

* NPM package: [@monad-crypto/mpp](https://www.npmjs.com/package/@monad-crypto/mpp)
* GitHub repository: [monad-crypto/monad-ts](https://github.com/monad-crypto/monad-ts)
