Skip to main content
Shows both integration patterns: site-wide middleware and per-route decorator.

Setup

pip install xenarch[fastapi] fastapi>=0.115.0 uvicorn>=0.30.0 python-dotenv
Create .env:
XENARCH_SITE_TOKEN=st_your_site_token
XENARCH_SITE_ID=your-site-uuid
XENARCH_ACCESS_TOKEN_SECRET=your_secret

Code

main.py
"""FastAPI publisher — gate AI agents behind Xenarch payments."""

import os

from dotenv import load_dotenv
from fastapi import FastAPI, Request

from xenarch.decorator import require_payment
from xenarch.middleware import XenarchMiddleware

load_dotenv()

SITE_TOKEN = os.environ["XENARCH_SITE_TOKEN"]
SITE_ID = os.environ["XENARCH_SITE_ID"]
ACCESS_TOKEN_SECRET = os.environ["XENARCH_ACCESS_TOKEN_SECRET"]

app = FastAPI(title="Xenarch Publisher Example")

# Pattern 1: Site-wide middleware
app.add_middleware(
    XenarchMiddleware,
    site_token=SITE_TOKEN,
    site_id=SITE_ID,
    access_token_secret=ACCESS_TOKEN_SECRET,
    excluded_paths={"/healthz", "/docs", "/openapi.json", "/"},
)

# Pattern 2: Per-route decorator
gate = require_payment(
    site_token=SITE_TOKEN,
    site_id=SITE_ID,
    access_token_secret=ACCESS_TOKEN_SECRET,
)


@app.get("/")
async def home():
    """Free — not gated."""
    return {"message": "Welcome! This content is free for everyone."}


@app.get("/healthz")
async def health():
    """Excluded from gating."""
    return {"status": "ok"}


@app.get("/articles")
async def articles():
    """Gated by site-wide middleware."""
    return {
        "articles": [
            {"title": "Understanding AI Payments", "id": 1},
            {"title": "Micropayments at Scale", "id": 2},
        ]
    }


@app.get("/premium")
@gate
async def premium(request: Request):
    """Gated by per-route decorator."""
    return {"content": "This is premium content worth paying for."}

Run

uvicorn main:app --reload

Test

# Human request — passes through
curl http://localhost:8000/

# Bot without token — returns 402
curl -H "User-Agent: GPTBot/1.0" http://localhost:8000/articles

# Bot with valid token — passes through
curl -H "User-Agent: GPTBot/1.0" \
     -H "Authorization: Bearer <access_token>" \
     http://localhost:8000/articles

Response examples

Free route:
{"message": "Welcome! This content is free for everyone."}
Bot without token (402):
{
  "xenarch": true,
  "gate_id": "...",
  "price_usd": "0.003",
  "splitter": "0xC6D3...",
  "collector": "0xabc1...",
  "network": "base",
  "asset": "USDC",
  "protocol": "x402",
  "verify_url": "https://xenarch.dev/v1/gates/.../verify"
}
Bot with valid token:
{"content": "This is premium content worth paying for."}