TypeScript SDK for the Machine Payments Protocol
Documentation · Install · Quick Start · Examples · CLI · Payments Proxy · Protocol
Full documentation, API reference, and guides are available at mpp.dev/sdk/typescript.
Contributors changing Tempo sessions should read the session design before altering credential, recovery, accounting, or transport behavior.
npm i mppximport { Mppx, tempo } from 'mppx/server'
const mppx = Mppx.create({
methods: [
tempo({
recipient: '0x742d35Cc6634c0532925a3b844bC9e7595F8fE00',
}),
],
secretKey: process.env.MPP_SECRET_KEY!,
})
export async function handler(request: Request) {
const response = await mppx.charge({ amount: '1' })(request)
if (response.status === 402) return response.challenge
return response.withReceipt(Response.json({ data: '...' }))
}Generate MPP_SECRET_KEY with at least 32 bytes, for example: openssl rand -base64 32.
import { privateKeyToAccount } from 'viem/accounts'
import { Mppx, tempo } from 'mppx/client'
Mppx.create({
methods: [tempo({ account: privateKeyToAccount('0x...') })],
})
// Global fetch now handles 402 automatically
const res = await fetch('https://mpp.dev/api/ping/paid')| Example | Description |
|---|---|
| charge | Payment-gated photo generation API |
| charge-wagmi | Payment-gated charge with Wagmi + React |
| session/multi-fetch | Multiple paid requests over a single payment channel |
| session/sse | Pay-per-token LLM streaming with SSE |
| stripe | Stripe SPT charge with automatic client |
npx gitpick wevm/mppx/examples/chargemppx includes a basic CLI for making HTTP requests with automatic payment handling. Tempo
session channels are retained and reused automatically until you close them.
# create account - stored in keychain, autofunded on testnet
mppx account create
# make request - automatic payment handling, curl-like api
mppx example.com
# pay an x402 offer on a server that advertises both protocols
mppx example.com --protocol x402
# open another session instead of reusing the preferred channel
mppx example.com --session new
# inspect and close retained sessions
mppx sessions list
mppx sessions view <channel-id>
mppx sessions close <channel-id>
mppx sessions close --all --yes
# explicitly trust a custom session escrow advertised by the server
mppx example.com -M allowCustomEscrow=true--session auto is the default. Pass new to open another channel or a channel ID to select one
explicitly.
Tempo session clients accept only the canonical escrow contract by default. A server may advertise
its configured custom escrow in the payment challenge, but the client rejects it unless
-M allowCustomEscrow=true is supplied. This opt-in trusts the server-selected address; clients
that do not support custom escrows should leave it unset. See the
session escrow trust documentation.
--protocol auto is the default: MPP is preferred when available, and x402 is used otherwise.
Pass mpp or x402 to require one protocol. x402 payments use the same EVM account as EVM
charges, so MPPX_PRIVATE_KEY or a stored account works for both.
Payment extensions can enforce policy or prepare funds after challenge selection and confirmation, immediately before credential creation:
import { defineConfig, Extension } from 'mppx/cli'
export default defineConfig({
extensions: [
Extension.from({
async preparePayment({ challenge }) {
await prepareFunds(challenge)
},
}),
],
})Extensions run in configuration order. Throwing rejects the payment before Mppx signs it.
You can also install globally to use the mppx CLI from anywhere:
npm i -g mppxmppx exports a Proxy server handler so that you can create or define a 402-protected payments proxy for any API.
import { openai, stripe, Proxy } from 'mppx/proxy'
import { Mppx, tempo } from 'mppx/server'
const mppx = Mppx.create({
methods: [tempo()],
secretKey: process.env.MPP_SECRET_KEY!,
})
const proxy = Proxy.create({
services: [
openai({
apiKey: 'sk-...',
routes: {
'POST /v1/chat/completions': mppx.charge({ amount: '0.05' }),
'POST /v1/completions': mppx.tempo.session({
amount: '0.0001',
unitType: 'token',
}),
'GET /v1/models': true,
},
}),
stripe({
apiKey: 'sk-...',
routes: {
'POST /v1/charges': mppx.charge({ amount: '0.01' }),
'GET /v1/customers/:id': true,
},
}),
],
})
createServer(proxy.listener) // Node.js
Bun.serve(proxy) // Bun
Deno.serve(proxy.fetch) // Deno
app.use(proxy.listener) // Express
app.all('*', (c) => proxy.fetch(c.req.raw)) // Hono
app.all('*', (c) => proxy.fetch(c.request)) // Elysia
export const GET = proxy.fetch // Next.js
export const POST = proxy.fetch // Next.jsThis exposes the following routes:
| Route | Pricing |
|---|---|
POST /openai/v1/chat/completions |
charge $0.005 |
POST /openai/v1/completions |
session $0.0001 per token |
GET /openai/v1/models |
free |
POST /stripe/v1/charges |
charge $0.01 |
GET /stripe/v1/customers/:id |
free |
Built on the "Payment" HTTP Authentication Scheme. See mpp-specs for the full specification.
MIT
tempo(), tempo.charge(), tempo.session(), and tempo.subscription() offer OUSD first, followed by USDC.e on mainnet or pathUSD on Moderato (testnet: true). Each factory returns a group accepted directly by Mppx.create. Clients choose one offer; ordering does not trigger an automatic swap.
import { Mppx, tempo } from 'mppx/server'
import { ousd, usdce } from 'viem/tokens'
const mppx = Mppx.create({
methods: [
tempo.charge({
currencies: [ousd, usdce],
recipient: '0x742d35Cc6634c0532925a3b844bC9e7595F8fE00',
}),
],
})Omit currencies for the network defaults, or use currencies: [ousd] to accept only OUSD on mainnet. Explicit lists replace the defaults. The deprecated currency option also restricts acceptance to one token. Wire requests and handler overrides continue to use singular currency.
Use configured handlers such as mppx.tempo.charge when composing payments. Code that directly inspects a Method can destructure the group: const [charge] = tempo.charge({ currencies: [ousd] }). Existing sessions and subscriptions continue using their originally authorized currency.