A FastAPI server with payment-protected endpoints using the Machine Payments Protocol.
- Free endpoints that anyone can access
- Paid endpoints protected by the
@paydecorator - Automatic 402 challenge/response flow for the Payment HTTP Authentication Scheme
- Python 3.10+
- uv (recommended) or pip
cd examples/api-server
uv syncSet environment variables (optional - defaults are provided):
export TEMPO_RPC_URL="https://rpc.testnet.tempo.xyz/"
export PAYMENT_DESTINATION="0x742d35Cc6634c0532925a3b844bC9e7595F8fE00"uv run python server.pyThe server starts at http://localhost:8000.
Free endpoint (no payment required):
curl http://localhost:8000/free
# {"message":"This content is free!"}Paid endpoint (use the pympp client to handle payment automatically):
python -m mpp.fetch http://localhost:8000/paid
# {"message":"This is paid content!","payer":"0x...","tx":"0x..."}Paid endpoint without payment (returns 402):
curl -i http://localhost:8000/paid
# HTTP/1.1 402 Payment Required
# WWW-Authenticate: Payment ...from mpp.server import Mpp
from mpp.methods.tempo import tempo
server = Mpp.create(
method=tempo(currency=PATH_USD, recipient=DESTINATION),
)Mpp.create() sets up the payment handler with smart defaults:
- realm auto-detected from environment (
MPP_REALM,VERCEL_URL, etc.) - secret_key read from
MPP_SECRET_KEYenv var (or passed explicitly) - currency and recipient configured once on the method
result = await server.charge(
authorization=request.headers.get("Authorization"),
amount="0.001",
)amountis in dollars (e.g.,"0.50"= $0.50), auto-converted to base unitsexpiresdefaults to now + 5 minutes- No nested request dict needed
- No Authorization header: Returns a
Challenge→ respond with 402 - Valid credential: Returns
(Credential, Receipt)→ return the resource - Invalid credential: Returns a
Challenge→ respond with 402