Pay-per-use WireGuard VPN gateway for autonomous agents. No subscriptions, no pre-auth — each access is gated by a USDC micropayment verified on Base.
tollgate is an early-stage TypeScript project in the AI payments / x402 ecosystem, focused on abstraction-layer, ai-agents, autonomous-agents, backend-wallet. It currently has 2 GitHub stars and 0 forks, and sits alongside related tools like claw-market, p402-protocol, x402-discovery-index, AgentTrust, tdm-sdk, xmr402-org.
Pay-per-use WireGuard VPN gateway for autonomous agents. No subscriptions, no pre-auth — each access is gated by a USDC micropayment verified on Base.
Flow: agent hits /vpn → gets 402 → pays 0.01 USDC on Base Sepolia via Openfort → retries with tx hash → receives WireGuard peer config valid for 1 hour.
Tollgate is built for programmatic, pay-per-use VPN access — no accounts, no subscriptions, no human in the loop. The x402 protocol makes it native to any agent or automated system that can send a USDC transaction.
| Use case | Why x402 fits |
|---|---|
| Autonomous AI agents | An agent hits a geo-restricted API, receives a 402, pays, and retries — entirely without human intervention |
| CI/CD pipelines | Build jobs pay only for the minutes they need VPN access; no standing subscription tied to infrastructure |
| Web scraping / data collection | Each agent session gets a fresh peer IP; pay per crawl run rather than managing a pool of proxies |
| Multi-agent systems | Many agents coordinate independently — each pays for its own session with no shared credentials or API keys to rotate |
| Privacy-sensitive upstream calls | Agents mask the operator's origin IP when calling third-party APIs, without exposing a persistent VPN identity |
| IoT / embedded devices | Low-cost devices that need occasional secure tunneling; per-use micropayments are more economical than monthly plans |
| Temporary developer access | A dev needs VPN access for one hour during an incident — pays $0.01 instead of provisioning a full subscription |
Tollgate implements the x402 payment protocol. When an agent hits GET /vpn without a payment header, the server returns a 402 Payment Required with a JSON body describing exactly what to pay, to whom, and on which network. The agent pays, then retries with X-Payment: <txHash>. The server verifies on-chain before provisioning access.
The agent script uses Openfort backend wallets to send USDC programmatically — no private keys in env vars, no manual signing. Openfort handles key custody, gas sponsorship, and ERC-4337 account abstraction under the hood.
The server uses Alchemy to fetch the transaction receipt from Base Sepolia and parses the ERC-20 Transfer event logs to verify:
PAYMENT_RECIPIENT_ADDRESSPAYMENT_AMOUNT_USDCUSDC_CONTRACT_ADDRESSBecause Openfort uses a bundler/paymaster, there can be a few seconds of indexing lag between when the UserOperation is confirmed and when Alchemy's RPC node returns the receipt. The server retries up to 4 times with 5s intervals before rejecting.
Each tx hash is stored in Redis with a 7-day TTL. Submitting the same hash twice returns a 402.
On successful payment, the server generates a unique keypair via the wg CLI, allocates an IP from 10.0.0.10–10.0.0.209, adds the peer to the wg0 interface, stores the session in Redis, and returns the client config string.
Currently running on Base Sepolia (testnet) — chainId 84532, USDC 0x036CbD53842c5426634e7929541eC2318f3dCF7e.
Mainnet constants are commented in scripts/agent-sim.ts and src/services/payment.ts — swap them in when a live Openfort key is available.
wg CLI, no shell — execFileSync)@openfort/openfort-node) — backend wallet for agent payments0x036CbD53842c5426634e7929541eC2318f3dCF7ebrew services start redis on macOS)npm install
cp .env.example .env
Fill in .env. Minimum required to start:
PORT=3002
REDIS_URL=redis://127.0.0.1:6379
ALCHEMY_API_KEY=your_key_here
PAYMENT_RECIPIENT_ADDRESS=0xYourWalletAddress
BASE_CHAIN_ID=84532
USDC_CONTRACT_ADDRESS=0x036CbD53842c5426634e7929541eC2318f3dCF7e
npm start # production entry point (src/main.ts)
npm run dev # auto-restarts on file changes
npm run typecheck # type check without running
npm test # runs all tests (uses PAYMENT_STUB and WG_STUB — no Alchemy or wg needed)
Simulates an autonomous agent paying USDC via Openfort and receiving a WireGuard config.
npm start)Create a backend wallet account (one-time setup):
node --input-type=module << 'EOF'
import 'dotenv/config';
import Openfort from '@openfort/openfort-node';
const of = new Openfort(process.env.OPENFORT_SECRET_KEY, { walletSecret: process.env.OPENFORT_WALLET_SECRET });
const account = await of.accounts.evm.backend.create({ chainId: 84532 });
console.log('OPENFORT_ACCOUNT_ID=' + account.id);
console.log('Wallet address: ' + account.address);
EOF
Fund the printed wallet address via the faucets above, then add the account ID to .env.
Add to .env:
OPENFORT_SECRET_KEY=sk_...
OPENFORT_WALLET_SECRET=...
OPENFORT_ACCOUNT_ID=acc_...
TOLLGATE_URL=http://your-server:3002
node --import tsx/esm scripts/agent-sim.ts
Expected output:
[1] GET http://your-server:3002/vpn
[1] 402 received — payment required: 0.01 USDC to 0x...
[2] Checking USDC contract registration in Openfort...
[2] USDC already registered: con_...
[3] Sending 0.01 USDC → 0x... via Openfort...
[3] Confirmed — tx: 0x...
[4] GET http://your-server:3002/vpn with X-Payment: 0x...
[4] 200 received — WireGuard config provisioned
Session ID : <uuid>
Allowed IP : 10.0.0.x
Expires in : 3600s
[5] Tollgate access provisioned.
WireGuard config : /tmp/tollgate-client.conf
Receipt : /tmp/tollgate-receipt.json
Connect with: sudo wg-quick up /tmp/tollgate-client.conf
── Openfort ────────────────────────────────────────────────────────────
Intent ID : tin_...
Account : acc_...
sudo wg-quick up /tmp/tollgate-client.conf
# Disconnect
sudo wg-quick down /tmp/tollgate-client.conf
node --import tsx/esm scripts/expire-test.ts <sessionId>
sudo apt update && sudo apt install wireguard redis-server -y
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
npm install -g pm2
# Generate server keypair
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key
# Create interface config (replace YOUR_PRIVATE_KEY and eth0 if needed)
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = YOUR_PRIVATE_KEY
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
EOF
# Enable IP forwarding
echo "net.ipv4.ip_forward=1" | tee -a /etc/sysctl.conf && sysctl -p
# Start WireGuard
systemctl enable wg-quick@wg0 && systemctl start wg-quick@wg0
# Copy project to server
scp -r /path/to/tollgate user@your-server:~/tollgate
# On the server
cd ~/tollgate
cp .env.example .env && nano .env # fill in all values
npm install
pm2 start src/main.ts --name tollgate --cwd ~/tollgate --interpreter tsx
pm2 save
pm2 startup
ufw allow 22/tcp
ufw allow 3002/tcp
ufw allow 51820/udp
ufw enable
Before going live, make sure these are set in your production .env:
| Setting | Production value | Why |
|---|---|---|
STRICT_REPLAY_CHECK |
true |
Prevents replay attacks if Redis restarts — fails closed (503) instead of open |
PUBLIC_HOST |
https://your-domain.com |
Ensures the 402 resource URL is correct behind a reverse proxy |
PAYMENT_AMOUNT_USDC |
your chosen price | Default 0.01 — adjust for mainnet economics |
Additional hardening in place out of the box:
/vpn is limited to 20 requests per IP per minute via express-rate-limit. Tune max in src/server.ts for your expected traffic.wg CLI calls use execFileSync with explicit argument arrays, eliminating shell injection surface.wg set … remove) before the 500 is returned, preventing zombie peers.flowchart TD
A([Agent]) --> B[GET /vpn]
B --> C{Rate limit\nexceeded?}
C -->|Yes| D[429 Too Many Requests]
C -->|No| E{X-Payment\nheader?}
E -->|Missing| F[402 + payment JSON\nx402 middleware]
E -->|Present txHash| G[payment.ts\nAlchemy → Base Sepolia\nretry up to 4×5s]
G -->|Invalid| H[402 + reason]
G -->|Valid| I[replay.ts → Redis\nreplay check + mark used]
I -->|Duplicate TX| J[402 Already used]
I -->|Fresh TX| K[wireguard.ts\ngenkey · allocateIP · addPeer]
K --> L[session.ts → Redis\nTTL = SESSION_TTL_SECONDS]
L --> M[200 + WireGuard config]
flowchart LR
subgraph L1[Layer 1 — Network]
A[UFW Firewall\nports 22 · 3002 · 51820]
end
subgraph L2[Layer 2 — Rate Limiting]
B[express-rate-limit\n20 req / IP / min]
end
subgraph L3[Layer 3 — Payment Gate]
C[x402 middleware\n402 challenge]
end
subgraph L4[Layer 4 — On-chain Verification]
D[Alchemy RPC\nTransfer event · amount · recipient]
end
subgraph L5[Layer 5 — Replay Protection]
E[Redis\nTX hash · 7-day TTL]
end
subgraph L6[Layer 6 — Peer Safety]
F[Rollback on Redis failure\nno zombie peers]
end
A --> B --> C --> D --> E --> F
| Variable | Description |
|---|---|
BASE_CHAIN_ID |
Chain ID for payment verification. Default 84532 (Base Sepolia). Set to 8453 for mainnet. |
USDC_CONTRACT_ADDRESS |
USDC contract address for the configured chain. Default 0x036CbD... (Base Sepolia). |
PAYMENT_RECIPIENT_ADDRESS |
Wallet address that receives USDC payments. |
PAYMENT_AMOUNT_USDC |
Price per access in USDC. Default 0.01. |
SESSION_TTL_SECONDS |
How long a provisioned WireGuard peer stays active. Default 3600 (1 hour). |
STRICT_REPLAY_CHECK |
true = fail closed if Redis is down (prevents replay attacks). Default false. Set to true in production. |
PUBLIC_HOST |
Set to your public URL when behind a reverse proxy — used in the 402 resource field. |
flowchart LR
D1([Day 1 ✓\nCore Gateway]) --> D2[Day 2\nSession Lifecycle]
D2 --> a[Session expiry daemon]
D2 --> b[WireGuard peer cleanup]
D2 --> c[Rate limiting per wallet]
D2 --> d[IP pool hardening]
D2 --> e[Status dashboard]
D2 --> D3[Day 3\nMainnet & Scale]
D3 --> f[Swap to Base mainnet]
D3 --> g[Live Openfort key]
D3 --> h[WireGuard concurrency queue]
D3 --> i[Reverse proxy + TLS]
A decentralized ecosystem where autonomous agents create, buy, and sell digital products, compute resources, and services - earning, reinvesting, and scaling without human intervention.
P402 Payment Protocol
A searchable index of x402-enabled APIs for autonomous agents
The first agent-native credit bureau on @Base. Real-time multi-factor reputation scoring with automated x402 payments (HTTP 402). 🛡️🤖💰
Open contract-facing SDK for payable routes and gateway-backed integrations. Thin public surface for authorize, checkout, and session flows.
XMR402 is an open, neutral standard for internet-native payments. It absolves the Internet's original sin by natively making payments possible between clients and servers, creating win-win economies that empower agentic payments at scale. XMR402 exists to build a more free and fair internet.
The AI agent with a wallet — spends USDC autonomously to get real work done. Apache-2.0, TypeScript.
Daydreams is a set of tools for building agents for commerce
A decentralized micro-settlement protocol enabling autonomous AI agents to pay publishers for premium content via Circle Programmable Wallets and x402 nanopayments.
The best way to monetize AI applications & MCP, using x402, CDP Smart Wallets & Paymaster
Command-line wallet and HTTP client for the Tempo blockchain, with built-in Machine Payments Protocol support.
Autonomous AI Agent Swarm framework with x402 self-executing wallets. Empowers LLM-driven agents to trade, bridge, and manage crypto treasuries without human intervention. The ultimate Agentic DeFi toolkit for 2026.