Skip to main content

Production-ready starter kit for building x402 payment-gated FastAPI services

Project description

x402-fastapi-kit

Production-ready starter kit for building x402 payment-gated FastAPI services.

Turn any FastAPI endpoint into a paid API with one decorator. Built on Coinbase's x402 protocol — the open standard for internet-native payments.

Features

  • One-line payment gating@require_payment(price="$0.01") on any route
  • PaymentApp — batteries-included FastAPI subclass with middleware pre-wired
  • Environment-driven config — Pydantic Settings with .env support
  • Multi-chain — EVM (Base, Ethereum, Polygon) and Solana out of the box
  • Introspection — built-in /x402/health and /x402/routes endpoints
  • CLI scaffoldingx402kit init my-api generates a ready-to-run project
  • Spec-compliant — x402 v2 responses, PAYMENT-REQUIRED header, facilitator verification
  • API key fallbackX-API-Key header auth for traditional clients
  • Wallet allowlist — free-pass access for partners and your own AI agents
  • Rate limiting — sliding-window rate limiter with per-route limits and 429 responses
  • Event hooks@bus.on("payment.verified") callbacks for logging, analytics, alerts

Quick Start

1. Install

pip install x402-fastapi-kit

2. Set your wallet

export X402_PAY_TO=0xYourWalletAddress

3. Write your app

from x402_fastapi_kit import PaymentApp, require_payment

app = PaymentApp()

@app.get("/free")
async def free():
    return {"msg": "hello, no payment needed"}

@app.get("/premium")
@require_payment(price="$0.05", description="Premium data")
async def premium():
    return {"data": "this costs $0.05 per request"}

4. Run

uvicorn app:app --reload

Try it:

curl http://localhost:8000/free        # → 200 OK
curl http://localhost:8000/premium     # → 402 Payment Required
curl http://localhost:8000/x402/routes # → list of gated routes

Configuration

All settings are loaded from environment variables (prefix X402_) or a .env file:

Variable Default Description
X402_PAY_TO (required) Wallet address (EVM or Solana)
X402_NETWORK eip155:84532 CAIP-2 network ID
X402_FACILITATOR_URL https://x402.org/facilitator Facilitator service URL
X402_DEFAULT_PRICE $0.01 Default price for gated routes
X402_SCHEME exact Payment scheme
X402_MAX_TIMEOUT_SECONDS 300 Payment expiry
X402_HOST 0.0.0.0 Server bind host
X402_PORT 8000 Server bind port
X402_DEBUG false Debug mode
X402_SVM_PAY_TO (optional) Solana address for dual-chain
X402_RATE_LIMIT_ENABLED true Enable rate limiting
X402_RATE_LIMIT_RPM 60 Default requests per minute per client
X402_RATE_LIMIT_ROUTES (empty) Per-route limits: /weather=30,/forecast=10
X402_API_KEYS_ENABLED false Enable API key fallback auth
X402_API_KEYS (empty) Keys as name=secret,name=secret
X402_ALLOWLIST_ENABLED false Enable wallet allowlist
X402_ALLOWLIST_ADDRESSES (empty) Comma-separated wallet addresses

Supported Networks

Network CAIP-2 ID
Base Sepolia (testnet) eip155:84532
Base Mainnet eip155:8453
Ethereum Mainnet eip155:1
Polygon Mainnet eip155:137
Solana Devnet solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1
Solana Mainnet solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp

Access Control

The middleware runs a 4-step pipeline on every gated request. The first match wins:

Request → [1] Wallet Allowlist → [2] API Key → [3] Rate Limit → [4] x402 Payment
               (bypass)            (bypass)        (429)           (402/200)

API Key Fallback

Support traditional clients alongside x402 payers:

from x402_fastapi_kit import PaymentApp, APIKeyManager, require_payment

keys = APIKeyManager()
keys.add_key("partner-1", "sk_live_abc123")
keys.add_key("internal",  APIKeyManager.generate_key())

app = PaymentApp(api_key_manager=keys)

@app.get("/data")
@require_payment(price="$0.05")
async def data():
    return {"result": "works with X-PAYMENT or X-API-Key header"}
curl -H "X-API-Key: sk_live_abc123" http://localhost:8000/data  # 200 — bypassed

Wallet Allowlist

Give free access to partners, your own agents, or test wallets:

from x402_fastapi_kit import PaymentApp, WalletAllowlist

allowlist = WalletAllowlist()
allowlist.add("0xPartnerWallet...", label="acme-corp")
allowlist.add("0xMyAgentWallet...", label="internal-bot")

app = PaymentApp(wallet_allowlist=allowlist)
curl -H "X-WALLET: 0xPartnerWallet..." http://localhost:8000/data  # 200 — free

Rate Limiting

Protect your facilitator from abuse with per-client sliding-window limits:

from x402_fastapi_kit import PaymentApp, RateLimiter

limiter = RateLimiter(
    requests_per_minute=60,
    route_limits={"/expensive": 10, "/cheap": 200},
)

app = PaymentApp(rate_limiter=limiter)

