agent402-tollbooth 0.9.2 → 0.9.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +54 -18
  2. package/index.js +21 -4
  3. package/package.json +5 -1
package/README.md CHANGED
@@ -10,17 +10,12 @@ The first self-hostable pay-per-crawl gate that speaks both wires on one 402 -
10
10
  the sell side of [Agentic Finance](https://agent402.tools/agentic-finance),
11
11
  where agents pay and sites get paid, per request, with no account in between.
12
12
 
13
- The big platforms are converging on the same model: Cloudflare's
14
- [pay-per-crawl](https://stackoverflow.blog/2026/02/26/how-pay-per-crawl-is-reshaping-data-monetization/)
15
- and now its [Monetization Gateway](https://blog.cloudflare.com/monetization-gateway/)
16
- (launched July 2026 - x402 charging in USDC on Base for anything behind Cloudflare:
17
- pages, APIs, datasets, MCP tools) confirm that pay-per-request is the business model
18
- of the agentic web. Tollbooth is the **open-source monetization gateway**: the same
19
- idea, but MIT-licensed and live today, running in
20
- front of *any* origin (even a Cloudflare Worker), non-custodial (you hold the wallet,
21
- no signup or Merchant-of-Record), and - the wedge the platform gateways don't offer -
22
- with a **proof-of-work free tier** so a walletless agent still has a path through.
23
- Built on the same hardened 402 + proof-of-work machinery as
13
+ Tollbooth is an **open-source monetization gateway**: MIT-licensed, running in
14
+ front of *any* origin (Express, a reverse proxy, Next.js, a Cloudflare Worker),
15
+ non-custodial (you hold the wallet, no signup or Merchant-of-Record), settling
16
+ over x402 and MPP on one 402 - including native MPP on Tempo with split
17
+ payments - and with a **proof-of-work free tier** so a walletless agent still
18
+ has a path through. Built on the same hardened 402 + proof-of-work machinery as
24
19
  [Agent402](https://github.com/MikeyPetrillo/Agent402).
25
20
 
26
21
  ## See it work (one command)
@@ -123,8 +118,7 @@ must pay, or `null` to let it through.
123
118
  **Ready-to-deploy templates** (copy a folder, don't assemble from docs):
124
119
 
125
120
  - **Cloudflare Workers** → [`deploy/cloudflare/`](deploy/cloudflare/) - a ready
126
- `wrangler.toml` + a 3-step deploy guide (the open pay-per-crawl, on the
127
- incumbent's own platform).
121
+ `wrangler.toml` + a 3-step deploy guide.
128
122
  - **Next.js / Vercel** → [`deploy/nextjs/`](deploy/nextjs/) - a drop-in
129
123
  `middleware.js` + a 3-step deploy guide.
130
124
  - **Docker** → [`deploy/docker/`](deploy/docker/) - a `Dockerfile` +
@@ -162,8 +156,8 @@ export const config = { matcher: ["/((?!_next/static|_next/image|favicon.ico).*)
162
156
  > On the edge, pass a stable `secret` (PoW tokens are HMAC-signed). For
163
157
  > single-use replay protection across stateless invocations, supply a `store`
164
158
  > (e.g. a Cloudflare KV wrapper - the Worker entry wires this for you).
165
- > The `x402:` middleware mode and MPP are Node/Express features today; the
166
- > edge gate offers proof-of-work plus the `verifyX402` callback.
159
+ > The `x402:` middleware mode, MPP and the native Tempo rail are Node/Express
160
+ > features today; the edge gate offers proof-of-work plus the `verifyX402` callback.
167
161
 
168
162
  ## Accepting USDC: x402 and MPP on the same 402
169
163
 
@@ -240,9 +234,21 @@ app.use(createTollbooth({
240
234
  }));
241
235
  ```
242
236
 
237
+ The `tempo` object takes `apiKey` (required), `recipient` (required, your
238
+ Tempo payTo), `currency` or `currencies` (TIP-20 token addresses; default USDC.e
239
+ `0x20C000000000000000000000b9537d11c60E8b50`, one challenge minted per currency,
240
+ first = preferred), `splits` (up to 10, total below the price, same transaction),
241
+ `chainId` (default 4217, Tempo mainnet), `apiBaseUrl` (relay, default
242
+ `https://api.tempo.xyz`), `decimals` (6), `timeoutSeconds` (300), plus the
243
+ confirm knobs below. A bad config throws at construction - the gate never boots
244
+ minting unpayable challenges.
245
+
243
246
  Or from env on the CLI: `TOLLBOOTH_TEMPO_API_KEY`, `TOLLBOOTH_TEMPO_RECIPIENT`
244
- (defaults to `TOLLBOOTH_PAYTO`), optional `TOLLBOOTH_TEMPO_CURRENCY`,
245
- `TOLLBOOTH_TEMPO_SPLITS="0xabc:0.0002,0xdef:0.0001"`.
247
+ (defaults to `TOLLBOOTH_PAYTO`), optional `TOLLBOOTH_TEMPO_CURRENCY` (CSV of
248
+ token addresses), `TOLLBOOTH_TEMPO_SPLITS="0xabc:0.0002,0xdef:0.0001"`,
249
+ `TOLLBOOTH_TEMPO_API_BASE` (relay override), `TOLLBOOTH_TEMPO_RPC_URL` (confirm
250
+ RPC override). Tempo works with NO x402 middleware at all (a Tempo-only
251
+ tollbooth) and next to one.
246
252
 
247
253
  Every 402 then carries a `WWW-Authenticate: Payment` tempo/charge challenge
248
254
  (next to any evm challenges from the x402 rail, if you run both); a stock
@@ -293,6 +299,9 @@ live incident transaction in the tests).
293
299
  | `mpp` | `true` when `x402` set | Accept MPP (`WWW-Authenticate: Payment` / `Authorization: Payment`) through the `x402` middleware |
294
300
  | `mppSecret` | `powSecret` / `TOLLBOOTH_SECRET` | HMAC secret binding MPP challenge ids (stable across workers) |
295
301
  | `mppNetworks` | `[8453, 42220]` | EVM chain ids to offer as MPP challenges (`"all"` = every EVM chain the middleware advertises) |
302
+ | `tempo` | env (`TOLLBOOTH_TEMPO_*`) or off | Native MPP on Tempo (0.9.0): `{ apiKey, recipient, currency \| currencies, splits, chainId, apiBaseUrl, decimals, timeoutSeconds, confirm, confirmRpcUrl }` - mints `tempo/charge` challenges, validates with Tempo's relay before the handler, broadcasts after a <400 response. Works with or without `x402` |
303
+ | `tempo.confirm` | `true` | Chain-truth confirm (0.9.2): on a relay broadcast failure, check the chain for the credential's own txid before answering 402; `false` disables |
304
+ | `tempo.confirmRpcUrl` | `https://rpc.tempo.xyz` (`TOLLBOOTH_TEMPO_RPC_URL`) | Tempo JSON-RPC used by the confirm step |
296
305
  | `verifyX402(req, opts)` | – | Legacy verify-only USDC check (deprecated for settle-after-handler middlewares; see above) |
297
306
  | `resourceBaseUrl` | `""` | Absolute base used for the `resource` field / PoW binding |
298
307
  | `observe` | `false` | Observe-only: classify and count, but never 402. For pre-launch traffic measurement. |
@@ -309,11 +318,18 @@ Read by the bundled proxy / Express entry point (`index.js`):
309
318
  | `TOLLBOOTH_PAYTO` | – | Wallet address; advertises a USDC x402 quote (and, with `TOLLBOOTH_FACILITATOR_URL`, settles it) |
310
319
  | `TOLLBOOTH_FACILITATOR_URL` | – | x402 facilitator that settles your network. With `TOLLBOOTH_PAYTO` the CLI builds a real `@x402/express` middleware and takes payment over x402 **and** MPP (0.8.0). Needs `@x402/express @x402/core @x402/evm` installed; refuses to start without them |
311
320
  | `TOLLBOOTH_FACILITATOR_HEADERS` | – | Optional JSON object of auth headers sent on the facilitator's `/verify`, `/settle`, `/supported` (e.g. `{"X-API-Key":"…"}`) |
321
+ | `TOLLBOOTH_CDP_API_KEY_ID` + `TOLLBOOTH_CDP_API_KEY_SECRET` | – | Settle through Coinbase's facilitator (CDP) instead of a URL: fee-free on Base, and the endpoint is indexed in Coinbase's x402 Bazaar. Needs `npm i @coinbase/x402`. This is how a Coinbase Business account gets paid by agents: `TOLLBOOTH_PAYTO` = the account's USDC (Base) receive address. |
312
322
  | `TOLLBOOTH_PRICE` | `"$0.001"` | Advertised price per request |
313
323
  | `TOLLBOOTH_NETWORK` | `"base"` | x402 network. CLI settlement mode accepts `base`, `base-sepolia`, `polygon`, `arbitrum`, `optimism`, `avalanche`, `celo`, `sei`, `monad`, or a raw `eip155:<id>` |
314
324
  | `TOLLBOOTH_MPP` | on when `x402` set | `false` to switch MPP off |
315
325
  | `TOLLBOOTH_MPP_SECRET` | `TOLLBOOTH_SECRET` | HMAC secret for MPP challenge ids |
316
326
  | `TOLLBOOTH_MPP_NETWORKS` | `8453,42220` | CSV of EVM chain ids to offer as MPP challenges, or `all` |
327
+ | `TOLLBOOTH_TEMPO_API_KEY` | – | Tempo API key (`mpp:write` scope). Presence switches on the native Tempo rail (0.9.0) |
328
+ | `TOLLBOOTH_TEMPO_RECIPIENT` | `TOLLBOOTH_PAYTO` | Tempo payTo (0x address) |
329
+ | `TOLLBOOTH_TEMPO_CURRENCY` | USDC.e on Tempo | CSV of TIP-20 token addresses to offer (one challenge each, first = preferred) |
330
+ | `TOLLBOOTH_TEMPO_SPLITS` | – | `0xabc:0.0002,0xdef:0.0001` - split recipients + USD amounts paid in the same transaction (≤10, total below the price) |
331
+ | `TOLLBOOTH_TEMPO_API_BASE` | `https://api.tempo.xyz` | Tempo relay base URL override |
332
+ | `TOLLBOOTH_TEMPO_RPC_URL` | `https://rpc.tempo.xyz` | Tempo JSON-RPC for the chain-truth confirm step (0.9.2) |
317
333
  | `TOLLBOOTH_ASSET` | `"USDC"` | Asset symbol in the quote (`USDG` charges in USDG on Robinhood Chain) |
318
334
  | `TOLLBOOTH_POW_BITS` | `18` | Proof-of-work difficulty in leading zero bits |
319
335
  | `TOLLBOOTH_MODE` | `"bots"` | Who pays: `bots` · `all` · `strict` |
@@ -381,7 +397,7 @@ changes. Bots see a `X-Tollbooth-Observed: would-charge` header in observe mode
381
397
  ## Analytics
382
398
 
383
399
  The middleware keeps aggregate counters (no per-request data):
384
- - `gate.stats()` → sync, in-process mirror: `{ requests, freeAllowed, wouldCharge, charged, powSolved, x402Paid, mppPaid, difficultyNow, observe }`.
400
+ - `gate.stats()` → sync, in-process mirror: `{ requests, freeAllowed, wouldCharge, charged, powSolved, x402Paid, mppPaid, tempoPaid, difficultyNow, observe }`.
385
401
  - `gate.snapshot()` → async, reads from the configured durable sink (defaults to memory).
386
402
  - `gate.flush()` → flush any buffered deltas to the durable sink (call inside `ctx.waitUntil` on edge runtimes).
387
403
 
@@ -585,3 +601,23 @@ Celo by default - what a stock mppx client can sign); add `4663` there or pass
585
601
  ## Legal
586
602
 
587
603
  Use of the hosted instance at agent402.tools is subject to its [Terms of Service](https://agent402.tools/terms) (acceptable-use policy included) and [Privacy Policy](https://agent402.tools/privacy). This package is MIT-licensed; the hosted server is AGPL-3.0. Both are provided as-is without warranty, and self-hosted deployments are their operator's responsibility.
604
+
605
+ ## Get paid into a Coinbase Business account
606
+
607
+ Coinbase Business accounts receive x402 payments from AI agents directly. The
608
+ tollbooth is the "integrate x402 into your API" step: point `TOLLBOOTH_PAYTO`
609
+ at the account's USDC receive address on Base and settle through Coinbase's
610
+ facilitator with a CDP API key.
611
+
612
+ ```bash
613
+ npm i agent402-tollbooth @x402/express @x402/core @x402/evm @coinbase/x402
614
+ TOLLBOOTH_PAYTO=0xYourCoinbaseBusinessBaseAddress \
615
+ TOLLBOOTH_CDP_API_KEY_ID=... TOLLBOOTH_CDP_API_KEY_SECRET=... \
616
+ TOLLBOOTH_PRICE='$0.005' TOLLBOOTH_UPSTREAM=http://localhost:8080 \
617
+ npx agent402-tollbooth
618
+ ```
619
+
620
+ Every paid request settles as USDC into the Coinbase Business account; humans
621
+ browse your site normally. Full walkthrough with an Express example:
622
+ https://agent402.tools/guides/coinbase-business-get-paid-by-agents
623
+
package/index.js CHANGED
@@ -686,9 +686,16 @@ export const CLI_NETWORKS = {
686
686
  export async function buildCliX402Middleware(env = process.env) {
687
687
  const payTo = env.TOLLBOOTH_PAYTO || "";
688
688
  const facilitatorUrl = env.TOLLBOOTH_FACILITATOR_URL || "";
689
+ // Coinbase's facilitator (CDP) authenticates every verify/settle call with
690
+ // a short-lived JWT signed by a CDP API key, so a static header cannot
691
+ // reach it; @coinbase/x402's createFacilitatorConfig mints them. With the
692
+ // two keys set the CLI settles through CDP (fee-free on Base, and the
693
+ // endpoint is indexed in Coinbase's x402 Bazaar), no URL needed. This is
694
+ // the path a Coinbase Business account uses to get paid by agents.
695
+ const cdpKeys = env.TOLLBOOTH_CDP_API_KEY_ID && env.TOLLBOOTH_CDP_API_KEY_SECRET;
689
696
  if (!payTo) return null;
690
- if (!facilitatorUrl) {
691
- console.warn("⚠ TOLLBOOTH_PAYTO is set without TOLLBOOTH_FACILITATOR_URL: the 402 advertises a USDC quote but nothing here can verify or settle a payment, so every paid request is refused. Set TOLLBOOTH_FACILITATOR_URL (a public x402 facilitator that settles your network - keyless free tiers exist; https://x402.org/facilitator for base-sepolia) to actually charge, over x402 and MPP.");
697
+ if (!facilitatorUrl && !cdpKeys) {
698
+ console.warn("⚠ TOLLBOOTH_PAYTO is set without TOLLBOOTH_FACILITATOR_URL (or TOLLBOOTH_CDP_API_KEY_ID/SECRET): the 402 advertises a USDC quote but nothing here can verify or settle a payment, so every paid request is refused. Set TOLLBOOTH_FACILITATOR_URL (a public x402 facilitator that settles your network - keyless free tiers exist; https://x402.org/facilitator for base-sepolia) to actually charge, over x402 and MPP.");
692
699
  return null;
693
700
  }
694
701
  const asset = (env.TOLLBOOTH_ASSET || "USDC").toUpperCase();
@@ -717,7 +724,17 @@ export async function buildCliX402Middleware(env = process.env) {
717
724
  if (env.TOLLBOOTH_FACILITATOR_HEADERS) {
718
725
  try { authHeaders = JSON.parse(env.TOLLBOOTH_FACILITATOR_HEADERS); } catch { console.error("✖ TOLLBOOTH_FACILITATOR_HEADERS must be a JSON object of header name -> value. Refusing to start."); process.exit(1); }
719
726
  }
720
- const client = new HTTPFacilitatorClient({
727
+ let cdpConfig = null;
728
+ if (cdpKeys) {
729
+ try {
730
+ const { createFacilitatorConfig } = await import("@coinbase/x402");
731
+ cdpConfig = createFacilitatorConfig(env.TOLLBOOTH_CDP_API_KEY_ID, env.TOLLBOOTH_CDP_API_KEY_SECRET);
732
+ } catch (e) {
733
+ console.error(`✖ TOLLBOOTH_CDP_API_KEY_ID/SECRET are set, so this gate must settle through Coinbase's facilitator, but @coinbase/x402 is not installed (${String(e?.message || e).slice(0, 120)}). Install it: npm install @coinbase/x402`);
734
+ process.exit(1);
735
+ }
736
+ }
737
+ const client = new HTTPFacilitatorClient(cdpConfig || {
721
738
  url: facilitatorUrl,
722
739
  ...(authHeaders ? { createAuthHeaders: async () => ({ verify: authHeaders, settle: authHeaders, supported: authHeaders }) } : {}),
723
740
  });
@@ -857,7 +874,7 @@ async function startCli() {
857
874
  app.use((_req, res) => res.json({ ok: true, note: "Bare tollbooth gate (no TOLLBOOTH_UPSTREAM set). Clients that reach here paid or solved a proof-of-work." }));
858
875
  }
859
876
  app.listen(port, () => {
860
- const paidLabel = x402mw ? `x402 + MPP (${process.env.TOLLBOOTH_ASSET || "USDC"}, settling via ${process.env.TOLLBOOTH_FACILITATOR_URL})` : (process.env.TOLLBOOTH_PAYTO ? `x402 quote only (${process.env.TOLLBOOTH_ASSET || "USDC"}, NOT settling - set TOLLBOOTH_FACILITATOR_URL)` : "");
877
+ const paidLabel = x402mw ? `x402 + MPP (${process.env.TOLLBOOTH_ASSET || "USDC"}, settling via ${process.env.TOLLBOOTH_CDP_API_KEY_ID && process.env.TOLLBOOTH_CDP_API_KEY_SECRET ? "Coinbase CDP" : process.env.TOLLBOOTH_FACILITATOR_URL})` : (process.env.TOLLBOOTH_PAYTO ? `x402 quote only (${process.env.TOLLBOOTH_ASSET || "USDC"}, NOT settling - set TOLLBOOTH_FACILITATOR_URL)` : "");
861
878
  const rails = [gate.pow ? "proof-of-work" : "", paidLabel].filter(Boolean).join(" + ");
862
879
  console.log(`agent402-tollbooth listening on :${port} — charging AI bots via ${rails || "proof-of-work"}`);
863
880
  if (upstream) console.log(` proxying → ${upstream}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent402-tollbooth",
3
- "version": "0.9.2",
3
+ "version": "0.9.3",
4
4
  "description": "Agent402 tollbooth: open-source, self-hostable pay-per-crawl for x402 AND MPP (the sell side of Agentic Finance): charge AI bots per request (USDC via x402, or MPP - the Machine Payments Protocol - through the same settlement, or USDG on Robinhood Chain, or free proof-of-work) while humans browse free. Drop-in Express middleware or reverse proxy that settles both wires from env alone - no Cloudflare, no Stripe, no signup.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -47,11 +47,15 @@
47
47
  "express": "^5.0.0"
48
48
  },
49
49
  "peerDependencies": {
50
+ "@coinbase/x402": ">=2.0.0",
50
51
  "@x402/core": ">=2.0.0",
51
52
  "@x402/evm": ">=2.0.0",
52
53
  "@x402/express": ">=2.0.0"
53
54
  },
54
55
  "peerDependenciesMeta": {
56
+ "@coinbase/x402": {
57
+ "optional": true
58
+ },
55
59
  "@x402/core": {
56
60
  "optional": true
57
61
  },