Skip to main content

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

Metadata

Release files for fastapi-mpp 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fastapi-mpp 0.3.0
File Size Uploaded
fastapi_mpp-0.3.0.tar.gz 20.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fastapi-mpp 0.3.0
File Interpreter ABI Platform
fastapi_mpp-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 39.0 kB

Release files / fastapi_mpp-0.3.0.tar.gz

Download URL fastapi_mpp-0.3.0.tar.gz
Size 20.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7944602410afbdf5d66553d47a861925f3e218fbc4466c2cccec30c20ac06b25
BLAKE2b-256 checksum
How to use checksums
c63124722a8ff974564acbec10f02a53a66ad13b7569800647d7e3f295c5d1a4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.

Transparency log

Release files / fastapi_mpp-0.3.0-py3-none-any.whl

Download URL fastapi_mpp-0.3.0-py3-none-any.whl
Size 18.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
9fb69deb2ea955c62219e322119fd9195b57ddd1bb6e42c785d961287bf89dd8
BLAKE2b-256 checksum
How to use checksums
05bb764083e89709ae384211c208bb392c7fca9a897765c3836c5b031238f4e1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Mar 19, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page