Gate an existing API (proxy)
The idea
Section titled “The idea”Already have an API, in Python, Go, Rails, anything? You don’t have to rewrite it to charge for it.
proxyTo(origin) is a ready-made handler that forwards a paid request to your existing backend,
untouched, and rejects unpaid ones before they ever reach it. Deploy it on the edge in front of
your API; the API never changes and never sees an unpaid request.
import { createPaywall, toWorker, proxyTo } from '@piprail/sdk'
const gate = createPaywall({ chain: 'base', amount: '0.01', payTo: '0xYourWallet' })
// A Cloudflare Worker that charges 0.01 USDC per request to https://api.example.com:export default toWorker(gate, proxyTo('https://api.example.com'))proxyTo preserves the method, path, query, body, and headers; it strips the x402 proof headers so
they don’t leak upstream. The origin only ever receives requests that have already paid. An unpaid
request gets a 402 and never reaches your backend.
Scaffold it
Section titled “Scaffold it”The fastest way is the scaffolder’s proxy mode, which generates a complete, mainnet-default edge proxy:
npm create @piprail -- my-gateway \ --sell proxy \ --origin https://api.example.com \ --host cloudflare \ --pay-to 0xYourPublicAddress \ --amount 0.01The generated worker forwards paid traffic to your origin and serves /.well-known/x402 so AI agents
can discover and price it. → Scaffold a merchant
How it compares
Section titled “How it compares”Cloudflare ships an x402-proxy template too, but it defaults to testnet and routes settlement
through a facilitator. PipRail’s proxy is mainnet-default and facilitator-free: it verifies
each payment locally against your own RPC, and receiving needs only your public address: no key, no
account, no middleman.
- The proxy is edge-only (Cloudflare Workers / Vercel Edge Functions), because that’s where a low-latency
forward belongs. For a Node/Express app you own, gate the route directly with
requirePaymentinstead. - It gates every path. Carve out free routes by checking
new URL(request.url).pathnamebefore the gate, exactly like the scaffolded/.well-known/x402route does. proxyTocomposes with both framework adapters:toWorker(gate, proxyTo(origin))for the{ fetch }export, ortoFetchHandler(gate, proxyTo(origin))for a bare handler.