Skip to content

Repository files navigation

x402

AI agents pay USDC on Base for private internet access through Sentinel's decentralized VPN network.

Live at x402.sentinel.co.

One HTTP request. No KYC. No accounts. No P2P tokens. No custom contract to deploy. The agent signs an EIP-3009 USDC transfer, our facilitator settles it on Base, the server provisions a Sentinel subscription with a gas fee grant, and the agent connects to the VPN — paying zero gas.

import{x402Client,wrapFetchWithPayment}from'@x402/fetch';import{ExactEvmScheme}from'@x402/evm/exact/client';import{createWallet,connect}from'blue-js-sdk/ai-path';constwallet=awaitcreateWallet();constscheme=newExactEvmScheme({ address, signTypedData });constclient=newx402Client();client.register('eip155:8453',scheme);constpaidFetch=wrapFetchWithPayment(fetch,client);constres=awaitpaidFetch('https://x402.sentinel.co/vpn/connect/30days',{method: 'POST',body: JSON.stringify({sentinelAddr: wallet.address}),});const{ subscriptionId, feeGranter, nodeAddress }=awaitres.json();constvpn=awaitconnect({mnemonic: wallet.mnemonic, subscriptionId, feeGranter, nodeAddress,protocol: 'v2ray'});// protocol:'v2ray' = zero admin on Windows, binary auto-installs (~70% of nodes).// vpn.connected === true — agent's IP is now a Sentinel node, zero gas paid

How It Works

Agent x402 Server Sentinel Chain
───── ─────────── ──────────────
1. POST /vpn/connect/30days Returns HTTP 402 +
{ sentinelAddr } PAYMENT-REQUIRED header
│ (amount, asset, payTo, network)
│
2. @x402/fetch reads 402, Facilitator verifies + settles
signs EIP-3009 USDC transfer on Base (~2s)
transferWithAuthorization
│ │
3. Resends with ──────────────────────────────> MsgShareSubscription
PAYMENT-SIGNATURE Server then sends one atomic + MsgGrantAllowance
│ Sentinel TX: (fee grant for agent)
│
4. 200 OK with provisioning Returns subscriptionId,
credentials feeGranter, nodeAddress, nodes[]
│
5. connect({ mnemonic, ─────────────────────────────> MsgStartSession
subscriptionId, feeGranter, (gas paid by operator)
nodeAddress })
│
6. Handshake directly with VPN node (WireGuard/V2Ray). We never see the tunnel.
│
7. VPN tunnel up. Agent is private.

Key property: USDC payment uses native EIP-3009 transferWithAuthorization — no custom contract to deploy, no approve() step, no token-allowance round-trip. The asset address in every payment is the canonical USDC contract on Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913.

Architecture

x402/
├── server/ — x402 HTTP 402 VPN server (the one you run)
│ └── src/
│ ├── index.ts — Express routes + x402 paymentMiddleware
│ ├── facilitator.ts — Self-hosted EIP-3009 facilitator
│ └── sentinel.ts — MsgShareSubscription + MsgGrantAllowance
│
├── client/ — Reference agent client (@x402/fetch wrapper)
│
├── docs/ — Public site (docs/index.html)
│
└── fresh-test/ — End-to-end tests against a live server

The api/, contracts/, and sdk/ directories contain an earlier event-watcher design (custom payment contract + agentId registration + polling). The HTTP 402 + EIP-3009 flow in server/ is the canonical implementation — it needs no contract, no event watcher, and no database, and auto-creates Sentinel subscriptions on demand. The live deployment at x402.sentinel.co runs server/.

Chains

ChainPayment MethodStatus
BaseNative USDC + EIP-3009 transferWithAuthorization (no custom contract)Live on mainnet
SolanaSPL USDC transfer + memo (Helius webhook)Code written, not yet enabled

Pricing

EndpointDaysPrice
POST /vpn/connect/1day1$0.033 USDC
POST /vpn/connect/7days7$0.233 USDC
POST /vpn/connect/30days30$1.00 USDC

Pricing is configurable per operator — see server/src/index.ts.

Quick Start

Run your own server

cd server
cp .env.example .env # fill in operator details (see below)
npm install
npx tsc
node dist/index.js

Server starts on http://localhost:4020. The self-hosted facilitator starts on :4021.

You need:

  1. EVM wallet on Base — receives USDC payments, also funds the facilitator (~0.001 ETH per settlement)
  2. Sentinel wallet — holds P2P tokens for chain gas (~0.06 P2P per agent provisioning)
  3. Sentinel plan — with leased nodes (your nodes, or rented from operators)

