Skip to main content

Add Machine Payments Protocol (MPP) support to FastAPI endpoints in a few lines.

Project description

fastapi-mpp

PyPI version Python versions License: MIT GitHub stars

Machine Payments Protocol middleware for FastAPI.

Version v0.3 hardens receipt validation, replay protection, session binding, and adds pluggable storage backends with Redis support for production deployments. This project is still beta.

Installation

pip install fastapi-mpp

For production validation, install Tempo support so default cryptographic validation is available:

pip install "fastapi-mpp[tempo]"

Optional extras:

pip install "fastapi-mpp[dotenv]"
pip install "fastapi-mpp[redis]"
pip install "fastapi-mpp[stripe]"
pip install "fastapi-mpp[all]"

System Prerequisites

  • RedisStore is designed for Redis 6.2+ where GETDEL is available for atomic one-time challenge consumption.
  • For older Redis versions, the library falls back to an atomic Lua script, but Redis 6.2+ is strongly recommended for production compatibility and operations.

Usage

Server setup

import os

from fastapi import FastAPI, Request
from mpp_fastapi.core import MPP
from mpp_fastapi.stores import RedisStore

app = FastAPI()

# Production mode (default): requires receipt_validator or fastapi-mpp[tempo].
mpp = MPP(
    store=RedisStore(
        redis_url=os.getenv("MPP_REDIS_URL", "redis://localhost:6379/0"),
    )
)

@app.get("/premium")
@mpp.charge(amount="0.05", currency="USD", description="Premium data")
async def premium(request: Request):
    return {"data": "paid content"}

HTTP flow (v0.3 hardened)

  1. Client calls endpoint without credential.
  2. Server responds 402 Payment Required with:
    • WWW-Authenticate: Payment challenge="<base64url(JSON)>", realm="MyAPI", expires="..."
    • challenge body containing challenge_id, intent, amount, currency, expires_at, hints
  3. Wallet pays and retries with:
    • Authorization: Payment credential="<base64url(receipt-json)>"
  4. Server validates receipt (fail-closed in production), applies replay checks, and returns success with:
    • Payment-Receipt: <base64url(receipt-json)>
    • optional session headers when session mode is enabled.

Legacy compatibility can be kept with allow_legacy_headers=True:

  • X-MPP-Receipt
  • X-MPP-Session-Id

Session budgets

from fastapi import FastAPI, Request
from mpp_fastapi.core import MPP
from mpp_fastapi.types import MPPChargeOptions

app = FastAPI()
mpp = MPP()

session_options = MPPChargeOptions(
    amount="0.01",
    currency="USD",
    description="Session-metered call",
    session=True,
    max_amount="0.50",
    require_idempotency_key=True,
)

@app.post("/agent/infer")
@mpp.charge(options=session_options)
async def infer(request: Request):
    return {"result": "paid inference"}

Sessions are HMAC-signed opaque tokens bound to:

  • route scope
  • optional payer source
  • currency/provider
  • issued-at and expiry (default 15 minutes)
  • max budget tracked in store

Local Run

uv venv
source .venv/bin/activate
uv pip install -e ".[dev]"
uvicorn examples.simple_app:app --reload

Then test:

curl -i http://127.0.0.1:8000/free
curl -i http://127.0.0.1:8000/premium

Expected behavior demo:

GET /free -> 200 OK
GET /premium (without Authorization) -> 402 Payment Required
GET /premium (with Authorization: Payment credential="...") -> 200 OK

Security

Read SECURITY.md before production usage.

  • Beta warning: use with caution.
  • In-memory replay/session/rate-limit stores are suitable for single-process deployments only.
  • Production mode is fail-closed when receipt validation is not configured.
  • HTTPS is enforced in production mode.

Headers

Incoming:

  • Authorization: Payment credential="..." (preferred)
  • Payment-Receipt (supported)
  • Payment-Session (session spends)
  • X-MPP-Receipt and X-MPP-Session-Id in legacy mode
  • Idempotency-Key for safer retries

Response on 402:

  • WWW-Authenticate: Payment challenge="...", realm="...", expires="..."
  • JSON challenge payload

Response on success:

  • Payment-Receipt
  • Payment-Session when session authorization is established

Design Notes

  • Storage is abstracted via BaseStore; default InMemoryStore is single-process only.
  • RedisStore is available for multi-worker production deployments.
  • Header size limit is enforced (8KB) for authorization and receipt headers.
  • A basic in-memory challenge rate limiter is enabled (default 10 challenges/IP/minute).

Roadmap

  • Redis-backed replay/session/rate-limit stores
  • Full conformance with evolving HTTP Payment auth draft semantics
  • Advanced rate limiting and abuse controls
  • Payment provider adapters and richer telemetry

Contributing

  1. Fork the repository.
  2. Create a feature branch.
  3. Add tests for behavior changes.
  4. Run:
uv pip install -e ".[dev]"
pytest
ruff check .
mypy src
  1. Open a PR with clear before/after behavior.

Credits

Inspired by the MPP ecosystem work and early protocol specs from Tempo and Stripe collaborators. Please refer to official protocol repos/specs for normative behavior and updates.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastapi_mpp-0.3.0.tar.gz (20.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastapi_mpp-0.3.0-py3-none-any.whl (18.3 kB view details)

Uploaded Python 3

File details

Details for the file fastapi_mpp-0.3.0.tar.gz.

File metadata

  • Download URL: fastapi_mpp-0.3.0.tar.gz
  • Upload date:
  • Size: 20.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fastapi_mpp-0.3.0.tar.gz
Algorithm Hash digest
SHA256 7944602410afbdf5d66553d47a861925f3e218fbc4466c2cccec30c20ac06b25
MD5 187e797a9e2a07acf23149b2bee6f2d3
BLAKE2b-256 c63124722a8ff974564acbec10f02a53a66ad13b7569800647d7e3f295c5d1a4

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_mpp-0.3.0.tar.gz:

Publisher: publish.yml on SylvainCostes/fastapi-mpp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fastapi_mpp-0.3.0-py3-none-any.whl.

File metadata

  • Download URL: fastapi_mpp-0.3.0-py3-none-any.whl
  • Upload date:
  • Size: 18.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for fastapi_mpp-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9fb69deb2ea955c62219e322119fd9195b57ddd1bb6e42c785d961287bf89dd8
MD5 0ae2033177891a2d079bb9a2b8485af7
BLAKE2b-256 05bb764083e89709ae384211c208bb392c7fca9a897765c3836c5b031238f4e1

See more details on using hashes here.

Provenance

The following attestation bundles were made for fastapi_mpp-0.3.0-py3-none-any.whl:

Publisher: publish.yml on SylvainCostes/fastapi-mpp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page