# MPP payments

Use MPP for machine-to-machine payments.

Find the app’s [complete source code](https://github.com/stripe-samples/machine-payments) on GitHub.

[MPP, the Machine Payments Protocol](https://mpp.dev), is a protocol for internet payments. When a client requests a paid resource, your server returns an HTTP `402` response with payment details. The client authorizes the payment, retries the request, pays, and gets access to the paid resource along with a receipt.

MPP supports two payment methods:

- **Fiat payments**: Card, wallet, and other payment methods that [shared payment tokens (SPTs)](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md) support. Available to businesses with a US or Canada legal entity.
- **Crypto payments**: Direct on-chain payment that uses crypto deposit addresses. Available to businesses with physical locations in all states, except New York, and in more than 30 countries.

## Before you begin

> Stablecoin payments are available to businesses in all US states, except New York. For businesses operating outside of the US, email [machine-payments@stripe.com](mailto:machine-payments@stripe.com) with your Stripe account ID to request access to stablecoin payments in more than 30 countries.

To start accepting stablecoin payments:

1. Make sure you’ve [set up your Stripe account](https://dashboard.stripe.com/register).
2. Go to your [Payment methods](https://dashboard.stripe.com/settings/payment_methods) settings in the Dashboard and request the **Stablecoins and Crypto** payment method. If you want to accept stablecoin or crypto payments only for [machine payments](https://docs.stripe.com/payments/machine.md), create a separate [payment method configuration](https://docs.stripe.com/payments/payment-method-configurations.md) dedicated to machine payments.
3. Stripe reviews your access request and contacts you for more details if necessary. The payment method appears as **Pending** while we review your request.
4. After we approve your request, the **Stablecoins and Crypto** payment method becomes active in the Dashboard.

To accept fiat payments with SPTs:

1. [Create a Stripe profile](https://docs.stripe.com/get-started/account/profile.md) in the Stripe Dashboard.
2. Store your profile’s `profile_` ID. You use this value as the `networkId` in the following SPT configuration. A profile ID identifies a business on the Stripe network and is required for your server integration.

## Payment lifecycle

In this guide, you build the server. Your server indicates that payment is required and returns the content after successful payment.

#### Crypto
A diagram showing the MPP crypto payment flow between client, server, and Stripe (See full diagram at https://docs.stripe.com/payments/machine/mpp)
You create a deposit address once, and record each on-chain payment as a [PaymentIntent](https://docs.stripe.com/api/payment_intents.md) using `transaction_verification` mode after funds settle on-chain.

#### SPT
A diagram showing the MPP SPT payment flow between client, server, and Stripe (See full diagram at https://docs.stripe.com/payments/machine/mpp)
With [shared payment token payments (SPTs)](https://docs.stripe.com/agentic-commerce/concepts/shared-payment-tokens.md), the client creates an SPT, and the server creates a `PaymentIntent` with the token. Settlement completes through Stripe’s payment rails.

## Use a coding agent

You can build an API that uses MPP with a single prompt to your coding agent:

```bash
Read https://docs.stripe.com/payments/machine/mpp.md?lang=node, and monetize my API using MPP to charge for access using Stripe SPTs for fiat and the Tempo network for crypto. Run `npx mppx@latest validate http://localhost:$PORT` to iteratively validate the implementation as you develop.
```

You can also follow the step-by-step guide below.

## Create a Stripe deposit address

Before you configure your server, create a crypto deposit address. This is the on-chain address where Tempo payments are sent.

```bash
curl https://api.stripe.com/v1/crypto/deposit_addresses \
  -u "$STRIPE_SECRET_KEY:" \
  -H "Stripe-Version: 2026-05-27.preview" \
  -d network=tempo
```

Store the returned address as your `TEMPO_DEPOSIT_ADDRESS` environment variable.

You can create deposit addresses as often as you want, but we recommend that you keep these calls off your core request path.

## Install dependencies

Install the required dependencies:

```bash
npm install mppx stripe
```

## Create your endpoint

Configure your server with both payment methods: Tempo, which uses the deposit address from the previous step, and Stripe for cards and Link. Add a single POST `/paid` endpoint that accepts both payment types with `Mppx.compose`. In this example, the endpoint charges 0.01 USD for crypto and 0.50 USD for fiat. When no credential is present, the server returns a `402` with both challenges, and the client selects the payment method it supports.

#### Node.js

```node
import crypto from 'crypto';
import StripeClient from 'stripe';
import { Mppx, stripe } from 'mppx/server';

// Secret used to secure payment challenges
// https://mpp.dev/protocol/challenges#challenge-binding
const mppSecretKey = crypto.createHmac("sha256", process.env.STRIPE_SECRET_KEY!).update("mpp-challenge-signing").digest("base64");

const stripeClient = new StripeClient(process.env.STRIPE_SECRET_KEY!);

const stripeMachinePayments = stripe.create({
  client: stripeClient,
  networkId: process.env.STRIPE_PROFILE_ID!,
  livemode: !process.env.STRIPE_SECRET_KEY!.includes('_test_'),
  // Stripe deposit address from the previous step
  // If omitted, mppx fetches an existing deposit address or creates a new one.
  depositAddresses: { tempo: process.env.TEMPO_DEPOSIT_ADDRESS! },
});

const mppx = Mppx.create({
  // Returns Tempo and SPT methods today. Future mppx versions may include
  // additional methods Stripe can configure automatically.
  methods: stripeMachinePayments.defaultMethods(),
  secretKey: mppSecretKey,
});

export async function handler(request: Request) {
  const response = await mppx.compose(
    ['tempo/charge', { amount: '0.01' }],
    ['stripe/charge', { amount: '0.50' }],
  )(request);

  if (response.status === 402) return response.challenge;

  return response.withReceipt(Response.json({ data: '...' }));
}
```

### PaymentIntents on Stripe

When you use mppx’s `stripe.create`, successful payments automatically create [PaymentIntents](https://docs.stripe.com/api/payment_intents.md). For SPT payments, mppx creates the `PaymentIntent` when it processes the token. For Tempo payments, mppx records the payment after on-chain settlement by using `transaction_verification` mode.

## Test your endpoint

### Test with mppx validate

Run `mppx validate` to automatically verify your implementation end-to-end. The command tests discovery, challenge formats, error handling, and the full payment flow.

```bash
npx mppx@latest validate http://localhost:4242
```

We recommend running `validate` against both a sandbox and live mode version of your server. In a sandbox, the CLI automatically completes roundtrip test transactions against your server. In live mode, the CLI can also complete roundtrip transactions with real funds.

### Test manually

You can also test each step individually. First, verify your server returns a `402` with the payment requirements:

#### Crypto

Use the [Tempo CLI](https://tempo.xyz/developers/docs/cli) to send a payment from the command line. If your server uses a live mode deposit address, this command moves real funds.

```bash
curl -fsSL https://tempo.xyz/install | bash
tempo wallet login
tempo wallet fund
tempo request -X POST --json '{}' http://localhost:4242/paid
```

After a successful payment, the server returns the content. In the [Dashboard](https://dashboard.stripe.com), go to **Payments** to see the transaction.

#### SPT

> Stripe requires a minimum 0.50 USD charge (or the equivalent amount) for card payments made with SPT.

Use the [link-cli](https://link.com/agents) to issue a test SPT for your account. The `link-cli` is a tool that can provision one-time shared payment token credentials using your Link account. Follow the instructions at [link.com/agents](https://link.com/agents) to install the `link-cli` skills or register it as an MCP server in your preferred agent.

To test with the `link-cli` manually, directly invoke its commands:

```bash
npx @stripe/link-cli auth login
```

```bash
npx @stripe/link-cli mpp pay http://localhost:4242/paid \
  -X POST \
  -d '{}' \
  --context "Testing machine payments integration on Stripe MPP using the link-cli on http://localhost:4242/paid"
```

In the [Dashboard](https://dashboard.stripe.com), go to **Payments** to see the transaction.

### Test with a Stripe sandbox

To test in a sandbox:

1. Configure your server to use your sandbox Stripe API key.
2. Create a Stripe profile for your sandbox and use the `profile_test_` ID.
3. Create a Tempo deposit address in your sandbox account:

```bash
curl https://api.stripe.com/v1/crypto/deposit_addresses \
  -u "$STRIPE_SECRET_KEY:" \
  -H "Stripe-Version: 2026-05-27.preview" \
  -d network=tempo
```

Store the returned address as your `TEMPO_DEPOSIT_ADDRESS` environment variable. The configuration above detects your sandbox API key and sets `livemode` to `false`. mppx’s `stripe.create` automatically configures Tempo testnet.
