examples/ppr-embedded
What it demonstrates
- Defining
mode: "per-request"plans alongsidefetchResourceCredentials(required for the/x402/accessendpoint, though not called for per-request routes) - Using
key0.payPerRequest(planId, opts?)middleware to gate individual routes - Accessing
req.key0Payment(containingtxHash,planId,amount,challengeId) in route handlers - Discovery via
GET /discoveryand agent card showing per-request skills with route metadata - Automatic
PENDING → PAID → DELIVEREDstate transitions with refund safety (pass astoreto enable)
Architecture
Key differences from subscription mode
| Subscription | Per-Request (Embedded) | |
|---|---|---|
| Response | AccessGrant (JWT) | Your route handler’s response |
| Token issued | Yes | No |
| Follow-up auth | Bearer JWT needed for each call | Each call includes PAYMENT-SIGNATURE |
| Route protection | validateAccessToken middleware | key0.payPerRequest() middleware |
| Payment metadata | In IssueTokenParams callback | In req.key0Payment |
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 self-contained settlement
Setup
http://localhost:3000.
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) |
PORT | Server port (default: 3000) |
PUBLIC_URL | Public-facing server URL (used in agent card) |
Code walkthrough
1. Define plans with mode: "per-request"
2. Mount key0Router and gate routes
3. Discovery response
Agents callGET /discovery and see per-request plans with their routes:
/.well-known/agent.json includes these as skills with "pay-per-request" tags.
Testing with curl
Extending the example
- Add more routes with different plans
- Use
req.key0Payment.challengeIdfor your own audit records - Pass
storetokey0.payPerRequest()to enable refund safety on per-request routes (when settlement succeeds but the handler crashes) - Combine with subscription plans on the same server — agents can use both flows
Next Steps
PPR Standalone Example
Key0 as a gateway that proxies to a separate backend service.
Express Integration
Full reference for key0Router and payPerRequest options.
SellerConfig Reference
Plan mode, routes, and ProxyToConfig type definitions.
Building a Seller
End-to-end guide from install to production.

