Skip to content

Repository files navigation

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.

Contributors changing Tempo sessions should read the session design before altering credential, recovery, accounting, or transport behavior.

Install

npm i mppx

Quick Start

Server

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

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')

Examples

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

# 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 mppx

Payments Proxy

mppx 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.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. See 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.

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.

About

TypeScript Interface for Machine Payments Protocol

Topics

Resources

Code of conduct

Security policy

Stars

182 stars

Watchers

1 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages