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
82 changes: 82 additions & 0 deletions src/pages/guides/use-mpp-with-x402.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,88 @@ console.log(response.status)
// @log: 200
```

### Build a client for MPP and x402

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

```ts twoslash [client.ts]
import { Fetch, evm, tempo } from 'mppx/client'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount(
'0x0123456789012345678901234567890123456789012345678901234567890123',
)

const fetch = Fetch.from({
acceptPaymentPolicy: {
origins: ['https://api.example.com'],
},
methods: [
evm.charge({
account,
currencies: [evm.assets.baseSepolia.USDC],
maxAmount: '1.00',
}),
tempo.charge({ account }),
],
})

const response = await fetch('https://api.example.com/paid')
console.log(response.status)
// @log: 200
```

Use this pattern for coding agents, CLIs, SDKs, and application clients that need to call both native MPP APIs and x402 exact APIs.

### Send x402 headers manually

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

```ts twoslash [client.ts]
import { Mppx, evm } from 'mppx/client'
import { x402 } from 'mppx'
import { privateKeyToAccount } from 'viem/accounts'

const account = privateKeyToAccount(
'0x0123456789012345678901234567890123456789012345678901234567890123',
)

const mppx = Mppx.create({
methods: [
evm.charge({
account,
currencies: [evm.assets.baseSepolia.USDC],
maxAmount: '1.00',
}),
],
polyfill: false,
})

const challenge = await mppx.rawFetch('https://api.example.com/paid')
if (challenge.status !== 402) throw new Error('Expected payment challenge')

const paymentRequired = challenge.headers.get(x402.Types.paymentRequiredHeader)
if (!paymentRequired) throw new Error('Missing PAYMENT-REQUIRED')

const credential = await mppx.createCredential(
new Response(null, {
headers: {
[x402.Types.paymentRequiredHeader]: paymentRequired,
},
status: 402,
}),
)

const response = await mppx.rawFetch('https://api.example.com/paid', {
headers: {
[x402.Types.paymentSignatureHeader]: credential,
},
})

console.log(response.status)
// @log: 200
```

:::tip
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.
:::
Expand Down
31 changes: 31 additions & 0 deletions src/pages/partner-integrations/cloudflare-agents.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,37 @@ export async function paidPing() {
}
```

## Support MPP and x402 clients

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.

```ts [payments.ts]
import { Mppx, evm, tempo } from 'mppx/client'
import { privateKeyToAccount } from 'viem/accounts'

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

Mppx.create({
acceptPaymentPolicy: {
origins: ['https://api.example.com'],
},
methods: [
// [!code hl:start]
evm.charge({
account,
currencies: [evm.assets.baseSepolia.USDC],
maxAmount: '1.00',
}),
tempo.charge({ account }),
// [!code hl:end]
],
})
```

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.

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.

## Manage agent spend

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.
Expand Down
31 changes: 31 additions & 0 deletions src/pages/partner-integrations/mcp-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,37 @@ export async function paidPing() {
}
```

## Support MPP and x402 clients

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.

```ts [payments.ts]
import { Mppx, evm, tempo } from 'mppx/client'
import { privateKeyToAccount } from 'viem/accounts'

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

Mppx.create({
acceptPaymentPolicy: {
origins: ['https://api.example.com'],
},
methods: [
// [!code hl:start]
evm.charge({
account,
currencies: [evm.assets.baseSepolia.USDC],
maxAmount: '1.00',
}),
tempo.charge({ account }),
// [!code hl:end]
],
})
```

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.

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.

## Manage agent spend

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.
Expand Down
31 changes: 31 additions & 0 deletions src/pages/partner-integrations/vercel-ai-sdk.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,37 @@ console.log(toolResults)

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

## Support MPP and x402 clients

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.

```ts [payments.ts]
import { Mppx, evm, tempo } from 'mppx/client'
import { privateKeyToAccount } from 'viem/accounts'

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

Mppx.create({
acceptPaymentPolicy: {
origins: ['https://api.example.com'],
},
methods: [
// [!code hl:start]
evm.charge({
account,
currencies: [evm.assets.baseSepolia.USDC],
maxAmount: '1.00',
}),
tempo.charge({ account }),
// [!code hl:end]
],
})
```

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.

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.

## Manage agent spend

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.
Expand Down
34 changes: 34 additions & 0 deletions src/pages/sdk/typescript/middlewares/elysia.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -88,3 +88,37 @@ const app = new Elysia()
(app) => app.get('/content', () => ({ data: 'session content' })),
)
```

## x402-compatible clients

Elysia apps can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.

```ts [server.ts]
import { Elysia } from 'elysia'
import { Mppx, evm } from 'mppx/elysia'

const mppx = Mppx.create({
methods: [
evm.charge({
currency: evm.assets.baseSepolia.USDC,
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
x402: {
facilitator: 'https://x402.org/facilitator',
},
}),
],
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
})

const app = new Elysia().guard(
{
beforeHandle: mppx.evm.charge({
amount: '0.01',
description: 'Premium API access',
}),
},
(app) => app.get('/paid', () => ({ data: 'paid content' })),
)
```

See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.
32 changes: 32 additions & 0 deletions src/pages/sdk/typescript/middlewares/express.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,35 @@ app.get(
},
)
```

## x402-compatible clients

Express routes can serve MPP and x402 clients from the same endpoint when you register [`evm.charge`](/payment-methods/evm/charge) with `x402.facilitator`.

```ts [server.ts]
import express from 'express'
import { Mppx, evm } from 'mppx/express'

const app = express()

const mppx = Mppx.create({
methods: [
evm.charge({
currency: evm.assets.baseSepolia.USDC,
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
x402: {
facilitator: 'https://x402.org/facilitator',
},
}),
],
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
})

app.get(
'/paid',
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' }),
(req, res) => res.json({ data: 'paid content' }),
)
```

See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.
34 changes: 34 additions & 0 deletions src/pages/sdk/typescript/middlewares/hono.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -97,3 +97,37 @@ app.get(
},
)
```

## x402-compatible clients

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

```ts [worker.ts]
import { Hono } from 'hono'
import { Mppx, evm } from 'mppx/hono'

const app = new Hono()

const mppx = Mppx.create({
methods: [
evm.charge({
currency: evm.assets.baseSepolia.USDC,
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
x402: {
facilitator: 'https://x402.org/facilitator',
},
}),
],
secretKey: 'local-dev-secret',
})

app.get(
'/paid',
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' }),
(c) => c.json({ data: 'paid content' }),
)

export default app
```

See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.
27 changes: 27 additions & 0 deletions src/pages/sdk/typescript/middlewares/nextjs.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,30 @@ export const GET =
return Response.json({ payer })
})
```

## x402-compatible clients

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

```ts [app/api/paid/route.ts]
import { Mppx, evm } from 'mppx/nextjs'

const mppx = Mppx.create({
methods: [
evm.charge({
currency: evm.assets.baseSepolia.USDC,
recipient: '0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266',
x402: {
facilitator: 'https://x402.org/facilitator',
},
}),
],
secretKey: process.env.MPP_SECRET_KEY ?? 'local-dev-secret',
})

export const GET =
mppx.evm.charge({ amount: '0.01', description: 'Premium API access' })
(() => Response.json({ data: 'paid content' }))
```

See [build a client for MPP and x402](/guides/use-mpp-with-x402#build-a-client-for-mpp-and-x402) for the client setup.
Loading