Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@ currency: '0x20c0000000000000000000000000000000000000', // pathUSD on Tempo
1. **Alphabetize everything** - Object properties in code examples and ### parameter headings must be alphabetically ordered
13. **Install code-groups must include npm, pnpm, and bun** - Every `:::code-group` with install commands must have all three tabs: `npm`, `pnpm`, and `bun`. Use `npm install`, `pnpm add`, and `bun add` respectively.
12. **No `// @noErrors` in twoslash** - NEVER use `// @noErrors` in twoslash code blocks. All snippets must typecheck against the installed mppx types. If a snippet fails, fix the snippet or bump the mppx version — do not suppress the error.
2. **No code-groups for variants** - Use separate ### sections under ## Usage for different usage patterns (e.g., `### With MCP Transport`), not `:::code-group`
3. **Keep descriptions concise** - One line for the intro, brief explanations for parameters
4. **Show realistic examples** - Use actual values that make sense
5. **Use `// @log:` comments** - Show expected output inline
Expand Down
2 changes: 1 addition & 1 deletion src/components/terminal-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ export const POEM_RESULTS = [
"A stream of data onward drifts.",
"No human hand to slow the pace,",
"Just math and trust in empty space.",
"The escrow holds, the channel clears,",
"The reserve holds, the channel clears,",
"A settlement in milliseconds, not years.",
],
[
Expand Down
2 changes: 1 addition & 1 deletion src/pages/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ function MobileNav() {
rel="noopener noreferrer"
data-mobile-nav-item=""
>
IETF Specs
IETF Specification
</a>
<span data-mobile-nav-label="">GitHub</span>
<div data-mobile-nav-subitems="" data-mobile-nav-flat="">
Expand Down
6 changes: 4 additions & 2 deletions src/pages/advanced/identity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,10 @@ export async function handler(request: Request) {
if (result.status === 402) return result.challenge

const credential = Credential.fromRequest(request)
const pubkey = credential.source // [!code hl]
const jobId = createJob({ owner: pubkey }) // [!code hl]
// [!code hl:start]
const pubkey = credential.source
const jobId = createJob({ owner: pubkey })
// [!code hl:end]

return result.withReceipt(Response.json({ jobId }))
}
Expand Down
2 changes: 1 addition & 1 deletion src/pages/advanced/refunds.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ This gives sessions a **built-in refund mechanism**—unclaimed funds are refund
participant Tempo
Client->>Tempo: Deposit tokens
Tempo-->>Client: Channel created
Client->>Server: Open credential
Client->>Server: Open Credential
Server-->>Client: 200 OK (session established)
loop Per request
Client->>Server: Request + voucher
Expand Down
8 changes: 4 additions & 4 deletions src/pages/advanced/security.mdx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
description: "Protect MPP server secrets and payment credentials. Keep MPP_SECRET_KEY server-side, never log it, and rotate it safely."
description: "Protect MPP server secrets and payment Credentials. Keep MPP_SECRET_KEY server-side, never log it, and rotate it safely."
imageDescription: "Protect MPP server secrets"
---

# Security [Protect server secrets and payment credentials]
# Security [Protect server secrets and payment Credentials]

The core Payment HTTP Authentication Scheme already requires TLS and treats payment Credentials and Receipts as sensitive data. This page covers the operational practices around `MPP_SECRET_KEY` and server deployments.

Expand All @@ -22,15 +22,15 @@ Use your platform's secret store as the system of record—AWS Secrets Manager,

Environment variables are a good delivery mechanism at runtime, but they are not a secrets management strategy by themselves. Inject `MPP_SECRET_KEY` into your process from a managed secret store instead of treating `.env` files or deployment manifests as the source of truth.

## Never log secrets or payment credentials
## Never log secrets or payment Credentials

Do not log:

- `MPP_SECRET_KEY`
- `Authorization: Payment` headers
- `Payment-Receipt` headers

Keep them out of error messages, debugging output, analytics, traces, and support logs. If you need observability, log stable metadata such as request IDs, challenge IDs, status codes, or payment method names instead.
Keep them out of error messages, debugging output, analytics, traces, and support logs. If you need observability, log stable metadata such as request IDs, Challenge IDs, status codes, or payment method names instead.

## Handle proxies and caches safely

Expand Down
4 changes: 2 additions & 2 deletions src/pages/blog/subscriptions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ With subscriptions, the client doesn't sign every paid request, instead authoriz

## How they work

The first request activates the subscription. The server maps the request to a stable subscription key, such as a user and plan, then returns a `402` Challenge with subscription terms. The client signs a credential that authorizes a scoped access key. The server charges the first billing period, stores the subscription record, and returns the protected response with a Receipt.
The first request activates the subscription. The server maps the request to a stable subscription key, such as a user and plan, then returns a `402` Challenge with subscription terms. The client signs a Credential that authorizes a scoped access key. The server charges the first billing period, stores the subscription record, and returns the protected response with a Receipt.

<MermaidDiagram chart={`sequenceDiagram
participant Client
Expand All @@ -50,7 +50,7 @@ The first request activates the subscription. The server maps the request to a s
Server-->>Client: 200 OK + Receipt
`} />

After activation, the server can grant access without asking for another payment credential. It resolves the same subscription key, checks the stored record, validates that the request still matches the subscription terms, and returns a receipt.
After activation, the server can grant access without asking for another payment Credential. It resolves the same subscription key, checks the stored record, validates that the request still matches the subscription terms, and returns a Receipt.

When a billing period ends, the server renews the subscription before granting access. You can renew during the request path, or run renewals automatically via cron or any other scheduled job.

Expand Down
4 changes: 2 additions & 2 deletions src/pages/extensions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ Third-party packages that extend MPP with new payment methods, middleware, and u
| Name | Languages | Description | Link |
|---|---|---|---|
| `@insumermodel/mppx-condition-gate` | TypeScript, JavaScript | Condition-based access for mppx routes—free access for wallets that meet token, NFT, EAS attestation, or Farcaster ID conditions across 33 chains, returned as ECDSA-signed attestations | [npm](https://www.npmjs.com/package/@insumermodel/mppx-condition-gate) · [GitHub](https://github.com/douglasborthwick-crypto/mppx-condition-gate) |
| `mpp-inspector` | TypeScript, JavaScript | CLI toolkit to inspect, debug, and test HTTP 402 MPP endpoints—parse challenges, verify receipts, compare pricing, and dry-run payment flows | [npm](https://www.npmjs.com/package/mpp-inspector) · [GitHub](https://github.com/amgb20/MPP-Inspector) |
| `mpp-inspector` | TypeScript, JavaScript | CLI toolkit to inspect, debug, and test HTTP 402 MPP endpoints—parse Challenges, verify Receipts, compare pricing, and dry-run payment flows | [npm](https://www.npmjs.com/package/mpp-inspector) · [GitHub](https://github.com/amgb20/MPP-Inspector) |
| `x402-proxy` | TypeScript, JavaScript | `curl` for MPP and x402 paid APIs—auto-pays one-shot charges and session-based streaming (per-token voucher cycling), with built-in wallet management (EVM + Solana), spend limits, and MCP stdio proxy for AI agents | [npm](https://www.npmjs.com/package/x402-proxy) · [GitHub](https://github.com/cascade-protocol/x402-proxy) |
| `@quicknode/mpp` | TypeScript, JavaScript | Extends MPP with payments on Ethereum, Base, and other EVM networks, with support for `permit2`, EIP-3009 `authorization` and `hash` credential types | [npm](https://www.npmjs.com/package/@quicknode/mpp) · [GitHub](https://github.com/quiknode-labs/mpp) |
| `@quicknode/mpp` | TypeScript, JavaScript | Extends MPP with payments on Ethereum, Base, and other EVM networks, with support for `permit2`, EIP-3009 `authorization` and `hash` Credential types | [npm](https://www.npmjs.com/package/@quicknode/mpp) · [GitHub](https://github.com/quiknode-labs/mpp) |

Want to build your own? See [Custom payment methods](/payment-methods/custom).
6 changes: 3 additions & 3 deletions src/pages/guides/monetize-mcp-server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Add per-call payments to any [MCP](https://modelcontextprotocol.io) server. When
A->>S: (1) tools/call
S-->>A: (2) {"error":{"code":-32042}} + Challenge
Note over A: (3) Create Credential
A->>S: (4) tools/call + {"_meta":{"credential"}}
A->>S: (4) tools/call + {"_meta":{"Credential"}}
S->>N: (5) Settle payment
N-->>S: (6) Confirmed
S-->>A: (7) {"result":{}} + Receipt
Expand All @@ -36,7 +36,7 @@ Add per-call payments to any [MCP](https://modelcontextprotocol.io) server. When
6. **Network** confirms the payment
7. **Server** returns the tool result with a Receipt in `_meta`

This maps directly to the standard MPP challengecredentialreceipt flow, encoded as JSON-RPC instead of HTTP headers. See the [MCP transport spec](/protocol/transports/mcp) for the full encoding.
This maps directly to the standard MPP ChallengeCredentialReceipt flow, encoded as JSON-RPC instead of HTTP headers. See the [MCP transport spec](/protocol/transports/mcp) for the full encoding.

:::info
This guide uses the MCP transport, so Challenge, Credential, and Receipt data travel as native JSON in `error.data` and `_meta`. The base64url-encoded `request` and `opaque` auth-params apply to the HTTP transport.
Expand Down Expand Up @@ -257,7 +257,7 @@ Under the hood, the MCP transport encodes MPP Challenges, Credentials, and Recei

| MPP concept | MCP encoding |
|---|---|
| Challenge | Error code `-32042` with challenges in `error.data` |
| Challenge | Error code `-32042` with Challenges in `error.data` |
| Credential | `_meta["org.paymentauth/credential"]` on the tool call |
| Receipt | `_meta["org.paymentauth/receipt"]` on the tool result |

Expand Down
8 changes: 4 additions & 4 deletions src/pages/guides/one-time-payments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ $ npx mppx http://localhost:3000/api/photo
<Tab title="Hono">
::::steps

### Install `mppx` and `hono`
## Install `mppx` and `hono`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -257,7 +257,7 @@ $ npx mppx http://localhost:3000/api/photo
<Tab title="Workers">
::::steps

### Install `mppx`
## Install `mppx`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -367,7 +367,7 @@ $ npx mppx http://localhost:8787
<Tab title="Express">
::::steps

### Install `mppx` and `express`
## Install `mppx` and `express`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -485,7 +485,7 @@ This guide walks through using `mppx/server` directly with any [Fetch API](https

::::steps

### Install `mppx`
## Install `mppx`

:::code-group
```bash [npm]
Expand Down
8 changes: 4 additions & 4 deletions src/pages/guides/pay-as-you-go.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ $ npx mppx http://localhost:3000/api/sessions/photo
<Tab title="Hono">
::::steps

### Install `mppx` and `hono`
## Install `mppx` and `hono`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -296,7 +296,7 @@ $ npx mppx http://localhost:3000/api/sessions/photo
<Tab title="Workers">
::::steps

### Install `mppx`
## Install `mppx`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -420,7 +420,7 @@ $ npx mppx http://localhost:8787
<Tab title="Express">
::::steps

### Install `mppx` and `express`
## Install `mppx` and `express`

:::code-group
```bash [npm]
Expand Down Expand Up @@ -555,7 +555,7 @@ This guide walks through using `mppx/server` directly with any [Fetch API](https

::::steps

### Install `mppx`
## Install `mppx`

:::code-group
```bash [npm]
Expand Down
34 changes: 20 additions & 14 deletions src/pages/guides/split-payments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,14 @@ export async function handler(request: Request) {
amount: '1.00',
currency: '0x20c0000000000000000000000000000000000000', // pathUSD
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266', // seller
splits: [ // [!code hl]
{ // [!code hl]
amount: '0.10', // [!code hl]
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform fee // [!code hl]
}, // [!code hl]
], // [!code hl]
// [!code hl:start]
splits: [
{
amount: '0.10',
recipient: '0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform fee
},
],
// [!code hl:end]
})(request)

// seller receives $0.90, platform receives $0.10
Expand Down Expand Up @@ -127,10 +129,12 @@ Mppx.create({
methods: [
tempo.charge({
account: provider.getAccount({ signable: true }),
expectedRecipients: [ // [!code hl]
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform // [!code hl]
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', // referrer // [!code hl]
], // [!code hl]
// [!code hl:start]
expectedRecipients: [
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', // referrer
],
// [!code hl:end]
getClient: provider.getClient,
}),
],
Expand All @@ -150,10 +154,12 @@ Mppx.create({
methods: [
tempo.charge({
account,
expectedRecipients: [ // [!code hl]
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform // [!code hl]
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', // referrer // [!code hl]
], // [!code hl]
// [!code hl:start]
expectedRecipients: [
'0x70997970C51812dc3A010C7d01b50e0d17dc79C8', // platform
'0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC', // referrer
],
// [!code hl:end]
}),
],
})
Expand Down
8 changes: 4 additions & 4 deletions src/pages/guides/streamed-payments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ $ npx mppx http://localhost:3000/api/sessions/poem
<Tab title="Hono">
::::steps

### Install `mppx` and `hono`
## Install `mppx` and `hono`

:::code-group

Expand Down Expand Up @@ -273,7 +273,7 @@ $ npx mppx http://localhost:3000/api/sessions/poem
<Tab title="Workers">
::::steps

### Install `mppx`
## Install `mppx`

:::code-group

Expand Down Expand Up @@ -387,7 +387,7 @@ $ npx mppx http://localhost:8787
<Tab title="Express">
::::steps

### Install `mppx` and `express`
## Install `mppx` and `express`

:::code-group

Expand Down Expand Up @@ -509,7 +509,7 @@ This guide walks through using `mppx/server` directly with any [Fetch API](https

::::steps

### Install `mppx`
## Install `mppx`

:::code-group

Expand Down
2 changes: 1 addition & 1 deletion src/pages/guides/subscription-payments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ export async function cancelSubscription(userId: string) {
}
```

Keep the canceled record instead of deleting it. That preserves receipts and prevents in-flight renewals from clearing the cancellation marker.
Keep the canceled record instead of deleting it. That preserves Receipts and prevents in-flight renewals from clearing the cancellation marker.

### Revoke the access key

Expand Down
12 changes: 7 additions & 5 deletions src/pages/guides/use-mpp-with-x402.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -303,11 +303,13 @@ const mppx = Mppx.create({
recipient: '0xYourAddress',
testnet: true,
}),
stripe.charge({ // [!code hl]
client: stripeClient, // [!code hl]
networkId: 'internal', // [!code hl]
paymentMethodTypes: ['card'], // [!code hl]
}), // [!code hl]
// [!code hl:start]
stripe.charge({
client: stripeClient,
networkId: 'internal',
paymentMethodTypes: ['card'],
}),
// [!code hl:end]
],
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
})
Expand Down
2 changes: 1 addition & 1 deletion src/pages/intents/charge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { SpecCard } from '../../components/SpecCard'

# Charge [Immediate one-time payments]

The `charge` intent requests an immediate one-time payment. The client pays a fixed amount and the server settles the transaction before returning the response. This is the simplest MPP payment pattern—one request, one payment, one receipt.
The `charge` intent requests an immediate one-time payment. The client pays a fixed amount and the server settles the transaction before returning the response. This is the simplest MPP payment pattern—one request, one payment, one Receipt.

## How it works

Expand Down
4 changes: 2 additions & 2 deletions src/pages/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The Machine Payments Protocol (MPP) lets any client—agents, apps, or humans—
MPP is built around a simple, extensible core and is neutral to the implementation of underlying payment flows and methods.

- **Open standard built for the internet**—Built on an [open specification proposed to the IETF](https://paymentauth.org), not a proprietary API
- **Designed for payments**—Idempotency, security, and receipts are first-class primitives
- **Designed for payments**—Idempotency, security, and Receipts are first-class primitives
- **Works with stablecoins, cards, and bank transfers**—All payment methods can be supported through one protocol and flexible control flow
- **Any currency**—Transact in USD, EUR, BRL, USDC.e, BTC, or any other asset
- **Composable and designed for extension**—A flexible core allows advanced flows like disputes or additional primitives like identity to be gradually introduced
Expand All @@ -36,7 +36,7 @@ There is no shortage of ways to pay for things on the internet. Hundreds of paym

However, the very things that make these payment flows familiar and fast for human purchasers are structural headwinds for programmatic consumption. Many have tried, but it is a consistent uphill battle to fight browser automation pipelines, visual captchas, and ever changing payment forms—all of which reduce reliability, increase latency, and bear high costs.

This is not the fault of any individual payment method or credential. This is a global problem which exists at the _interface_ level: how buyer and seller negotiate cost, supported payment methods, and ultimately transact.
This is not the fault of any individual payment method or Credential. This is a global problem which exists at the _interface_ level: how buyer and seller negotiate cost, supported payment methods, and ultimately transact.

The Machine Payments Protocol addresses this gap by providing a payment interface built for programmatic access that strips away the complexity of rich checkout flows, while still providing robust security and reliability. By using MPP, you can accept payments from any client—agents, apps, or humans—and across any payment method, without complex checkout flows and integrations.

Expand Down
8 changes: 4 additions & 4 deletions src/pages/payment-methods/card/charge.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { SpecCard } from '../../../components/SpecCard'

The card implementation of the [charge](/intents/charge) intent.

The client obtains an encrypted network token from a credential issuer and sends it as a Credential. The server decrypts the token and charges the card through existing card network rails.
The client obtains an encrypted network token from a Credential issuer and sends it as a Credential. The server decrypts the token and charges the card through existing card network rails.

This method is best for single API calls, content access, or one-off purchases.

Expand Down Expand Up @@ -49,14 +49,14 @@ export async function handler(request: Request) {
| --- | --- | --- | --- |
| `acceptedNetworks` | `string[]` | Required | Accepted card networks |
| `merchantName` | `string` | Required | Display name shown to cardholder |
| `secretKey` | `string` | Required | HMAC signing key for challenge integrity |
| `secretKey` | `string` | Required | HMAC signing key for Challenge integrity |
| `gateway` | `ServerEnabler` | Required | Payment gateway for charging decrypted tokens |
| `privateKey` | `string` | Required | RSA-2048 PEM for token decryption |
| `billingRequired` | `boolean` | Optional | Request billing address from client |

## Client

Use `MppCard.create` to automatically handle `402` responses. The client parses the Challenge, requests an encrypted network token from the credential issuer, and retries with the Credential.
Use `MppCard.create` to automatically handle `402` responses. The client parses the Challenge, requests an encrypted network token from the Credential issuer, and retries with the Credential.

For production payments, enroll a card through a tokenization provider (a secure card collection form or vault API) to obtain a `cardId`.

Expand All @@ -79,7 +79,7 @@ const res = await fetch('https://api.merchant.com/data')

### Dev mode

Omit `enabler` to use the SDK's built-in dev mode. The client generates test network tokens encrypted with the server's published public key—no card enrollment or credential issuer required.
Omit `enabler` to use the SDK's built-in dev mode. The client generates test network tokens encrypted with the server's published public key—no card enrollment or Credential issuer required.

### Without polyfill

Expand Down
Loading
Loading