Python SDK
The Orvion Python SDK provides seamless integration with FastAPI for creating payment-protected API endpoints using the x402 protocol.
Installation
pip install orvion
Quick Start
from fastapi import FastAPI, Request
from orvion.fastapi import OrvionMiddleware, require_payment
import os
app = FastAPI()
# Add the middleware
app.add_middleware(
OrvionMiddleware,
api_key=os.environ["ORVION_API_KEY"],
)
# Protect an endpoint
@app.get("/api/premium")
@require_payment(amount="0.10", currency="USDC")
async def premium(request: Request):
return {"message": "Premium content!"}
OrvionMiddleware
The middleware handles route registration, payment verification, and request state management.
Configuration
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| api_key | str | Optional | Your Orvion API key (required) | — |
| base_url | str? | Optional | Custom API base URL (default: https://api.orvion.sh) | — |
| cache_ttl_seconds | float | Optional | Route cache TTL (default: 60.0) | — |
| transaction_header | str | Optional | Header for transaction ID (default: 'X-Transaction-Id') | — |
| customer_header | str | Optional | Header for customer ID (default: 'X-Customer-Id') | — |
| register_on_first_request | bool | Optional | Auto-register routes on first request (default: True) | — |
Example
app.add_middleware(
OrvionMiddleware,
api_key=os.environ["ORVION_API_KEY"],
cache_ttl_seconds=120.0, # Cache routes for 2 minutes
transaction_header="X-Payment-Id", # Custom header name
)
@require_payment Decorator
Mark endpoints as payment-protected with configurable pricing.
Parameters
| Field | Type | Required | Description | Example |
|---|---|---|---|---|
| amount | str? | Optional | Price per request (e.g., '0.10') | — |
| currency | str | Optional | Currency code (default: 'USD') | — |
| name | str? | Optional | Friendly name for dashboard/402 response | — |
| description | str? | Optional | Description shown in 402 response | — |
| allow_anonymous | bool? | Optional | Allow requests without customer ID (default: True) | — |
| customer_resolver | Callable? | Optional | Function to extract customer ID from request | — |
| hosted_checkout | bool | Optional | Redirect to pay.orvion.sh instead of 402 (default: False) | — |
| return_url | str? | Optional | Return URL after hosted checkout payment | — |
Always place @require_payment under @app.get/@app.post. The decorator order matters!
Examples
# Basic usage
@app.get("/api/basic")
@require_payment(amount="0.01", currency="USDC")
async def basic_endpoint(request: Request):
return {"data": "..."}
# With metadata
@app.get("/api/premium")
@require_payment(
amount="1.00",
currency="USDC",
name="Premium API Access",
description="Full access to premium features",
)
async def premium_endpoint(request: Request):
return {"data": "..."}
# Hosted checkout mode
@app.get("/premium")
@require_payment(
amount="1.00",
currency="USDC",
hosted_checkout=True,
)
async def premium_hosted(request: Request):
return {"message": "Premium content!"}
Pre-built Payment Router (NEW in v0.2)
The SDK provides a pre-built router that adds all payment endpoints automatically - no boilerplate needed!
Usage
from orvion import OrvionClient
from orvion.fastapi import create_payment_router
client = OrvionClient(api_key=os.environ["ORVION_API_KEY"])
# Add all payment endpoints with one line!
app.include_router(
create_payment_router(client),
prefix="/api/payments",
)
This adds the following endpoints:
| Endpoint | Method | Description |
|----------|--------|-------------|
| /api/payments/confirm | POST | Confirm wallet payment with tx_hash |
| /api/payments/cancel/{id} | POST | Cancel a pending charge |
| /api/payments/state/{id} | GET | Get charge state for payment widgets |
| /api/payments/charge/{id} | GET | Get full charge details |
Available Routers
from orvion.fastapi import (
create_payment_router, # Payment operations
create_health_router, # Health check endpoint
create_full_router, # All endpoints combined
)
# Payment router only
app.include_router(create_payment_router(client), prefix="/api/payments")
# Health router only
app.include_router(create_health_router(client), prefix="/api")
# Combined router (payments + health)
app.include_router(create_full_router(client), prefix="/api/orvion")
OrvionClient
The client provides direct API access for all payment operations.
New Methods (v0.2)
from orvion import OrvionClient
async with OrvionClient(api_key="your-api-key") as client:
# Health check & API key validation
health = await client.health_check()
print(f"Organization: {health.organization_id}")
print(f"API Key Valid: {health.api_key_valid}")
# Create a charge
charge = await client.create_charge(
amount="0.10",
currency="USDC",
description="API access",
)
# Get charge details
charge = await client.get_charge(charge.id)
# Get charge state (optimized for UI widgets)
state = await client.get_charge_state(charge.id)
print(f"Status: {state.status}")
print(f"Recipient: {state.recipient_address}")
# Confirm wallet payment
result = await client.confirm_payment(
transaction_id=charge.id,
tx_hash="blockchain_tx_signature...",
)
print(f"Success: {result.success}")
# Cancel a pending charge
cancelled = await client.cancel_charge(charge.id)
# Verify a payment
result = await client.verify_charge(
transaction_id=charge.id,
resource_ref="my-resource",
)
All Client Methods
| Method | Description |
|--------|-------------|
| create_charge() | Create a new payment charge |
| verify_charge() | Verify a payment transaction |
| get_charge() | Get charge details by ID |
| get_charge_state() | Get UI-optimized charge state |
| confirm_payment() | Confirm wallet payment with tx_hash |
| cancel_charge() | Cancel a pending charge |
| health_check() | Validate API key & get org info |
| get_routes() | Get protected route configurations |
| match_route() | Match a request to a protected route |
| register_route() | Register a new protected route |
Models
Core Models
from orvion import (
Charge, # Payment charge
VerifyResult, # Payment verification result
PaymentInfo, # Payment info attached to request
RouteConfig, # Protected route configuration
)
New Models (v0.2)
from orvion import (
ConfirmResult, # Result of wallet payment confirmation
ChargeState, # UI state for payment widgets
HealthInfo, # API health & organization info
WalletPaymentInfo, # Wallet payment details
PaymentMethodInfo, # Available payment methods
)
Example: Parsing Payment Methods
from orvion import PaymentMethodInfo
# Parse payment methods from x402_requirements
charge = await client.create_charge(amount="0.10", currency="USDC")
methods = PaymentMethodInfo.from_x402_requirements(charge.x402_requirements)
print(f"Available methods: {methods.methods}") # ["solana"]
if methods.solana:
print(f"Recipient: {methods.solana.recipient_address}")
print(f"Token: {methods.solana.token_address}")
print(f"Amount: {methods.solana.amount}")
Route Registration
Routes are automatically registered with Orvion when your app starts.
Default: First Request
By default, routes register on the first request to your app:
app.add_middleware(
OrvionMiddleware,
api_key=API_KEY,
# register_on_first_request=True (default)
)
Explicit Startup Registration
For immediate registration at startup, use sync_routes() in your lifespan:
from contextlib import asynccontextmanager
from orvion import OrvionClient
from orvion.fastapi import OrvionMiddleware, sync_routes
@asynccontextmanager
async def lifespan(app: FastAPI):
client = OrvionClient(api_key=os.environ["ORVION_API_KEY"])
# Verify API key on startup
health = await client.health_check()
if health.api_key_valid:
print(f"✓ Connected to org: {health.organization_id}")
# Register all protected routes
count = await sync_routes(app, client)
print(f"✓ Registered {count} protected routes")
yield
await client.close()
app = FastAPI(lifespan=lifespan)
app.add_middleware(
OrvionMiddleware,
api_key=os.environ["ORVION_API_KEY"],
register_on_first_request=False, # Already synced
)
Complete Example (Minimal)
This example shows how thin your app can be with the SDK:
from fastapi import FastAPI, Request
from orvion import OrvionClient
from orvion.fastapi import (
OrvionMiddleware,
require_payment,
create_payment_router,
)
import os
app = FastAPI()
client = OrvionClient(api_key=os.environ["ORVION_API_KEY"])
# Add middleware
app.add_middleware(OrvionMiddleware, api_key=os.environ["ORVION_API_KEY"])
# Add pre-built payment router (confirm, cancel, state, charge endpoints)
app.include_router(create_payment_router(client), prefix="/api/payments")
# Protected endpoint - that's it!
@app.get("/api/premium")
@require_payment(amount="0.01", currency="USDC")
async def premium(request: Request):
return {"access": "granted", "message": "Welcome to premium!"}
Error Handling
from orvion import OrvionClient, OrvionAPIError, OrvionAuthError
try:
client = OrvionClient(api_key="your-api-key")
charge = await client.create_charge(amount="0.10", currency="USDC")
except OrvionAuthError:
print("Invalid API key")
except OrvionAPIError as e:
print(f"API Error: {e.status_code} - {e.message}")
except Exception as e:
print(f"Unexpected error: {e}")
Related Documentation
- Protected Routes - Full protected routes guide
- Protected Routes - Python - FastAPI integration details
- Hosted Checkout - Redirect-based payment flow
- Charges API - Low-level charge creation
- API Keys - Managing API keys