Skip to content

Commit 74f2d45

Browse files
authored
docs: add x402-compatible client examples (#776)
1 parent 45ea98d commit 74f2d45

8 files changed

Lines changed: 302 additions & 0 deletions

File tree

src/pages/guides/use-mpp-with-x402.mdx

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,88 @@ console.log(response.status)
181181
// @log: 200
182182
```
183183

184+
### Build a client for MPP and x402
185+
186+
Register `evm.charge` for x402 exact Challenges and the MPP methods you want to support. The HTTP client reads both `WWW-Authenticate` and `PAYMENT-REQUIRED`, then retries with either `Authorization` or `PAYMENT-SIGNATURE`.
187+
188+
```ts twoslash [client.ts]
189+
import { Fetch, evm, tempo } from 'mppx/client'
190+
import { privateKeyToAccount } from 'viem/accounts'
191+
192+
const account = privateKeyToAccount(
193+
'0x0123456789012345678901234567890123456789012345678901234567890123',
194+
)
195+
196+
const fetch = Fetch.from({
197+
acceptPaymentPolicy: {
198+
origins: ['https://api.example.com'],
199+
},
200+
methods: [
201+
evm.charge({
202+
account,
203+
currencies: [evm.assets.baseSepolia.USDC],
204+
maxAmount: '1.00',
205+
}),
206+
tempo.charge({ account }),
207+
],
208+
})
209+
210+
const response = await fetch('https://api.example.com/paid')
211+
console.log(response.status)
212+
// @log: 200
213+
```
214+
215+
Use this pattern for coding agents, CLIs, SDKs, and application clients that need to call both native MPP APIs and x402 exact APIs.
216+
217+
### Send x402 headers manually
218+
219+
Use `Mppx.create` when you need explicit control over the first request and retry. `createCredential` returns a `PAYMENT-SIGNATURE` value when the selected Challenge came from `PAYMENT-REQUIRED`.
220+
221+
```ts twoslash [client.ts]
222+
import { Mppx, evm } from 'mppx/client'
223+
import { x402 } from 'mppx'
224+
import { privateKeyToAccount } from 'viem/accounts'
225+
226+
const account = privateKeyToAccount(
227+
'0x0123456789012345678901234567890123456789012345678901234567890123',
228+
)
229+
230+
const mppx = Mppx.create({
231+
methods: [
232+
evm.charge({
233+
account,
234+
currencies: [evm.assets.baseSepolia.USDC],
235+
maxAmount: '1.00',
236+
}),
237+
],
238+
polyfill: false,
239+
})
240+
241+
const challenge = await mppx.rawFetch('https://api.example.com/paid')
242+
if (challenge.status !== 402) throw new Error('Expected payment challenge')
243+
244+
const paymentRequired = challenge.headers.get(x402.Types.paymentRequiredHeader)
245+
if (!paymentRequired) throw new Error('Missing PAYMENT-REQUIRED')
246+
247+
const credential = await mppx.createCredential(
248+
new Response(null, {
249+
headers: {
250+
[x402.Types.paymentRequiredHeader]: paymentRequired,
251+
},
252+
status: 402,
253+
}),
254+
)
255+
256+
const response = await mppx.rawFetch('https://api.example.com/paid', {
257+
headers: {
258+
[x402.Types.paymentSignatureHeader]: credential,
259+
},
260+
})
261+
262+
console.log(response.status)
263+
// @log: 200
264+
```
265+
184266
:::tip
185267
Because MPP uses the standard `WWW-Authenticate` scheme, it works with HTTP intermediaries (proxies, CDNs, API gateways) that understand [RFC 7235](https://www.rfc-editor.org/rfc/rfc7235) authentication.
186268
:::

src/pages/partner-integrations/cloudflare-agents.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,37 @@ export async function paidPing() {
6868
}
6969
```
7070

71+
## Support MPP and x402 clients
72+
73+
Register an EVM method beside your Tempo method when the agent needs to call APIs that support either native MPP or x402 exact. The same payment-aware fetch reads MPP `WWW-Authenticate` Challenges and x402 `PAYMENT-REQUIRED` Challenges, then retries with the matching `Authorization` or `PAYMENT-SIGNATURE` header.
74+
75+
```ts [payments.ts]
76+
import { Mppx, evm, tempo } from 'mppx/client'
77+
import { privateKeyToAccount } from 'viem/accounts'
78+
79+
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
80+
81+
Mppx.create({
82+
acceptPaymentPolicy: {
83+
origins: ['https://api.example.com'],
84+
},
85+
methods: [
86+
// [!code hl:start]
87+
evm.charge({
88+
account,
89+
currencies: [evm.assets.baseSepolia.USDC],
90+
maxAmount: '1.00',
91+
}),
92+
tempo.charge({ account }),
93+
// [!code hl:end]
94+
],
95+
})
96+
```
97+
98+
Use this setup before creating MCP transports or calling `fetch`. MCP tool calls can keep using MPP through the wrapped client, while HTTP calls can pay either native MPP or x402 exact endpoints.
99+
100+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the shared client flow.
101+
71102
## Manage agent spend
72103

73104
The examples above use a standard viem account. For long-running apps or agents, use scoped access keys when the runtime should pay in the background with spending limits, call scopes, recipient restrictions, and independent revocation.

src/pages/partner-integrations/mcp-sdk.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,37 @@ export async function paidPing() {
5858
}
5959
```
6060

61+
## Support MPP and x402 clients
62+
63+
Register an EVM method beside your Tempo method when the agent needs to call APIs that support either native MPP or x402 exact. The same payment-aware fetch reads MPP `WWW-Authenticate` Challenges and x402 `PAYMENT-REQUIRED` Challenges, then retries with the matching `Authorization` or `PAYMENT-SIGNATURE` header.
64+
65+
```ts [payments.ts]
66+
import { Mppx, evm, tempo } from 'mppx/client'
67+
import { privateKeyToAccount } from 'viem/accounts'
68+
69+
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
70+
71+
Mppx.create({
72+
acceptPaymentPolicy: {
73+
origins: ['https://api.example.com'],
74+
},
75+
methods: [
76+
// [!code hl:start]
77+
evm.charge({
78+
account,
79+
currencies: [evm.assets.baseSepolia.USDC],
80+
maxAmount: '1.00',
81+
}),
82+
tempo.charge({ account }),
83+
// [!code hl:end]
84+
],
85+
})
86+
```
87+
88+
Use this setup before creating MCP transports or calling `fetch`. MCP tool calls can keep using MPP through the wrapped client, while HTTP calls can pay either native MPP or x402 exact endpoints.
89+
90+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the shared client flow.
91+
6192
## Manage agent spend
6293

6394
The example above uses a standard viem account. For long-running apps or agents, use scoped access keys when the runtime should pay in the background with spending limits, call scopes, recipient restrictions, and independent revocation.

src/pages/partner-integrations/vercel-ai-sdk.mdx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,37 @@ console.log(toolResults)
7878

7979
The `tempo({ account })` helper used above supports Tempo [charge](/payment-methods/tempo/charge) and [session](/payment-methods/tempo/session) challenges.
8080

81+
## Support MPP and x402 clients
82+
83+
Register an EVM method beside your Tempo method when the agent needs to call APIs that support either native MPP or x402 exact. The same payment-aware fetch reads MPP `WWW-Authenticate` Challenges and x402 `PAYMENT-REQUIRED` Challenges, then retries with the matching `Authorization` or `PAYMENT-SIGNATURE` header.
84+
85+
```ts [payments.ts]
86+
import { Mppx, evm, tempo } from 'mppx/client'
87+
import { privateKeyToAccount } from 'viem/accounts'
88+
89+
const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`)
90+
91+
Mppx.create({
92+
acceptPaymentPolicy: {
93+
origins: ['https://api.example.com'],
94+
},
95+
methods: [
96+
// [!code hl:start]
97+
evm.charge({
98+
account,
99+
currencies: [evm.assets.baseSepolia.USDC],
100+
maxAmount: '1.00',
101+
}),
102+
tempo.charge({ account }),
103+
// [!code hl:end]
104+
],
105+
})
106+
```
107+
108+
Use this setup before creating MCP transports or calling `fetch`. MCP tool calls can keep using MPP through the wrapped client, while HTTP calls can pay either native MPP or x402 exact endpoints.
109+
110+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the shared client flow.
111+
81112
## Manage agent spend
82113

83114
The example above uses a standard viem account. For long-running apps or agents, use scoped access keys when the runtime should pay in the background with spending limits, call scopes, recipient restrictions, and independent revocation.

src/pages/sdk/typescript/middlewares/elysia.mdx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,3 +88,37 @@ const app = new Elysia()
8888
(app) => app.get('/content', () => ({ data: 'session content' })),
8989
)
9090
```
91+
92+
## x402-compatible clients
93+
94+
Elysia apps can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.
95+
96+
```ts [server.ts]
97+
import { Elysia } from 'elysia'
98+
import { Mppx, evm } from 'mppx/elysia'
99+
100+
const mppx = Mppx.create({
101+
methods: [
102+
evm.charge({
103+
currency: evm.assets.baseSepolia.USDC,
104+
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
105+
x402: {
106+
facilitator: 'https://x402.org/facilitator',
107+
},
108+
}),
109+
],
110+
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
111+
})
112+
113+
const app = new Elysia().guard(
114+
{
115+
beforeHandle: mppx.evm.charge({
116+
amount: '0.01',
117+
description: 'Premium API access',
118+
}),
119+
},
120+
(app) => app.get('/paid', () => ({ data: 'paid content' })),
121+
)
122+
```
123+
124+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.

src/pages/sdk/typescript/middlewares/express.mdx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,35 @@ app.get(
9797
},
9898
)
9999
```
100+
101+
## x402-compatible clients
102+
103+
Express routes can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.
104+
105+
```ts [server.ts]
106+
import express from 'express'
107+
import { Mppx, evm } from 'mppx/express'
108+
109+
const app = express()
110+
111+
const mppx = Mppx.create({
112+
methods: [
113+
evm.charge({
114+
currency: evm.assets.baseSepolia.USDC,
115+
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
116+
x402: {
117+
facilitator: 'https://x402.org/facilitator',
118+
},
119+
}),
120+
],
121+
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
122+
})
123+
124+
app.get(
125+
'/paid',
126+
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' }),
127+
(req, res) => res.json({ data: 'paid content' }),
128+
)
129+
```
130+
131+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.

