Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

API Server Example

A FastAPI server with payment-protected endpoints using the Machine Payments Protocol.

What This Demonstrates

  • Free endpoints that anyone can access
  • Paid endpoints protected by the @pay decorator
  • Automatic 402 challenge/response flow for the Payment HTTP Authentication Scheme

Prerequisites

  • Python 3.10+
  • uv (recommended) or pip

Installation

cd examples/api-server
uv sync

Configuration

Set environment variables (optional - defaults are provided):

export TEMPO_RPC_URL="https://rpc.testnet.tempo.xyz/"
export PAYMENT_DESTINATION="0x742d35Cc6634c0532925a3b844bC9e7595F8fE00"

Running

uv run python server.py

The server starts at http://localhost:8000.

Testing

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

Code Walkthrough

Payment Handler

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_KEY env var (or passed explicitly)
  • currency and recipient configured once on the method

Charging

result = await server.charge(
    authorization=request.headers.get("Authorization"),
    amount="0.001",
)
  • amount is in dollars (e.g., "0.50" = $0.50), auto-converted to base units
  • expires defaults to now + 5 minutes
  • No nested request dict needed

Payment Flow

  1. No Authorization header: Returns a Challenge → respond with 402
  2. Valid credential: Returns (Credential, Receipt) → return the resource
  3. Invalid credential: Returns a Challenge → respond with 402