Protected Routes
Protected Routes allow you to require payment before users can access your API endpoints. Simply add the @require_payment decorator (Python) or requirePayment middleware (Node.js) to your endpoints, and the SDK handles everything—including automatic registration in your dashboard.
Overview
The Protected Routes feature enables:
- Code-First Configuration: Define protected routes in your code with the
@require_paymentdecorator - Auto-Registration: Routes automatically appear in your dashboard when your app starts
- SDK Enforcement: Automatic 402 responses and payment verification
- Hosted Checkout: Redirect users to
pay.orvion.shfor browser-based payments - Dashboard Management: Adjust pricing, pause routes, and view analytics
- Pattern Matching: Use wildcards to protect groups of endpoints
Routes are defined in code and auto-registered to the dashboard. The dashboard is used for pricing adjustments, monitoring, and analytics—not for creating routes.
How Protected Routes Work
Each Route Has Its Own Amount
Every protected route stores its own amount in the protected_routes table. When you define a route with @require_payment(amount="0.10"), that amount is registered and can be adjusted in the dashboard without code changes.
Payment Configuration: Routing Flows vs Standalone Charges
Protected routes can use two different payment mechanisms:
1. Routing Flows (Dynamic Configuration)
If you have an active routing flow with an api_request_entry node, the route will automatically use that flow for payment configuration. The routing flow determines:
- Network (e.g.,
solana-mainnet,base-mainnet) - Asset (e.g.,
USDC,ETH) - Payment Receiver (wallet address, facilitator, collection mode)
The route's amount is still used from the protected_routes table, but the payment configuration comes from the routing flow.
Use routing flows when:
- You want dynamic payment routing based on conditions
- You need different payment configurations for different scenarios
- You want A/B testing or conditional routing logic
2. Standalone Charges (Direct Configuration)
If there's no active routing flow, the route uses a standalone charge with:
- Amount: From the
protected_routestable - Currency: From the
protected_routestable - Payment Receiver: From the route's
receiver_config_id(or default receiver config)
Use standalone charges when:
- You have simple, fixed pricing
- You want direct control over payment configuration
- You don't need conditional routing logic
Summary
| Aspect | Routing Flow | Standalone Charge |
|--------|-------------|-------------------|
| Amount | From protected_routes table | From protected_routes table |
| Payment Config | From active routing flow | From route's receiver_config_id |
| Network/Asset | Determined by flow | Determined by receiver config |
| When Used | Active flow with api_request_entry node exists | No active routing flow |
The amount is always stored in the protected route, regardless of whether routing flows or standalone charges are used. This ensures consistent pricing that can be managed in the dashboard.
Quick Start
Choose your SDK to get started:
Python SDK
FastAPI integration with decorators
@require_paymentdecorator- Automatic route registration
- Type-safe payment info
Node.js SDK
Express middleware integration
requirePaymentmiddleware- TypeScript support
- Auto-registration
Basic Example (402 Mode)
from fastapi import FastAPI, Requestfrom orvion.fastapi import OrvionMiddleware, require_paymentapp = FastAPI()app.add_middleware(OrvionMiddleware, api_key=os.environ["ORVION_API_KEY"])@app.get("/api/premium")@require_payment(amount="0.10", currency="USDC")async def premium(request: Request):return {"data": "Premium content!"}
Hosted Checkout Mode
For web apps where users pay via browser, use hosted checkout to redirect to pay.orvion.sh:
@app.get("/premium")@require_payment(amount="1.00", currency="USDC", hosted_checkout=True)async def premium(request: Request):return {"data": "Premium content!"}
Hosted checkout requires configuring allowed domains in Settings → Domains. See the Hosted Checkout Guide for details.
View in Dashboard
Once your app starts and receives its first request, your protected routes automatically appear in Billing → Protected Routes with an "SDK" badge. From there you can:
- Adjust pricing without code changes
- Pause/unpause routes
- View payment analytics
- Monitor usage
Auto-Registration
When your app starts, the SDK automatically scans for protected endpoints and registers them with Orvion. This happens on the first request to your app.
- Python: Scans for
@require_paymentdecorated endpoints - Node.js: Scans for routes using
requirePaymentmiddleware - Multi-worker safe: Uses idempotent upserts—safe for Gunicorn, PM2, etc.
Routes are automatically registered and appear in your dashboard. No manual configuration needed!
For detailed registration options, see the Python SDK or Node.js SDK pages.
Route Pattern Syntax
Protected routes support two pattern types:
Exact Match
/api/reports/generate
Matches only this exact path.
Wildcard (Prefix) Match
/api/premium/*
Matches any path starting with /api/premium/:
- ✅
/api/premium/data - ✅
/api/premium/users/123 - ❌
/api/premiumX - ❌
/api/premium(no trailing content)
Note: Wildcards are only allowed at the end of patterns.
Priority Rules
When multiple routes could match a request, the most specific one wins:
- Exact path + Exact method (highest priority)
- Exact path + Wildcard method (*)
- Wildcard path + Exact method
- Wildcard path + Wildcard method (*) (lowest priority)
For wildcard paths with the same specificity, longer prefixes take priority.
Example
Given these routes:
/api/premium/*(method:*, price: $0.10)/api/premium/data(method:GET, price: $0.25)
A GET /api/premium/data request uses the $0.25 price (exact path + exact method beats wildcard path).
SDK Guides
For detailed SDK configuration and examples, see:
- Python SDK Guide - FastAPI decorators, middleware setup, and examples
- Node.js SDK Guide - Express middleware, TypeScript types, and examples
Dashboard Management
Once routes are auto-registered, you can manage them in the dashboard:
What You Can Edit
- Price: Adjust amount and currency without code changes
- Status: Pause/unpause routes to temporarily disable payment requirements
- Allow Anonymous: Toggle whether requests without customer ID are allowed
What's Read-Only
- Route Pattern: The URL path (defined in code)
- HTTP Method: GET, POST, etc. (defined in code)
- Source: Shows "SDK" for auto-registered routes
Route Source Badges
| Badge | Meaning |
|-------|---------|
| SDK | Auto-registered from @require_payment decorator |
| Manual | Created via API (deprecated) |
API Reference
See the API Reference for complete endpoint documentation, request/response schemas, and examples.
Security Considerations
Anonymous Requests
By default, routes allow anonymous requests (no customer identifier). To prevent abuse:
- Set
allow_anonymous: falsein the dashboard - Or use
allow_anonymous=Falsein the decorator
When disabled, requests without a customer ID receive a 400 error instead of creating a charge.
Resource Reference
Each charge includes a resource_ref of protected_route:{route_id}. This prevents:
- Reusing a payment for one route on a different route
- Paying for a cheap endpoint and accessing an expensive one
Advanced Topics
Caching
SDKs cache route configurations for 60 seconds by default. Changes in the dashboard take up to 60 seconds to take effect. See SDK-specific pages for cache management.
Security
- Anonymous Requests: By default, routes allow anonymous requests. Set
allow_anonymous: falseto require customer identification. - Resource Reference: Each charge includes a
resource_refto prevent payment reuse across different routes.
Troubleshooting
Common issues and solutions:
- Route not appearing: Check decorator order, ensure middleware is configured, wait for first request
- 500 error: Middleware not configured or route scanning failed
- Payment verification failing: Check transaction headers and charge status
For detailed troubleshooting, see the Python SDK or Node.js SDK pages.