src/pages/sdk/typescript/middlewares/hono.mdx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,37 @@ app.get(
9797
},
9898
)
9999
```
100+
101+
## x402-compatible clients
102+
103+
Hono apps, including apps deployed on Cloudflare Workers, can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.
104+
105+
```ts [worker.ts]
106+
import { Hono } from 'hono'
107+
import { Mppx, evm } from 'mppx/hono'
108+
109+
const app = new Hono()
110+
111+
const mppx = Mppx.create({
112+
methods: [
113+
evm.charge({
114+
currency: evm.assets.baseSepolia.USDC,
115+
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
116+
x402: {
117+
facilitator: 'https://x402.org/facilitator',
118+
},
119+
}),
120+
],
121+
secretKey: 'local-dev-secret',
122+
})
123+
124+
app.get(
125+
'/paid',
126+
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' }),
127+
(c) => c.json({ data: 'paid content' }),
128+
)
129+
130+
export default app
131+
```
132+
133+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.

src/pages/sdk/typescript/middlewares/nextjs.mdx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,3 +85,30 @@ export const GET =
8585
return Response.json({ payer })
8686
})
8787
```
88+
89+
## x402-compatible clients
90+
91+
Next.js route handlers, including routes deployed on Vercel, can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.
92+
93+
```ts [app/api/paid/route.ts]
94+
import { Mppx, evm } from 'mppx/nextjs'
95+
96+
const mppx = Mppx.create({
97+
methods: [
98+
evm.charge({
99+
currency: evm.assets.baseSepolia.USDC,
100+
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
101+
x402: {
102+
facilitator: 'https://x402.org/facilitator',
103+
},
104+
}),
105+
],
106+
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
107+
})
108+
109+
export const GET =
110+
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' })
111+
(() => Response.json({ data: 'paid content' }))
112+
```
113+
114+
See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.

0 commit comments

Comments
 (0)