agent-toll
v1.1.0
Published
Middleware that charges AI agents for access to your content. Humans pass through free.
Downloads
277
Maintainers
Readme
agent-toll
Middleware that charges AI agents for access to your content. Humans pass through free.
Quickstart
npm install agent-tollconst express = require(‘express’);
const { agentToll } = require(‘agent-toll’);
const app = express();
// With your wallet — you receive 95% of each agent payment:
app.use(agentToll({ wallet: ‘0xYourWallet’ }));
// Or without a wallet — platform operator receives 100%:
// app.use(agentToll());
app.get(‘/article/:id’, (req, res) => {
res.json({ content: ‘your protected content’ });
});
app.listen(3000);That’s it. Agents hitting your routes get a 402 Payment Required with USDC payment instructions. Once paid, they receive a signed receipt and can access freely until it expires.
Who this is for
| Role | What you use |
|------|----------------|
| Publishers | npm install agent-toll — protect your routes in minutes |
| Agent developers | npm install agent-toll-sdk — automatic payment handling |
Documentation
- Full setup guide:
CUSTOMER_DEPLOYMENT_GUIDE.md(env vars, Docker, platform, security).
Public SDK (agents)
npm install agent-toll-sdkconst { AgentClient } = require('agent-toll-sdk');
const client = new AgentClient({
wallet: process.env.AGENT_PRIVATE_KEY,
rpcUrl: process.env.BASE_RPC_URL,
baseUrl: process.env.BASE_URL
});
await client.get('/article/123');Source in this repo: sdk/ (publish with npm publish from sdk/). The root agent-toll-sdk.js file mirrors the published package for local development and tests.
Maintainer: publish the SDK
cd sdk
npm publish --access=publicIf the name agent-toll-sdk is already taken on npm, use a scoped name (e.g. @yourcompany/agent-toll-sdk) in sdk/package.json.
Private operator layout (Docker / hidden backend)
These pieces are for operators who distribute pre-built images and keep backend implementation private:
- Private backend core:
agent-toll-core/(package@yourorg/agent-toll-core— replace scope when you publish) - Middleware container:
middleware/ - Platform container:
platform/ - Compose:
docker-compose.private.yml - Installer:
scripts/install-private-beta.sh
docker build -t yourorg/agent-toll-middleware:beta ./middleware
docker build -t yourorg/agent-toll-platform:beta ./platform
cp .env.publisher.example .env.publisher
cp .env.platform.example .env.platform
docker compose -f docker-compose.private.yml up -dWhat is included
index.js:agentToll()middleware- human bypass
- agent detection
402challenge flow- on-chain USDC verification on Base
- scoped/expiring/replay-protected receipts
- persistent file-backed receipt storage
- structured logging, metrics, rate limiting, spend caps
agent-toll-sdk(npm) / rootagent-toll-sdk.js:AgentClientget/post/put/patch- automatic
402 -> pay -> retry - retry with exponential backoff
- receipt cache per scope
server.js: local deployment entrypoint for middleware API routesdashboard/index.html+dashboard/app.jsx: React-based publisher dashboard UIplatform/server.js: central multi-publisher aggregation serviceplatform/dashboard/*: central platform dashboard UItests/e2e.test.js: unit + integration coverage with local end-to-end flow
Install
npm installEnvironment variables
Required for live on-chain payment flow
BASE_RPC_URL: Base RPC endpoint (mainnet or Base Sepolia)PUBLISHER_WALLET: publisher wallet address receiving USDCRECEIPT_SIGNER_PRIVATE_KEY: private key used to cryptographically sign receipts
SDK-side sensitive env vars
AGENT_PRIVATE_KEY: agent wallet private keyBASE_URL: middleware server URL (for SDK scripts)
Optional middleware env vars
PORT(default3000)RECEIPT_STORE_PATH(default./.agent-toll-receipts.json)RECEIPT_TTL_SECONDS(default300)MIDDLEWARE_LOGGING(true/false, defaulttrue)MIDDLEWARE_METRICS(true/false, defaulttrue)METRICS_PATH(default/metrics)MAX_REQUESTS_PER_WINDOWMAX_REQUESTS_PER_MINUTE(preferred alias for beta controls)MAX_AGENT_REQUESTS_PER_MINUTE(supported alias)RATE_LIMIT_WINDOW_SECONDS(default60)MAX_SPEND_PER_SCOPE(USDC string, e.g.0.00001)MAX_SPEND_TOTAL(USDC string)MAX_AGENT_SPEND_PER_SCOPE(preferred alias)MAX_AGENT_SPEND_TOTAL(preferred alias)MOCK_PAYMENT_PROVIDER(true/false) for local non-chain testingMOCK_AGENT_WALLETused only withMOCK_PAYMENT_PROVIDER=trueDASHBOARD_API_KEYoptional API key for/dashboard/*endpointsPUBLISHER_API_KEYoptional API key for/agent-toll/*publisher reporting endpointsPUBLISHER_IDpublisher identifier for central platform aggregationCOMMISSION_WALLET— not an env var. The commission wallet is hardcoded in the middleware binary by the platform operator. Publishers cannot configure or override it.
Run middleware locally
BASE_RPC_URL=https://sepolia.base.org \
PUBLISHER_WALLET=0xYourPublisherWallet \
RECEIPT_SIGNER_PRIVATE_KEY=0xYourReceiptSignerKey \
npm startServer starts at http://localhost:3000.
Protected endpoint examples:
GET /article/123POST /article/123/feedback
Metrics endpoint (if enabled): GET /metrics
Dashboard endpoints:
GET /dashboard(UI)GET /dashboard/agentsGET /dashboard/receiptsGET /dashboard/paymentsGET /dashboard/metrics
If DASHBOARD_API_KEY is set, send it as x-dashboard-api-key or Authorization: Bearer ....
Publisher reporting endpoints (for central platform pull model):
POST /agent-toll/metricsGET /agent-toll/payments?since=<unixTimestamp>
If PUBLISHER_API_KEY (or DASHBOARD_API_KEY) is set, provide x-dashboard-api-key.
Publisher dashboard
Start the server, then open:
http://localhost:3000/dashboard
Dashboard shows:
- agent wallets + total spend
- issued receipts and used status
- verified payments and tx hashes
- middleware counters (402, rate-limit blocks, spend-limit blocks)
- charts for spend per agent and spend per scope
End-to-end agent flow test (real SDK + local middleware)
Use the provided integration example:
AGENT_PRIVATE_KEY=0x... \
BASE_RPC_URL=https://sepolia.base.org \
BASE_URL=http://localhost:3000 \
node example-integration.jsExpected flow:
- SDK requests
/article/123 - Middleware returns
402if no valid receipt - SDK pays via wallet and retries with
X-Agent-Payment-Tx - Middleware verifies on-chain, issues
X-Agent-Receipt - SDK caches receipt and reuses on second call
Automated tests
Run all unit + integration tests:
npm testCovered scenarios:
- agent/human detection
- receipt parse and cache behavior
- full
402 -> payment -> receipt -> cached retry - per-agent rate limiting (
429) - spend cap enforcement (
402) - concurrent multi-agent access
- metrics exposure assertions
Testing rate limits and spend limits manually
Start server with limits:
BASE_RPC_URL=https://sepolia.base.org \
PUBLISHER_WALLET=0xYourPublisherWallet \
MAX_REQUESTS_PER_WINDOW=2 \
RATE_LIMIT_WINDOW_SECONDS=60 \
MAX_SPEND_TOTAL=0.00001 \
npm start- Exceed request window from same
X-Agent-Walletto get429 - Exceed spend limit for fresh scopes to get
402
Deploy options
Node server (quickest)
Deploy server.js to any Node host (Render, Railway, Fly, EC2, etc.) with the env vars above.
Central platform aggregation (multi-publisher)
The platform polls each publisher’s middleware (POST /agent-toll/metrics, GET /agent-toll/payments) using the API keys you configure. Add one JSON object per publisher deployment:
PUBLISHERS_JSON='[
{"id":"news-site","name":"News Site","baseUrl":"https://api.news.example","apiKey":"secret-news"},
{"id":"docs-site","name":"Docs Site","baseUrl":"https://api.docs.example","apiKey":"secret-docs"},
{"id":"shop-site","name":"Shop Site","baseUrl":"https://api.shop.example","apiKey":"secret-shop"}
]' \
npm run start:platformUse docker-compose.yml or .env.platform for the same PUBLISHERS_JSON pattern (see .env.platform.example).
Central platform URLs:
GET /dashboard UIGET /docsdeveloper-facing HTML guideGET /api/platform/aggregateaggregated metrics, spend, commission, and payouts across all publishersGET /api/platform/snapshotsraw per-publisher snapshots
Commission split flow
- Middleware challenge includes:
amount(total toll)publisher_amountcommission_amountcommission_recipient(platform wallet; 5% fixed, not configurable)
- SDK auto-sends:
- publisher payment tx in
X-Agent-Payment-Tx - commission payment tx in
X-Agent-Commission-Tx
- publisher payment tx in
- Middleware verifies both transfers on-chain before issuing a receipt.
Vercel / AWS Lambda / Cloudflare Worker
- Keep
agentToll()as the core middleware logic. - Wrap framework-specific request handlers around it.
- Use a durable shared store (Redis/managed DB) instead of local file storage in distributed/serverless environments.
- Point
paymentRpcUrl/BASE_RPC_URLto a reliable RPC provider.
Notes for production
- File-based receipt storage is durable per instance, but not shared across replicas.
- For horizontal scaling, swap to a shared backend (Redis/Postgres/SQLite service).
- Keep
AGENT_PRIVATE_KEYonly on trusted agent runtimes, never in browser code.
Beta notice
- Receipts are off-chain and signed by each publisher’s middleware.
- Default beta limits (spend/request caps) may change; configure limits explicitly for production.
- No SLA is implied; review
CUSTOMER_DEPLOYMENT_GUIDE.mdfor security and operations.
