Catalog PyPI
Back to packageRELEASE DETAILS

0.1.0

PyPI

a402

ASGI middleware that gates FastAPI/Starlette endpoints behind a402 HTTP payments

Published10 Jul 2026
Direct dependencies6
Transitive dependenciesNot calculated

README

Version 0.1.0 documentation

a402 Python SDK

ASGI middleware that gates FastAPI/Starlette endpoints behind a402 HTTP payments. The seller never handles keys or crypto — the facilitator does.

Install

pip install a402
# With FastAPI extras:
pip install "a402[fastapi]"

Usage

import os
from fastapi import FastAPI
from a402 import A402Middleware, A402Config

app = FastAPI()

app.add_middleware(
    A402Middleware,
    # facilitator_url is optional — defaults to a402's hosted facilitator.
    # Set it only to self-host or point at a staging facilitator.
    config=A402Config(api_key=os.environ["A402_KEY"]),
    routes=[
        {"method": "GET", "path": "/v1/financials", "price": "$0.05"},
        {"path": "/v1/quote", "price": "$0.01"},  # method defaults to GET
    ],
)

@app.get("/v1/financials")
async def get_financials():
    return {"ticker": "NVDA", "revenue": "$60.9B"}

@pay decorator

Attach pricing metadata to a route function. Must still be listed in the routes dict.

from a402 import pay

@app.get("/v1/report")
@pay("$0.10")
async def get_report():
    return {"report": "..."}

How it works

  1. A request arrives with no X-PAYMENT header. The middleware calls POST /facilitator/challenge with the seller's API key and route price. The 402 response contains an accepts array describing the EIP-3009 USDC authorization the client must sign.

  2. The client signs the authorization off-chain and retries with an X-PAYMENT header (base64-encoded JSON).

  3. The middleware decodes the header and calls POST /facilitator/settle. On success (HTTP 200) the real handler runs and the response carries X-PAYMENT-RESPONSE (base64 settlement receipt). On 402/403 the status and body are forwarded to the client.

The settlement uses EIP-3009 (transferWithAuthorization) — the on-chain transfer is confirmed before the 200 is returned, so a 200 from the middleware means funds are settled on the source chain. Cross-chain consolidation via CCTP may still be in progress (check mintTxHash).

Route config keys

KeyTypeDefault
price"$0.05" or 0.05required
descriptionstr"Access to METHOD /path"
resourcestr"METHOD /path"

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 7

Native requirements
6 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
httpx
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
httpx>=0.27runtime
starlette
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
starlette>=0.27runtime
fastapi
Environment
{
  "extras": "",
  "marker": "extra == \"fastapi\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
fastapi>=0.100; extra == "fastapi"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8; extra == "dev"runtime
anyio
Environment
{
  "extras": "trio",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
anyio[trio]; extra == "dev"runtime
httpx
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
httpx; extra == "dev"runtime
pytest-anyio
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest-anyio; extra == "dev"runtime

Distribution files

2 collected
a402-0.1.0-py3-none-any.whl

bdist_wheel · 6.21 KB · Python py3

Source file
a402-0.1.0.tar.gz

sdist · 9.34 KB · Python source

Source file

Repository

PENDING
pixel8labs/a402

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 16:41 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:0aaf2cc01e4ffa44d55c1604772b9aed8607e06ad463fae32d62e2b83337e906

Other collected versions

View all collected versions →