Connect as an agent

npm install @x402/fetch @x402/evm blue-js-sdk viem
import{x402Client,wrapFetchWithPayment}from'@x402/fetch';import{ExactEvmScheme}from'@x402/evm/exact/client';import{createWalletClient,http}from'viem';import{privateKeyToAccount}from'viem/accounts';import{base}from'viem/chains';import{createWallet,connect,disconnect}from'blue-js-sdk/ai-path';// 1. Sentinel wallet (one-time — persist the mnemonic)constwallet=awaitcreateWallet();// 2. x402 payment client backed by an EVM key with USDC on Baseconstaccount=privateKeyToAccount(process.env.EVM_KEY);constviemClient=createWalletClient({
account,chain: base,transport: http('https://mainnet.base.org'),});constscheme=newExactEvmScheme({address: account.address,signTypedData: (msg)=>viemClient.signTypedData(msg),});constclient=newx402Client();client.register('eip155:8453',scheme);constpaidFetch=wrapFetchWithPayment(fetch,client);// 3. Buy 30 days of VPN — 402 → auto-sign → settle → provisionconstres=awaitpaidFetch('https://x402.sentinel.co/vpn/connect/30days',{method: 'POST',headers: {'Content-Type': 'application/json'},body: JSON.stringify({sentinelAddr: wallet.address}),});constprovision=awaitres.json();// { subscriptionId, feeGranter, nodeAddress, nodes, expiresAt, ... }// 4. Connect — agent pays zero gas, operator fee-grants the sessionconstvpn=awaitconnect({mnemonic: wallet.mnemonic,nodeAddress: provision.nodeAddress,subscriptionId: String(provision.subscriptionId),feeGranter: provision.feeGranter,protocol: 'v2ray',// zero admin on Windows, binary auto-installs (~70% of nodes)});console.log(`VPN up: ${vpn.ip} via ${vpn.protocol}`);awaitdisconnect();

Endpoints

Payment-protected (HTTP 402)

MethodPathPriceBody
POST/vpn/connect/1day$0.033{ sentinelAddr }
POST/vpn/connect/7days$0.233{ sentinelAddr }
POST/vpn/connect/30days$1.00{ sentinelAddr }

Response after settlement:

{
"provisioned": true,
"subscriptionId": 1192288,
"planId": 42,
"feeGranter": "sent1...",
"nodeAddress": "sentnode1...",
"nodes": ["sentnode1a...", "sentnode1b...", "..."],
"sentinelTxHash": "...",
"expiresAt": "2026-05-14T18:50:48Z"
}

Free (no payment)

MethodPathDescription
GET/pricingTier table, asset, payTo, network
GET/nodesNodes in the operator's plan
GET/healthServer uptime
GET/agent/:sentinelAddrAgent's subscription + fee-grant status

Security

PropertyGuarantee
Agent controls its sessionAgent's Sentinel mnemonic signs MsgStartSession locally
Tunnel credentials stay with agentWireGuard/V2Ray handshake is agent ↔ node
EVM key never leaves the agentEIP-3009 signature created locally; facilitator only sees the signature
Self-hosted facilitatorNo Coinbase, no third party in the payment path
Payment is verifiableEvery USDC settlement is a public Base transaction
No agent PIIOperator stores sentinelAddr only — no IPs, no traffic, no logs

Costs (operator side)

ItemApprox. cost
EIP-3009 settlement on Base~$0.001 ETH
Sentinel provisioning TX (per agent)~$0.0001 in P2P
VPS for the server$5–10/month

Environment Variables (server/.env)

# ─── Base / payments ───
OPERATOR_ADDRESS=0x... # Receives USDC payments
BASE_NETWORK=eip155:8453 # Or eip155:84532 for Sepolia
# ─── Facilitator (pick ONE) ───
FACILITATOR_PRIVATE_KEY=0x... # Self-hosted, needs ETH on Base
FACILITATOR_PORT=4021
# CDP_API_KEY_ID= # Or use Coinbase CDP
# CDP_API_KEY_SECRET=
# ─── Sentinel ───
SENTINEL_OPERATOR_MNEMONIC=word1 word2 ... # 12-word mnemonic, holds P2P
SENTINEL_PLAN_ID=42 # Plan with leased nodes
SENTINEL_RPC_URL=https://rpc.sentinel.co:443
SENTINEL_LCD_URL=https://lcd.sentinel.co
# ─── Server ───
PORT=4020

See server/.env.example for the full template.

License

MIT

About

AI agents pay USDC on Base/Solana for private VPN access through 900+ decentralized nodes

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages