Documentation Index
Fetch the complete documentation index at: https://docs.swiftpay.finance/llms.txt
Use this file to discover all available pages before exploring further.
The swiftpay-x402-fastapi-guard middleware adds HTTP 402 payment requirements to your FastAPI routes. Protect specific endpoints with per-request stablecoin payments.
Features
- Two-round payment flow — Return 402 + requirements, then serve on second request with payment
- FastAPI middleware — Integrates seamlessly with FastAPI’s middleware stack
- Server-agnostic signing — SwiftPay handles EIP-712 signature verification
- No key management — Your server never touches private keys
- Type-safe — Full type hints with Python 3.10+
Installation
pip install swiftpay-x402-fastapi-guard
Also requires swiftpay-api-client:
pip install swiftpay-api-client
Quick Start
from fastapi import FastAPI
from swiftpay import AsyncSwiftPay
from swiftpay_x402_fastapi_guard import X402Guard
app = FastAPI()
client = AsyncSwiftPay(secret_key="sk_live_...")
# Register middleware
app.add_middleware(
X402Guard,
client=client,
routes={"/v1/analyze": "https://api.example.com/v1/analyze"},
)
@app.get("/v1/analyze")
async def analyze():
return {"sentiment": "positive", "score": 0.87}
How It Works
The x402 payment flow is a two-round process:
Client makes a request without the X-PAYMENT header:
Server responds with HTTP 402 and payment requirements:
HTTP/1.1 402 Payment Required
{
"x402-version": "v1",
"x402-nonce": "...",
"x402-payment-requirements": {
"asset": "USDC",
"network": "ethereum",
"amount": "0.05",
...
}
}
Round 2: With Payment Proof
Client signs the payment requirements and resends the request with the signed proof:
GET /v1/analyze
X-PAYMENT: <signed-eip712-payload>
Server validates the signature via SwiftPay’s API and serves the resource:
HTTP/1.1 200 OK
{
"sentiment": "positive",
"score": 0.87
}
Configuration
X402Guard(
client: AsyncSwiftPay, # Required: SwiftPay API client
routes: dict[str, str] = {}, # Route path → endpoint URL mapping
# Optional:
base_url: str = "https://api.swiftpay.finance", # API base URL
timeout: float = 30.0, # Request timeout in seconds
)
Routes mapping:
- Key: The FastAPI route path (e.g.,
/v1/analyze)
- Value: The endpoint URL registered with SwiftPay
- Routes not in this mapping pass through unprotected
Usage Patterns
Protect Specific Routes
from fastapi import FastAPI
from swiftpay import AsyncSwiftPay
from swiftpay_x402_fastapi_guard import X402Guard
app = FastAPI()
client = AsyncSwiftPay(secret_key="sk_live_...")
app.add_middleware(
X402Guard,
client=client,
routes={
"/v1/analyze": "https://api.example.com/v1/analyze",
"/v1/translate": "https://api.example.com/v1/translate",
},
)
@app.get("/v1/analyze")
async def analyze(text: str):
return {"sentiment": "positive", "score": 0.87}
@app.get("/v1/translate")
async def translate(text: str, target: str):
return {"translated": "translated text"}
@app.get("/v1/public")
async def public_endpoint():
# Not in routes → no payment required
return {"public": "data"}
Tiered Pricing
from enum import Enum
class Tier(str, Enum):
BASIC = "basic"
PREMIUM = "premium"
app.add_middleware(
X402Guard,
client=client,
routes={
"/v1/analyze-basic": "https://api.example.com/analyze-basic", # Lower cost
"/v1/analyze-premium": "https://api.example.com/analyze-premium", # Higher cost
},
)
@app.get("/v1/analyze/{tier}")
async def analyze(tier: Tier, text: str):
if tier == Tier.PREMIUM:
return {"analysis": "detailed results"}
return {"analysis": "basic results"}
Environment-Based Configuration
import os
from dotenv import load_dotenv
load_dotenv()
client = AsyncSwiftPay(
secret_key=os.getenv("SWIFTPAY_SECRET_KEY"),
base_url=os.getenv("SWIFTPAY_API_URL", "https://api.swiftpay.finance"),
)
# Production: All routes require payment
# Development: Routes pass through unprotected
routes = {
"/v1/analyze": "https://api.example.com/v1/analyze",
"/v1/translate": "https://api.example.com/v1/translate",
} if os.getenv("ENV") == "production" else {}
app.add_middleware(X402Guard, client=client, routes=routes)
Error Handling
The middleware handles payment errors automatically. Additional route-level error handling:
from fastapi import FastAPI, HTTPException
from swiftpay.errors import SwiftPayError
@app.exception_handler(SwiftPayError)
async def swiftpay_error_handler(request, exc):
return JSONResponse(
status_code=402,
content={
"error": "payment_required",
"message": str(exc),
},
)
@app.get("/v1/analyze")
async def analyze(text: str):
try:
result = perform_analysis(text)
return {"sentiment": result.sentiment}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
Client Implementation
Your frontend clients need to handle the 402 response and submit payment:
async function makePaymentRequest(url: string, options?: RequestInit) {
// First request
let response = await fetch(url, options);
if (response.status === 402) {
// Extract payment requirements
const requirements = response.headers.get('x402-payment-requirements');
// User signs payment proof (using MetaMask, etc)
const signature = await window.ethereum.request({
method: 'eth_signTypedData_v4',
params: [userAddress, JSON.stringify(JSON.parse(requirements))],
});
// Second request with payment proof
response = await fetch(url, {
...options,
headers: {
...options?.headers,
'X-PAYMENT': signature,
},
});
}
return response;
}
Full API Reference
For complete configuration options, advanced error handling, and additional patterns, see the official x402 FastAPI Guard on PyPI.
All APIs are in v0.1.0-beta — stable and production-ready.