POST /x402/access. After payment, Key0 proxies the request and returns the backend’s response as a ResourceResponse.
Source: examples/ppr-standalone
What it demonstrates
proxyToonSellerConfigto enable standalone per-request gateway mode- Unified
/x402/accessendpoint handling both subscription (AccessGrant) and per-request (ResourceResponse) plans - Automatic payment header injection (
x-key0-tx-hash,x-key0-plan-id,x-key0-amount) so the backend can log/audit payments - A shared secret (
x-gateway-secret) that the backend uses to reject requests that bypass the gateway - Full HTTP, A2A, and MCP client support with no separate route registrations needed
PENDING → PAID → DELIVEREDstate transitions with refund safety when the backend returns non-2xx
Architecture
Key differences from embedded mode
| Embedded | Standalone | |
|---|---|---|
| Where Key0 runs | Inside your application | Separate gateway process |
| Route registration | app.get("/api/…", key0.payPerRequest()) | None — traffic via /x402/access |
| Backend call | Handler runs in-process | Key0 proxies to proxyTo.baseUrl |
| Response to client | Your handler’s response | ResourceResponse wrapper |
| A2A / MCP support | HTTP-only for per-request | Full A2A + MCP via /x402/access |
| Backend auth | N/A | Shared secret via proxyTo.headers |
Running locally
Prerequisites
- Bun v1.3+ or Node 18+
- Redis running locally
- A wallet address on Base Sepolia
- A gas wallet private key (ETH-funded) for settlement
Setup
Environment variables
| Variable | Description |
|---|---|
KEY0_WALLET_ADDRESS | Wallet that receives USDC payments |
GAS_WALLET_PRIVATE_KEY | ETH-funded wallet for settlement |
KEY0_NETWORK | "testnet" (default) or "mainnet" |
REDIS_URL | Redis connection URL (default: redis://localhost:6379) |
BACKEND_URL | Backend URL for proxying (default: http://localhost:3001) |
GATEWAY_SECRET | Shared secret injected as x-gateway-secret header |
GATEWAY_PORT | Gateway port (default: 3000) |
PUBLIC_URL | Public-facing gateway URL (used in agent card) |
Code walkthrough
1. Enable proxy mode with proxyTo
2. Client request (HTTP)
3. ResourceResponse shape
4. Backend receives payment headers
The backend receives these headers on every proxied request:5. Non-2xx backend response
If the backend returns 4xx/5xx, Key0 wraps it in aResourceResponse and the challenge stays in PAID state. The refund cron will process it:
A2A client flow
A2A agents use the same/x402/access endpoint with the X-A2A-Extensions header (Express only). The resource field is included in the AccessRequest data part:
ResourceResponse artifact.
MCP client flow
MCP clients (Claude Code, Cursor) call therequest_access tool with a resource field. Set mcp: true in SellerConfig to enable:
Next Steps
PPR Embedded Example
Per-request with Key0 inside your application.
SellerConfig: proxyTo
ProxyToConfig, FetchResourceParams, and FetchResourceResult types.
POST /x402/access
Full API reference for the unified payment endpoint.
Two Modes
When to use standalone vs. embedded.

