Server
Protect endpoints with payment requirements
Protect endpoints with payment requirements.
Quick start
Create an Mpp instance with Mpp.create() and call charge() with a human-readable amount. The tempo() factory creates a Tempo payment method—configure currency and recipient once, then every charge() call uses those defaults.
import os
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from mpp import Challenge
from mpp.server import Mpp
from mpp.methods.tempo import tempo, ChargeIntent
app = FastAPI()
mpp = Mpp.create(
method=tempo(
currency="0x20c0000000000000000000000000000000000000",
intents={"charge": ChargeIntent()},
recipient="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
),
secret_key=os.environ["MPP_SECRET_KEY"],
)
@app.get("/resource")
async def get_resource(request: Request):
result = await mpp.charge(
authorization=request.headers.get("Authorization"),
amount="0.50",
)
if isinstance(result, Challenge):
return JSONResponse(
status_code=402,
content={"error": "Payment required"},
headers={"WWW-Authenticate": result.to_www_authenticate(mpp.realm)},
)
credential, receipt = result
return {"data": "paid content", "payer": credential.source}Mpp.create() auto-detects realm from environment variables (VERCEL_URL, FLY_APP_NAME, HOSTNAME, and others). It reads MPP_SECRET_KEY from the environment unless you pass secret_key explicitly:
mpp = Mpp.create(
method=tempo(
currency="0x20c0000000000000000000000000000000000000",
intents={"charge": ChargeIntent()},
recipient="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
),
realm="api.example.com",
secret_key="my-server-secret",
)tempo() factory
tempo() creates a TempoMethod that bundles a payment network, its intents, and default parameters together. Each intent must be explicitly registered via the intents parameter.
from mpp.methods.tempo import tempo, ChargeIntent
method = tempo(
currency="0x20c0000000000000000000000000000000000000",
recipient="0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
intents={"charge": ChargeIntent()},
)tempo() parameters
currency (optional)
- Type:
str
Default TIP-20 token address for charges.
decimals (optional)
- Type:
int - Default:
6
Token decimal places for amount conversion (6 for pathUSD).
intents
- Type:
dict[str, Intent]
Intents to register (for example, charge). Each intent must be explicitly provided.
recipient (optional)
- Type:
str
Default recipient address for charges.
rpc_url (optional)
- Type:
str - Default:
"https://rpc.tempo.xyz"
Tempo RPC endpoint URL.
Mpp.create() parameters
method
- Type:
Method
Payment method instance returned by tempo().
realm (optional)
- Type:
str
Server realm for WWW-Authenticate headers. Auto-detected from environment if omitted.
secret_key (optional)
- Type:
str
HMAC secret for stateless Challenge ID verification. Reads MPP_SECRET_KEY if omitted. Raises if neither is set.
charge() parameters
amount
- Type:
str
Payment amount in human-readable units (for example, "0.50" for $0.50). Automatically converted to base units using the method's decimal precision (6 decimals for pathUSD).
authorization
- Type:
str | None
The Authorization header value from the incoming request.
currency (optional)
- Type:
str
Override the method's default currency address.
description (optional)
- Type:
str
Human-readable description attached to the Challenge.
expires (optional)
- Type:
str
Challenge expiration as ISO 8601 timestamp. Defaults to 5 minutes from now.
recipient (optional)
- Type:
str
Override the method's default recipient address.
@requires_payment decorator
For the lower-level decorator API, use @requires_payment with an explicit intent, request, realm, and secret key:
from fastapi import FastAPI, Request
from mpp import Credential, Receipt
from mpp.server import requires_payment
from mpp.methods.tempo import ChargeIntent
app = FastAPI()
intent = ChargeIntent(rpc_url="https://rpc.tempo.xyz")
@app.get("/resource")
@requires_payment(
intent=intent,
request={"amount": "1000000", "currency": "0x...", "recipient": "0x..."},
realm="api.example.com",
secret_key="my-server-secret",
)
async def get_resource(request: Request, credential: Credential, receipt: Receipt):
return {"data": "paid content", "payer": credential.source}Parameters
| Parameter | Description |
|---|---|
intent | Payment intent for verification |
realm | Server realm for WWW-Authenticate |
request | Payment request data (dict or callable) |
secret_key | Secret for Challenge IDs |