Allowlisted wallets and API key holders bypass rate limits (they're checked first).

Event Hooks

Get notified at every decision point in the pipeline:

from x402_fastapi_kit import PaymentApp, EventBus, EventType

bus = EventBus()

@bus.on(EventType.PAYMENT_VERIFIED)
async def on_paid(event):
    print(f"💰 {event.route} — tx: {event.tx_hash}")

@bus.on(EventType.RATE_LIMITED)
async def on_throttled(event):
    alert(f"⚠️ Client {event.client_id} rate limited on {event.route}")

# Wildcard — see everything
bus.on_all(lambda e: metrics.emit(e.event_type, e.route))

app = PaymentApp(event_bus=bus)

Event types: payment.verified, payment.rejected, request.gated, auth.api_key, auth.allowlist, rate.limited, facilitator.error

Service Discovery

Make your API findable by AI agents and the x402 ecosystem:

from x402_fastapi_kit import PaymentApp, ServiceManifest

manifest = ServiceManifest(
    name="Weather API",
    description="Real-time weather data",
    tags=["weather", "data", "climate"],
    homepage="https://weather.example.com",
)

app = PaymentApp(manifest=manifest)
# Now serves /.well-known/x402 automatically

Enrich your OpenAPI schema so tools can read pricing from /openapi.json:

app.enrich_openapi_schema()
# Each gated endpoint now has x-x402 metadata in the spec

Register with the Bazaar discovery layer:

from x402_fastapi_kit import register_with_bazaar

await register_with_bazaar("https://weather.example.com", settings, manifest)

Client SDK (Buyer Side)

Make x402 payments from Python — for AI agents, scripts, and services that consume paid APIs:

from x402_fastapi_kit import X402Client, PaymentPolicy, DryRunSigner

# Dry-run mode (no real wallet, for testing)
client = X402Client(signer=DryRunSigner())

# With spending controls
client = X402Client(
    signer=my_wallet_signer,
    policy=PaymentPolicy(
        max_per_request="1.00",
        max_per_session="10.00",
        preferred_network="eip155:8453",
    ),
)

# Transparent 402 → pay → retry
resp = await client.get("https://api.example.com/weather")
print(resp.json())

# Check spending
print(f"Total spent: ${client.total_spent}")
print(f"Receipts: {client.receipts}")

# Discover a service
manifest = await client.discover("https://api.example.com")

Implement PaymentSigner for real wallets:

from x402_fastapi_kit import PaymentSigner

class MyWalletSigner(PaymentSigner):
    async def sign(self, requirements: dict) -> str:
        # Sign with your wallet (viem, web3.py, solders, etc.)
        return signed_payload_string

    @property
    def address(self) -> str:
        return "0xYourAddress"

Analytics Dashboard

Live revenue and request monitoring, powered by the EventBus:

from x402_fastapi_kit import PaymentApp, EventBus

bus = EventBus()
app = PaymentApp(event_bus=bus, analytics=True)
# Serves:
#   /x402/stats     → JSON snapshot (revenue, routes, auth breakdown)
#   /x402/dashboard → live HTML dashboard (auto-refreshes every 5s)

The dashboard shows: total revenue, payment count, per-route breakdown, auth method distribution, rate limit events, and a live event feed.

CLI

# Scaffold a new project
x402kit init my-paid-api

# Show version and networks
x402kit info

API Reference

PaymentApp

A FastAPI subclass that auto-wires the payment middleware, discovers @require_payment routes, and adds introspection endpoints.

from x402_fastapi_kit import PaymentApp

app = PaymentApp(
    title="My API",
    settings=X402Settings(pay_to="0x..."),
)

@require_payment

Decorator to gate a route. Apply after the route decorator:

@app.get("/data")
@require_payment(
    price="$0.05",           # required
    description="My data",   # shown in 402 response
    network="eip155:8453",   # override global network
    scheme="exact",          # payment scheme
    pay_to="0xOther",        # override global pay_to
)
async def get_data():
    return {"data": "paid content"}

PaymentGate

ASGI middleware (used internally by PaymentApp, or add manually):

from fastapi import FastAPI
from x402_fastapi_kit import PaymentGate, X402Settings

app = FastAPI()
app.add_middleware(PaymentGate, settings=X402Settings())

How It Works

Client                    Your FastAPI               Facilitator
  │                           │                          │
  │  GET /premium             │                          │
  │──────────────────────────▶│                          │
  │                           │ (no X-PAYMENT header)    │
  │  402 + payment details    │                          │
  │◀──────────────────────────│                          │
  │                           │                          │
  │  GET /premium             │                          │
  │  X-PAYMENT: <signed>      │                          │
  │──────────────────────────▶│                          │
  │                           │  POST /verify            │
  │                           │─────────────────────────▶│
  │                           │  { valid: true }         │
  │                           │◀─────────────────────────│
  │  200 + data               │                          │
  │◀──────────────────────────│                          │

Development

git clone https://github.com/your-org/x402-fastapi-kit
cd x402-fastapi-kit
pip install -e ".[dev]"
pytest

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

x402_fastapi_kit-0.3.0.tar.gz (49.5 kB view details)

Uploaded Source

Built Distribution

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

x402_fastapi_kit-0.3.0-py3-none-any.whl (43.5 kB view details)

Uploaded Python 3

File details

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

File metadata

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

File hashes

Hashes for x402_fastapi_kit-0.3.0.tar.gz
Algorithm Hash digest
SHA256 7a6334d7d96d7908e2932c29d5201e090884bed54b11d00b6a2b7ff6f7d353d1
MD5 58e58755bdcac384674b75eb9a9d74eb
BLAKE2b-256 494d60123d49cab0332a1e860cc6949484d0b32d8b2f97a1584b5d7ed5220a95

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on chetparker/x402-fastapi-kit

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

File details

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

File metadata

File hashes

Hashes for x402_fastapi_kit-0.3.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d281216aa8b9fb34a696466926cdfd6024008f17220f3ebac67ef6cc09f297f9
MD5 9a9a86e3a229020bc54195bd7a2f4dc8
BLAKE2b-256 61597f34c40c3bb305552d479d9c9b331185af52f09962da4bc60db6c4bc3963

See more details on using hashes here.

Provenance

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

Publisher: publish.yml on chetparker/x402-fastapi-kit

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