Cloudflare Worker
Put Penni in front of any website or API, wherever it is hosted, without touching its code.
The Worker sits in front of your origin. Priced paths need a payment; everything else is passed through untouched. Prices and test or live mode come from the dashboard, so changing them needs no redeploy. You need a Cloudflare account and Node.js 18 or later.
- In the dashboard, add a site, set your wallet, select a test token and add price rules, for example
/premium/**at0.01. Create an API key. - Get the Worker and install it:
Terminal
git clone https://github.com/tavbuilds/x402.git cd x402/integrations/cloudflare-worker npm install
- Set your site ID and origin in
wrangler.toml, and store the API key as a secret:
wrangler.toml
[vars] PENNI_SITE_ID = "site_..." ORIGIN_URL = "https://origin.example.com" # empty when the domain is already proxied by Cloudflare PENNI_WHO_PAYS = "everyone" # or "agents": people browse for free PENNI_EXEMPT_PATHS = "/favicon.ico,/robots.txt,/assets/**"
Terminal
npx wrangler secret put PENNI_API_KEY npx wrangler deploy
Two ways to reach your origin
| Mode | ORIGIN_URL | Use it when |
|---|---|---|
| Proxy | https://origin.example.com | The site runs anywhere (a VPS, Render, Fly, Vercel) and the Worker gets its own hostname. |
| Pass-through | empty | The domain is already proxied by Cloudflare and the Worker runs on a route like example.com/*. |
Settings
| Name | Default | What it does |
|---|---|---|
PENNI_WHO_PAYS | everyone | agents charges machine clients only and lets browsers through. |
PENNI_EXEMPT_PATHS | none | Patterns that are never charged and never ask Penni. |
PENNI_SETTLE | before | after fetches from the origin first and settles only on a 2xx. |
PENNI_ON_UNAVAILABLE | closed | Penni unreachable: closed answers 503, open serves for free. |
PENNI_AGENT_USER_AGENTS | none | Extra user agents that count as agents, comma-separated. |
What your origin receives
On a paid request the Worker adds X-Penni-Paid: 1, X-Penni-Payer, X-Penni-Network, X-Penni-Asset and X-Penni-Amount. It removes any X-Penni-* header a client sends. Trust these headers only if your origin can't be reached around the Worker.
Paid content never enters Cloudflare's cache. Settlements and problems show up in npx wrangler tail.