Install

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.

  1. In the dashboard, add a site, set your wallet, select a test token and add price rules, for example /premium/** at 0.01. Create an API key.
  2. Get the Worker and install it:
Terminal
git clone https://github.com/tavbuilds/x402.git
cd x402/integrations/cloudflare-worker
npm install
  1. 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

ModeORIGIN_URLUse it when
Proxyhttps://origin.example.comThe site runs anywhere (a VPS, Render, Fly, Vercel) and the Worker gets its own hostname.
Pass-throughemptyThe domain is already proxied by Cloudflare and the Worker runs on a route like example.com/*.

Settings

NameDefaultWhat it does
PENNI_WHO_PAYSeveryoneagents charges machine clients only and lets browsers through.
PENNI_EXEMPT_PATHSnonePatterns that are never charged and never ask Penni.
PENNI_SETTLEbeforeafter fetches from the origin first and settles only on a 2xx.
PENNI_ON_UNAVAILABLEclosedPenni unreachable: closed answers 503, open serves for free.
PENNI_AGENT_USER_AGENTSnoneExtra 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.