x402-starter
by Viraltbh
README.md
# x402-starter
**Paywall your Cloudflare Worker for AI agents in 5 minutes.**
Drop-in [x402](https://www.x402.org) starter. Agents pay per call in USDC — no signup, no API keys, no human in the loop. Comes with [Coinbase x402 Bazaar](https://www.x402.org) discoverability and an MCP manifest pre-wired so Coinbase-connected agents can find your API automatically.
## What you get out of the box
- A Cloudflare Worker that returns **HTTP 402 Payment Required** for paid routes until the caller settles a USDC micropayment
- Bazaar-discoverable routes (the non-obvious bit — without `discoverable: true` + schemas, even settled payments never list)
- A `/mcp` manifest so MCP clients and Coinbase AgentKit auto-discover your tools
- One example paid endpoint (`GET /api/echo`) you replace with your real API
- HTTPS-forced redirects, JSON-or-HTML root discovery, health check
## 5-minute quick start
```bash
git clone <this repo> my-paid-api
cd my-paid-api
npm install
npm run dev # paywall OFF by default — iterate locally
```
Hit `http://localhost:8787/api/echo?msg=hi` — you'll get a 200 with the echo. That's your free dev loop.
### Flip the paywall on (testnet)
1. Edit `wrangler.jsonc`:
```jsonc
"X402_ENABLED": "true",
"X402_NETWORK": "base-sepolia",
"PAY_TO": "0xYOUR_TESTNET_WALLET",
"PRICE_PER_CALL": "$0.01"
```
2. `npm run deploy`
3. Hit `/api/echo` — you'll get **HTTP 402** with the payment challenge.
`base-sepolia` uses the default public facilitator. **No keys needed.** This is the right setup for development and demos.
### Flip to mainnet (real USDC)
1. Get a Coinbase CDP Secret API key at [portal.cdp.coinbase.com](https://portal.cdp.coinbase.com).
2. Set the two secrets:
```bash
npx wrangler secret put CDP_API_KEY_ID # paste the key id when prompted
npx wrangler secret put CDP_API_KEY_SECRET # paste the secret when prompted
```
3. Set `X402_NETWORK` to `"base"` in `wrangler.jsonc`, set `PAY_TO` to your real Base wallet, and redeploy.
Without the CDP keys on mainnet, the 402 challenge still issues but **payments cannot settle**. Set both secrets before going live.
## Adding your own paid endpoints
Two places to edit `src/index.ts`:
1. **The handler** — add a route under `/api/*`:
```ts
app.get("/api/wash", async (c) => {
// your logic
return c.json({ ... });
});
```
2. **The paywall config** — add the same path to `routes` in `applyPaywall()` so it gets paywalled AND Bazaar-discoverable:
```ts
"/api/wash": {
price: env.PRICE_PER_CALL,
network: env.X402_NETWORK,
config: {
discoverable: true,
description: "Wash/sybil screen for any Base address",
inputSchema: { queryParams: { address: { type: "string" } } },
outputSchema: { type: "object", properties: { sybil_score: { type: "number" } } },
},
},
```
3. **The MCP manifest** — add a `tools[]` entry with the same `name`/`endpoint`/`price_usd` so MCP clients see it.
That's it. The middleware path matcher (`/api/*`) catches everything under `/api`, so only step 1 is structurally required — but skipping steps 2 and 3 means agents won't *find* your endpoint, which is most of the value.
## Going beyond echo
This template is intentionally minimal — one example endpoint, no business logic. The patterns it shows (Bazaar config, MCP manifest, free landing + JSON discovery, HTTPS forcing, lazy app build) are the load-bearing parts. Wire in your D1 / KV / Workers AI / Durable Objects as needed.
## Pricing
x402-hono accepts dollar-formatted strings: `"$0.01"`, `"$0.05"`, `"$1.00"`. Internally x402 settles in micro-USDC (six decimals), so `"$0.01"` becomes `10000` units. Different routes can charge different prices — set them per-route in the `routes` config.
## License
MIT. Use it, fork it, ship it.
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues