agent402-tollbooth 0.7.0 → 0.8.1
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.
- package/README.md +26 -5
- package/index.js +79 -2
- package/package.json +22 -3
package/README.md
CHANGED
|
@@ -6,7 +6,9 @@ in USDC over the [x402 protocol](https://x402.org), over
|
|
|
6
6
|
[MPP](https://mpp.dev) (the Machine Payments Protocol `Payment` HTTP auth
|
|
7
7
|
scheme, settled through the same stack), or for free by solving a
|
|
8
8
|
proof-of-work. No Cloudflare, no Stripe, no Merchant-of-Record, no signup.
|
|
9
|
-
The first self-hostable pay-per-crawl gate that speaks both wires on one 402
|
|
9
|
+
The first self-hostable pay-per-crawl gate that speaks both wires on one 402 -
|
|
10
|
+
the sell side of [Agentic Finance (AIFI)](https://agent402.tools/agentic-finance),
|
|
11
|
+
where agents pay and sites get paid, per request, with no account in between.
|
|
10
12
|
|
|
11
13
|
The big platforms are converging on the same model: Cloudflare's
|
|
12
14
|
[pay-per-crawl](https://stackoverflow.blog/2026/02/26/how-pay-per-crawl-is-reshaping-data-monetization/)
|
|
@@ -94,9 +96,24 @@ Point it at your existing site - no code changes there:
|
|
|
94
96
|
```bash
|
|
95
97
|
TOLLBOOTH_UPSTREAM=https://your-site.com \
|
|
96
98
|
TOLLBOOTH_PAYTO=0xYourWallet \
|
|
99
|
+
TOLLBOOTH_FACILITATOR_URL=https://x402.org/facilitator \
|
|
97
100
|
npx agent402-tollbooth # listens on :4021, proxies humans free, charges bots
|
|
98
101
|
```
|
|
99
102
|
|
|
103
|
+
With `TOLLBOOTH_PAYTO` **and** `TOLLBOOTH_FACILITATOR_URL` set, the proxy
|
|
104
|
+
settles real money over **both wires** from env alone (0.8.0): it builds the
|
|
105
|
+
standard `@x402/express` v2 stack in-process (verify, proxy the request, settle
|
|
106
|
+
only on a successful response, exactly once) and mints MPP challenges on the
|
|
107
|
+
same 402, so a stock `@x402/fetch` client and a stock `mppx` client both pay.
|
|
108
|
+
Install the x402 packages next to it once (`npm i @x402/express @x402/core
|
|
109
|
+
@x402/evm`; they are optional peers so the package stays dependency-free
|
|
110
|
+
otherwise) and pick a facilitator that settles your network - keyless free
|
|
111
|
+
tiers exist for mainnet chains, and `https://x402.org/facilitator` covers
|
|
112
|
+
base-sepolia for a dry run. USDC on the EVM chains in `TOLLBOOTH_NETWORK`'s
|
|
113
|
+
list (`base` default); other assets and rails use the library API below.
|
|
114
|
+
`TOLLBOOTH_PAYTO` alone still only *advertises* a quote (nothing can verify or
|
|
115
|
+
settle it, every paid request is refused) and now says so loudly at boot.
|
|
116
|
+
|
|
100
117
|
## Run on the edge (Cloudflare Workers, Next.js, Deno, Bun)
|
|
101
118
|
|
|
102
119
|
The same gate is also built on the Web Crypto + Fetch APIs (`edge.js`), so it runs
|
|
@@ -238,9 +255,11 @@ Read by the bundled proxy / Express entry point (`index.js`):
|
|
|
238
255
|
| env | default | meaning |
|
|
239
256
|
|---|---|---|
|
|
240
257
|
| `TOLLBOOTH_UPSTREAM` | – | Origin the built-in reverse proxy forwards to |
|
|
241
|
-
| `TOLLBOOTH_PAYTO` | – | Wallet address;
|
|
258
|
+
| `TOLLBOOTH_PAYTO` | – | Wallet address; advertises a USDC x402 quote (and, with `TOLLBOOTH_FACILITATOR_URL`, settles it) |
|
|
259
|
+
| `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 |
|
|
260
|
+
| `TOLLBOOTH_FACILITATOR_HEADERS` | – | Optional JSON object of auth headers sent on the facilitator's `/verify`, `/settle`, `/supported` (e.g. `{"X-API-Key":"…"}`) |
|
|
242
261
|
| `TOLLBOOTH_PRICE` | `"$0.001"` | Advertised price per request |
|
|
243
|
-
| `TOLLBOOTH_NETWORK` | `"base"` | x402 network |
|
|
262
|
+
| `TOLLBOOTH_NETWORK` | `"base"` | x402 network. CLI settlement mode accepts `base`, `base-sepolia`, `polygon`, `arbitrum`, `optimism`, `avalanche`, `celo`, `sei`, `monad`, or a raw `eip155:<id>` |
|
|
244
263
|
| `TOLLBOOTH_MPP` | on when `x402` set | `false` to switch MPP off |
|
|
245
264
|
| `TOLLBOOTH_MPP_SECRET` | `TOLLBOOTH_SECRET` | HMAC secret for MPP challenge ids |
|
|
246
265
|
| `TOLLBOOTH_MPP_NETWORKS` | `8453,42220` | CSV of EVM chain ids to offer as MPP challenges, or `all` |
|
|
@@ -500,10 +519,12 @@ instead of USDC:
|
|
|
500
519
|
TOLLBOOTH_PAYTO=0xYourWallet \
|
|
501
520
|
TOLLBOOTH_NETWORK=eip155:4663 \
|
|
502
521
|
TOLLBOOTH_ASSET=USDG \
|
|
503
|
-
npx agent402-tollbooth
|
|
522
|
+
npx agent402-tollbooth # advertises the USDG quote; settle it via the library API below
|
|
504
523
|
```
|
|
505
524
|
|
|
506
|
-
|
|
525
|
+
(The CLI's built-in settlement mode - `TOLLBOOTH_FACILITATOR_URL` - registers
|
|
526
|
+
the exact **USDC** scheme only and refuses to start with another asset rather
|
|
527
|
+
than advertise a quote it cannot settle.) In code: `createTollbooth({ payTo, network: "eip155:4663", asset: "USDG", x402 })`,
|
|
507
528
|
where `x402` is a `@x402/express` middleware whose facilitator settles chain
|
|
508
529
|
4663 (advertise `eip155:4663` in its `accepts`). Defaults are unchanged (USDC
|
|
509
530
|
on Base). MPP challenges are only minted for chains in `mppNetworks` (Base +
|
package/index.js
CHANGED
|
@@ -516,6 +516,81 @@ function readBody(req, cap = 10 * 1024 * 1024) {
|
|
|
516
516
|
});
|
|
517
517
|
}
|
|
518
518
|
|
|
519
|
+
// Chain names the CLI accepts for TOLLBOOTH_NETWORK, to CAIP-2. A raw
|
|
520
|
+
// `eip155:<id>` passes through. USDC-settling EVM chains only: the middleware
|
|
521
|
+
// built below registers @x402/evm's exact scheme, whose default money parser
|
|
522
|
+
// knows USDC on these networks; anything else (USDG on Robinhood Chain,
|
|
523
|
+
// Solana, Stellar, Algorand) needs the library API with the matching scheme.
|
|
524
|
+
export const CLI_NETWORKS = {
|
|
525
|
+
base: "eip155:8453", "base-sepolia": "eip155:84532", polygon: "eip155:137", arbitrum: "eip155:42161",
|
|
526
|
+
optimism: "eip155:10", avalanche: "eip155:43114", celo: "eip155:42220", sei: "eip155:1329", monad: "eip155:143",
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
/** Build a real @x402/express v2 middleware from env for the CLI, or null.
|
|
530
|
+
*
|
|
531
|
+
* Before 0.8.0, TOLLBOOTH_PAYTO in CLI mode only ADVERTISED a quote: the gate
|
|
532
|
+
* had no verifier there, so every request that carried a payment was refused
|
|
533
|
+
* with a fresh 402 - a price nobody could pay, and the operator saw no error.
|
|
534
|
+
* With TOLLBOOTH_FACILITATOR_URL set as well, the CLI now constructs the
|
|
535
|
+
* standard @x402/express stack (verify -> proxy the request -> settle only on
|
|
536
|
+
* a <400 response, in the middleware's own order, exactly once) and hands it
|
|
537
|
+
* to createTollbooth({ x402 }), which also mints MPP challenges and accepts
|
|
538
|
+
* Authorization: Payment credentials by default - so `npx agent402-tollbooth`
|
|
539
|
+
* takes money over BOTH wires from env alone. @x402/* are optional peers
|
|
540
|
+
* (this package stays dependency-free otherwise); asking for settlement
|
|
541
|
+
* without them installed FAILS the start (fail closed: the operator believes
|
|
542
|
+
* they are charging).
|
|
543
|
+
*
|
|
544
|
+
* Exported (with an injectable `env`) so the test can drive the same code the
|
|
545
|
+
* CLI runs, not a copy of it. */
|
|
546
|
+
export async function buildCliX402Middleware(env = process.env) {
|
|
547
|
+
const payTo = env.TOLLBOOTH_PAYTO || "";
|
|
548
|
+
const facilitatorUrl = env.TOLLBOOTH_FACILITATOR_URL || "";
|
|
549
|
+
if (!payTo) return null;
|
|
550
|
+
if (!facilitatorUrl) {
|
|
551
|
+
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.");
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
const asset = (env.TOLLBOOTH_ASSET || "USDC").toUpperCase();
|
|
555
|
+
if (asset !== "USDC") {
|
|
556
|
+
console.error(`✖ TOLLBOOTH_FACILITATOR_URL is set but TOLLBOOTH_ASSET=${asset}: the CLI's built-in settlement registers @x402/evm's exact USDC scheme only. For ${asset} use the library API - createTollbooth({ x402: paymentMiddleware(...) }) with the scheme your facilitator settles - or set TOLLBOOTH_ASSET=USDC. Refusing to start rather than advertise a quote it cannot settle.`);
|
|
557
|
+
process.exit(1);
|
|
558
|
+
}
|
|
559
|
+
const rawNet = String(env.TOLLBOOTH_NETWORK || "base").trim().toLowerCase();
|
|
560
|
+
const network = /^eip155:\d+$/.test(rawNet) ? rawNet : CLI_NETWORKS[rawNet];
|
|
561
|
+
if (!network) {
|
|
562
|
+
console.error(`✖ TOLLBOOTH_NETWORK=${rawNet} is not a chain the CLI can settle USDC on. Known: ${Object.keys(CLI_NETWORKS).join(", ")}, or a raw eip155:<chainId>. Refusing to start.`);
|
|
563
|
+
process.exit(1);
|
|
564
|
+
}
|
|
565
|
+
let paymentMiddleware, HTTPFacilitatorClient, x402ResourceServer, ExactEvmScheme;
|
|
566
|
+
try {
|
|
567
|
+
({ paymentMiddleware } = await import("@x402/express"));
|
|
568
|
+
({ HTTPFacilitatorClient, x402ResourceServer } = await import("@x402/core/server"));
|
|
569
|
+
({ ExactEvmScheme } = await import("@x402/evm/exact/server"));
|
|
570
|
+
} catch (e) {
|
|
571
|
+
console.error(`✖ TOLLBOOTH_FACILITATOR_URL is set, so this gate must settle x402 payments, but the x402 packages are not installed (${String(e?.message || e).slice(0, 120)}). Install them next to agent402-tollbooth: npm i @x402/express @x402/core @x402/evm . Refusing to start rather than advertise a quote it cannot settle.`);
|
|
572
|
+
process.exit(1);
|
|
573
|
+
}
|
|
574
|
+
// Optional facilitator auth headers, sent on /verify, /settle and /supported
|
|
575
|
+
// alike (facilitators disagree on the header name, so the operator names it).
|
|
576
|
+
let authHeaders = null;
|
|
577
|
+
if (env.TOLLBOOTH_FACILITATOR_HEADERS) {
|
|
578
|
+
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); }
|
|
579
|
+
}
|
|
580
|
+
const client = new HTTPFacilitatorClient({
|
|
581
|
+
url: facilitatorUrl,
|
|
582
|
+
...(authHeaders ? { createAuthHeaders: async () => ({ verify: authHeaders, settle: authHeaders, supported: authHeaders }) } : {}),
|
|
583
|
+
});
|
|
584
|
+
const resourceServer = new x402ResourceServer(client).register(network, new ExactEvmScheme());
|
|
585
|
+
const price = env.TOLLBOOTH_PRICE || "$0.001";
|
|
586
|
+
const routes = {
|
|
587
|
+
// Every method, every path (the proxy forwards them all); no verb prefix
|
|
588
|
+
// means "*" in @x402/core's matcher. Never a bazaar extension on a wildcard.
|
|
589
|
+
"/*": { accepts: [{ scheme: "exact", network, price, payTo }], description: "agent402-tollbooth: paid access for automated clients", mimeType: "application/json" },
|
|
590
|
+
};
|
|
591
|
+
return paymentMiddleware(routes, resourceServer);
|
|
592
|
+
}
|
|
593
|
+
|
|
519
594
|
async function startCli() {
|
|
520
595
|
const upstream = process.env.TOLLBOOTH_UPSTREAM;
|
|
521
596
|
const port = Number(process.env.PORT) || 4021;
|
|
@@ -584,7 +659,8 @@ async function startCli() {
|
|
|
584
659
|
}
|
|
585
660
|
const { default: express } = await import("express");
|
|
586
661
|
const app = express();
|
|
587
|
-
const
|
|
662
|
+
const x402mw = await buildCliX402Middleware();
|
|
663
|
+
const gate = createTollbooth({ resourceBaseUrl: process.env.TOLLBOOTH_RESOURCE_BASE || upstream || "", replayStore, ...(x402mw ? { x402: x402mw } : {}) });
|
|
588
664
|
// Operator analytics — aggregate counts only (no per-request data), mounted
|
|
589
665
|
// before the gate so they're always reachable and never themselves charged.
|
|
590
666
|
// Two opt-in admin tokens (legacy `TOLLBOOTH_STATS_TOKEN` covers /stats only;
|
|
@@ -641,7 +717,8 @@ async function startCli() {
|
|
|
641
717
|
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." }));
|
|
642
718
|
}
|
|
643
719
|
app.listen(port, () => {
|
|
644
|
-
const
|
|
720
|
+
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)` : "");
|
|
721
|
+
const rails = [gate.pow ? "proof-of-work" : "", paidLabel].filter(Boolean).join(" + ");
|
|
645
722
|
console.log(`agent402-tollbooth listening on :${port} — charging AI bots via ${rails || "proof-of-work"}`);
|
|
646
723
|
if (upstream) console.log(` proxying → ${upstream}`);
|
|
647
724
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent402-tollbooth",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.8.1",
|
|
4
|
+
"description": "Agentic Finance (AIFI) sell side: open-source, self-hostable pay-per-crawl tollbooth for x402 AND MPP: 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",
|
|
7
7
|
"bin": {
|
|
@@ -45,6 +45,22 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"express": "^5.0.0"
|
|
47
47
|
},
|
|
48
|
+
"peerDependencies": {
|
|
49
|
+
"@x402/core": ">=2.0.0",
|
|
50
|
+
"@x402/evm": ">=2.0.0",
|
|
51
|
+
"@x402/express": ">=2.0.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependenciesMeta": {
|
|
54
|
+
"@x402/core": {
|
|
55
|
+
"optional": true
|
|
56
|
+
},
|
|
57
|
+
"@x402/evm": {
|
|
58
|
+
"optional": true
|
|
59
|
+
},
|
|
60
|
+
"@x402/express": {
|
|
61
|
+
"optional": true
|
|
62
|
+
}
|
|
63
|
+
},
|
|
48
64
|
"keywords": [
|
|
49
65
|
"x402",
|
|
50
66
|
"pay-per-crawl",
|
|
@@ -71,7 +87,10 @@
|
|
|
71
87
|
"usdg",
|
|
72
88
|
"mpp",
|
|
73
89
|
"machine-payments-protocol",
|
|
74
|
-
"payment-auth"
|
|
90
|
+
"payment-auth",
|
|
91
|
+
"agentic-finance",
|
|
92
|
+
"aifi",
|
|
93
|
+
"agentic-payments"
|
|
75
94
|
],
|
|
76
95
|
"author": "Havok Holdings LLC <mike@agent402.tools> (https://agent402.tools)",
|
|
77
96
|
"license": "MIT",
|