mppx

TypeScript SDK for the Machine Payments Protocol

Documentation · Install · Quick Start · Examples · CLI · Payments Proxy · Protocol

Version MIT License

--- ## Documentation Full documentation, API reference, and guides are available at **[mpp.dev/sdk/typescript](https://mpp.dev/sdk/typescript)**. Contributors changing Tempo sessions should read the [session design](./src/tempo/session/README.md) before altering credential, recovery, accounting, or transport behavior. ## Install ```bash npm i mppx ``` ## Quick Start ### Server ```ts import { 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`. ### Client ```ts import { Mppx, tempo } from 'mppx/client' import { privateKeyToAccount } from 'viem/accounts' Mppx.create({ methods: [tempo({ account: privateKeyToAccount('0x...') })], }) // Global fetch now handles 402 automatically const res = await fetch('https://mpp.dev/api/ping/paid') ``` ## Examples | Example | Description | | ------------------------------------------------------ | ---------------------------------------------------- | | [charge](./examples/charge/) | Payment-gated photo generation API | | [charge-wagmi](./examples/charge-wagmi/) | Payment-gated charge with Wagmi + React | | [session/multi-fetch](./examples/session/multi-fetch/) | Multiple paid requests over a single payment channel | | [session/sse](./examples/session/sse/) | Pay-per-token LLM streaming with SSE | | [stripe](./examples/stripe/) | Stripe SPT charge with automatic client | ```bash npx gitpick wevm/mppx/examples/charge ``` ## CLI `mppx` includes a basic CLI for making HTTP requests with automatic payment handling. Tempo session channels are retained and reused automatically until you close them. ```bash # 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 mppx sessions close 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](./src/tempo/session/README.md#escrow-configuration-and-trust). `--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: ```ts 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: ```bash npm i -g mppx ``` ## Payments Proxy `mppx` exports a `Proxy` server handler so that you can create or define a 402-protected payments proxy for any API. ```ts 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.js ``` This 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 | ## Protocol Built on the ["Payment" HTTP Authentication Scheme](https://datatracker.ietf.org/doc/draft-ryan-httpauth-payment/). See [mpp-specs](https://github.com/tempoxyz/mpp-specs) for the full specification. ## License MIT ### Accepted Tempo currencies `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. ```ts 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.