Server quickstart
Plug MPP into any server framework to accept payments for protected resources. Use mppx middleware for your framework, or call mppx/server directly with the Fetch API.
MPP server framework middleware
Use the framework-specific middleware from mppx to integrate payment into your server. Each middleware handles the 402 challenge/credential flow and attaches receipts automatically.
import { Mppx, tempo } from 'mppx/nextjs'
const mppx = Mppx.create({
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})
export const GET =
mppx.charge({ amount: '0.1' })
(() => Response.json({ data: '...' }))import { Hono } from 'hono'
import { Mppx, tempo } from 'mppx/hono'
const app = new Hono()
const mppx = Mppx.create({
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})
app.get(
'/resource',
mppx.charge({ amount: '0.1' }),
(c) => c.json({ data: '...' }),
)import express from 'express'
import { Mppx, tempo } from 'mppx/express'
const app = express()
const mppx = Mppx.create({
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})
app.get(
'/resource',
mppx.charge({ amount: '0.1' }),
(req, res) => res.json({ data: '...' }))Manual MPP server mode
If you prefer full control over the payment flow, use mppx/server directly with the Fetch API.
import { Mppx, tempo } from 'mppx/server'
const mppx = Mppx.create({
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})
export async function handler(request: Request) {
const response = await mppx.charge({ amount: '0.1' })(request)
// Payment required: send 402 response with challenge
if (response.status === 402) return response.challenge
// Payment verified: attach receipt and return resource
return response.withReceipt(Response.json({ data: '...' }))
}MPP payment realm
The realm identifies your server in payment challenges and on-chain attribution. By default, mppx auto-detects it from environment variables (HOSTNAME, VERCEL_URL, etc.), but this can produce incorrect values in containerized environments where HOSTNAME is set to an internal identifier (e.g. a Kubernetes pod name).
Set realm explicitly to your public domain:
const mppx = Mppx.create({
realm: 'api.example.com',
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})You can also set the MPP_REALM environment variable instead of passing it in code.
MPP push and pull modes
Tempo charges support two transaction submission modes, determined by the client:
pullmode (default): the client signs the transaction and sends the serialized transaction to the server. The server broadcasts it and verifies on-chain. This enables the server to sponsor gas fees via afeePayer.pushmode: the client builds, signs, and broadcasts the transaction itself (for example, via a browser wallet). It sends the transaction hash to the server, which verifies the payment by fetching the receipt.
Your server handles both modes automatically — no configuration required. The server inspects the credential payload type (transaction for pull, hash for push) and verifies accordingly.
MPP fee sponsorship
To sponsor gas fees for pull-mode clients, pass a feePayer account to tempo():
import { Mppx, tempo } from 'mppx/server'
import { privateKeyToAccount } from 'viem/accounts'
const mppx = Mppx.create({
methods: [tempo({
currency: '0x20c0000000000000000000000000000000000000',
feePayer: privateKeyToAccount('0x…'),
recipient: '0xa726a1CD723409074DF9108A2187cfA19899aCF8',
})],
})When a pull-mode client submits a signed transaction, the server co-signs with the fee payer account before broadcasting. Push-mode clients pay their own gas, so feePayer is ignored for those requests.
Test your MPP server
After your server is running, test it with the mppx CLI:
# Create an account funded with testnet tokens
$ npx mppx account create
# Make a paid request
$ npx mppx <your-server>/resourceNext steps for MPP servers
Handle payment-gated resources automatically
End-to-end guide with the charge intent
Complete mppx server API documentation
Was this helpful?