Skip to content
LogoLogo

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.

server.py
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:

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

server.py
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:

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

ParameterDescription
intentPayment intent for verification
realmServer realm for WWW-Authenticate
requestPayment request data (dict or callable)
secret_keySecret for Challenge IDs