{"protocol":"x402","version":"1.0","spec":"https://github.com/coinbase/x402","description":"Pay USDC, get a Sentinel dVPN subscription. One HTTP request, one EIP-3009 signature.","tldr":["You need: (a) an EVM wallet with USDC on Base, (b) a Sentinel wallet from `createWallet()` in `blue-js-sdk/ai-path`.","Install (agent side only — you do NOT clone this repo): `npm install @x402/fetch @x402/evm viem blue-js-sdk`. That is the complete dependency set for paying and connecting. The express/@x402/express/dotenv packages are operator-only — ignore them.","POST https://x402.sentinel.co/vpn/connect/{1day|7days|30days} with { sentinelAddr } using @x402/fetch to auto-sign the 402. Tiers cost $0.033 / $0.233 / $1.00 USDC — pick the smallest that covers your need; $0.033 is enough to start. Add { country: \"DE\" } to get a node in a specific country (GET /nodes lists what is available). Payment is identical on every OS.","Connecting differs by OS. macOS & Linux: use the native CLI `sentinel-dvpncli` (go install github.com/sentinel-official/sentinel-dvpncli@latest — needs Go 1.24+). The CLI shells out to the system tunnel binary, so install `wireguard-tools` (provides `wg-quick`; most nodes are WireGuard) and, for V2Ray nodes, a `v2ray` binary on PATH. Then import the key (`printf '%s\\n\\n' \"$MNEMONIC\" | sentinel-dvpncli keys add agent --keyring.backend test`), `tx session-start <nodeAddress> --subscription-id <id> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test`, resolve the id with `query sessions --account-addr <sent1...> --subscription-id <id> --output-format json`, then `connect <sessionId>` (sudo to bring the interface up). See sentinel.connectMacLinux. Only Fedora is unsupported (SELinux blocks VPNs).","Windows: zero prereqs. `connect({ mnemonic, subscriptionId, feeGranter, nodeAddress, protocol: \"v2ray\" })` auto-downloads the v2ray binary (userspace SOCKS5, ~70% of nodes, no admin). WireGuard (~30%, faster) needs admin once; the SDK gates on admin BEFORE payment, so no funds are wasted. See sentinel.connectWindows.","Tunnel is up. You paid as little as $0.033 USDC (1day) up to $1.00 (30day), zero gas on Base, zero gas on Sentinel."],"network":{"caip2":"eip155:8453","chainId":8453,"name":"Base mainnet"},"payment":{"scheme":"exact","standard":"EIP-3009","method":"transferWithAuthorization","asset":{"symbol":"USDC","decimals":6,"address":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"},"payTo":"0x35bA8d9313368094BF0428733cF205a27b5c4430","gasless":true,"approveRequired":false,"prerequisites":{"evmWallet":"Agent must hold an EVM private key with USDC on Base. EIP-3009 signature is created locally; the key never leaves the agent.","minUsdc":"Fund only for the tier you want: $0.033 (1day), $0.233 (7days), or $1.00 (30day). The $0.033 entry tier is enough to start — no need to over-fund. Fund the wallet before calling the endpoint.","gasOnBase":"Agent pays ZERO gas on Base — the facilitator submits the transferWithAuthorization. Agent only needs USDC."},"eip712":{"note":"Builders using @x402/fetch get this automatically — fields below are for low-level integrators.","domain":{"name":"USD Coin","version":"2","chainId":8453,"verifyingContract":"0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"},"primaryType":"TransferWithAuthorization","types":{"EIP712Domain":[{"name":"name","type":"string"},{"name":"version","type":"string"},{"name":"chainId","type":"uint256"},{"name":"verifyingContract","type":"address"}],"TransferWithAuthorization":[{"name":"from","type":"address"},{"name":"to","type":"address"},{"name":"value","type":"uint256"},{"name":"validAfter","type":"uint256"},{"name":"validBefore","type":"uint256"},{"name":"nonce","type":"bytes32"}]},"message":{"from":"agent EVM address","to":"payment.payTo (operator)","value":"price.atomic of chosen tier","validAfter":"0 (or now)","validBefore":"now + 10 minutes (unix seconds)","nonce":"random 32 bytes — server tracks to prevent replay"}}},"endpoints":{"paid":[{"method":"POST","path":"/vpn/connect/1day","price":{"display":"$0.033","atomic":"33000","decimals":6},"days":1},{"method":"POST","path":"/vpn/connect/7days","price":{"display":"$0.233","atomic":"233000","decimals":6},"days":7},{"method":"POST","path":"/vpn/connect/30days","price":{"display":"$1.00","atomic":"1000000","decimals":6},"days":30}],"free":[{"method":"GET","path":"/manifest","description":"This document"},{"method":"GET","path":"/pricing","description":"Human pricing table"},{"method":"GET","path":"/nodes","description":"VPN nodes in operator plan with live geo data (country, city, protocol, online) and a byCountry summary"},{"method":"GET","path":"/health","description":"Uptime check"},{"method":"GET","path":"/agent/:sentinelAddr","description":"Subscription + fee-grant status"}]},"request":{"contentType":"application/json","body":{"sentinelAddr":{"type":"string","pattern":"^sent1[0-9a-z]{38}$","required":true,"description":"Agent Sentinel bech32 address — receives the subscription share and fee grant"},"country":{"type":"string","required":false,"description":"Preferred node country — ISO 3166-1 alpha-2 code (\"DE\") or name (\"Germany\"). Validated BEFORE payment: if no online plan node matches, you get COUNTRY_UNAVAILABLE with availableCountries and are not charged. Omit to let the server pick.","example":"DE"}}},"response":{"success":{"status":200,"schema":{"provisioned":"boolean","subscriptionId":"number","planId":"number","feeGranter":"string (sent1...)","nodeAddress":"string (sentnode1...)","nodeCountry":"string | null — country of nodeAddress when a country was requested and matched","nodes":"string[]","sentinelTxHash":"string","expiresAt":"string (ISO 8601)"}},"paymentRequired":{"status":402,"header":"PAYMENT-REQUIRED","nextAction":"Sign EIP-3009 transferWithAuthorization, resend with PAYMENT-SIGNATURE header"},"errors":{"note":"All errors are JSON: { code, message, nextAction, docs }. Branch on `code` — it is the stable contract.","codes":{"MISSING_SENTINEL_ADDR":{"status":400,"meaning":"Request body did not include sentinelAddr."},"INVALID_SENTINEL_ADDR":{"status":400,"meaning":"sentinelAddr is not a valid sent1-bech32 address — use createWallet() from 'blue-js-sdk/ai-path'."},"UNKNOWN_TIER":{"status":404,"meaning":"Path tier is not one of 1day | 7days | 30days."},"COUNTRY_UNAVAILABLE":{"status":400,"meaning":"Requested country has no online plan node. Returned BEFORE payment — no USDC charged. Response includes availableCountries; resend with one of those or omit country."},"PAYMENT_REQUIRED":{"status":402,"meaning":"Sign EIP-3009 transferWithAuthorization and resend with PAYMENT-SIGNATURE header. @x402/fetch handles this automatically."},"CAPACITY_EXHAUSTED":{"status":503,"meaning":"Operator cannot provision right now (subscription pool full and operator balance below new-subscription cost). Returned BEFORE payment — no USDC charged. Retry later; re-checked every 60s."},"PROVISIONING_FAILED":{"status":500,"meaning":"Sentinel TX failed after payment verification. USDC was NOT charged — settlement only happens after a successful 2xx response. Safe to retry."},"INTERNAL_ERROR":{"status":500,"meaning":"Unexpected server error. Open an issue if reproducible."},"NOT_FOUND":{"status":404,"meaning":"No route matches. See /manifest for endpoints."}},"prePaymentGuarantee":"MISSING_SENTINEL_ADDR / INVALID_SENTINEL_ADDR / UNKNOWN_TIER / COUNTRY_UNAVAILABLE / CAPACITY_EXHAUSTED are returned BEFORE paymentMiddleware. Beyond that, USDC settlement only occurs after a successful 2xx response — error responses (including PROVISIONING_FAILED) never charge the agent."}},"flow":[{"step":1,"actor":"agent","action":"POST /vpn/connect/{days} with { sentinelAddr }"},{"step":2,"actor":"server","action":"Respond 402 with PAYMENT-REQUIRED (amount, asset, payTo, network)"},{"step":3,"actor":"agent","action":"Sign EIP-3009 transferWithAuthorization locally (EIP-712)"},{"step":4,"actor":"agent","action":"Resend request with PAYMENT-SIGNATURE header"},{"step":5,"actor":"facilitator","action":"Settle USDC on Base (~2s)"},{"step":6,"actor":"server","action":"Atomic MsgShareSubscription + MsgGrantAllowance on Sentinel"},{"step":7,"actor":"server","action":"Respond 200 with subscriptionId, feeGranter, nodeAddress"},{"step":8,"actor":"agent","action":"Connect (OS-specific, same 200 fields). macOS/Linux: keys add (printf mnemonic+blank-line | keys add agent --keyring.backend test), tx session-start <nodeAddress> --subscription-id <id> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test, resolve id via query sessions --account-addr <sent1...> --subscription-id <id> --output-format json, then connect <sessionId>. Windows: connect({ mnemonic, subscriptionId, feeGranter, nodeAddress, protocol: \"v2ray\" }) — zero admin, binary auto-installs; setup() is optional."},{"step":9,"actor":"agent","action":"MsgStartSession (gas paid by operator via fee grant)"},{"step":10,"actor":"agent","action":"Direct WireGuard/V2Ray handshake with node — tunnel up"}],"install":{"npm":"npm install @x402/fetch @x402/evm viem blue-js-sdk","note":"Agent side only — you do NOT clone this repo. The four packages above are the complete set for paying + connecting on every OS. express / @x402/express / dotenv are operator-only; do not install them.","nativeMacLinux":"The macOS/Linux connect path also needs, OUTSIDE npm: Go 1.24+ (to `go install` sentinel-dvpncli), wireguard-tools (provides `wg-quick`, for WireGuard nodes), and a `v2ray` binary on PATH (for V2Ray nodes). The Windows path needs none of these — connect({ protocol: \"v2ray\" }) auto-fetches the binary (setup() is optional)."},"packages":{"payment":"@x402/fetch","scheme":"@x402/evm","evm":"viem","sentinel":"blue-js-sdk/ai-path"},"example":{"language":"typescript","code":"import { x402Client, wrapFetchWithPayment } from '@x402/fetch';\nimport { ExactEvmScheme } from '@x402/evm/exact/client';\nimport { setup, createWallet, connect, disconnect } from 'blue-js-sdk/ai-path';\n\nawait setup();                                // optional: pre-fetch V2Ray (no admin). connect() also auto-fetches it.\nconst wallet = await createWallet();          // { address: sent1..., mnemonic }\nconst scheme = new ExactEvmScheme({ address, signTypedData });\nconst client = new x402Client();\nclient.register('eip155:8453', scheme);\nconst paidFetch = wrapFetchWithPayment(fetch, client);\n\nconst res = await paidFetch('https://x402.sentinel.co/vpn/connect/30days', {\n  method: 'POST',\n  body: JSON.stringify({ sentinelAddr: wallet.address, country: 'DE' }),  // country optional\n});\nconst { subscriptionId, feeGranter, nodeAddress } = await res.json();\nawait connect({ mnemonic: wallet.mnemonic, subscriptionId, feeGranter, nodeAddress, protocol: 'v2ray' });  // v2ray = zero admin, zero manual install (Windows)"},"sentinel":{"chain":"sentinelhub-2","planId":41,"countries":"70+","protocols":["wireguard","v2ray"],"gasGrantedByOperator":true,"rpc":"https://rpc.sentinel.co:443","lcd":"https://lcd.sentinel.co","rpcFallbacks":["https://rpc.sentinel.co:443","https://sentinel-rpc.polkachu.com","https://rpc.mathnodes.com","https://sentinel-rpc.publicnode.com:443","https://rpc.sentinel.quokkastake.io:443","https://rpc.sentinel.suchnode.net:443"],"lcdFallbacks":["https://lcd.sentinel.co","https://sentinel-api.polkachu.com","https://api.sentinel.quokkastake.io","https://sentinel-rest.publicnode.com","https://api.sentinel.suchnode.net"],"endpointsNote":"blue-js-sdk ships the first five RPC / four LCD entries as built-in fallbacks and rotates automatically; suchnode.net is an additional public endpoint (suchnode.net) you can add at runtime with addRpcEndpoint(url).","addressPrefix":"sent","coinType":118,"denom":"udvpn","denomDecimals":6,"setup":{"package":"blue-js-sdk/ai-path","fn":"await setup()","platform":"Windows connect path only. macOS/Linux do not need setup() — use connectMacLinux (native CLI) instead.","note":"OPTIONAL on Windows — connect({ protocol: \"v2ray\" }) auto-downloads V2Ray on first use, so you can skip setup() entirely. If you do run it on a fresh machine: auto-downloads V2Ray to ~/.sentinel-sdk/bin (no admin) and, only when run elevated, auto-installs the WireGuard MSI (needs admin). Returns { os, node, v2ray, wireguard, admin }. v2ray ok => you can connect with zero manual installs and zero admin via protocol: \"v2ray\"."},"walletCreate":{"package":"blue-js-sdk/ai-path","fn":"createWallet()","returns":{"address":"sent1... (use this as sentinelAddr)","mnemonic":"string (persist this)"},"note":"Generate once per agent. The address goes in the request body; the mnemonic signs MsgStartSession."},"platforms":"Payment is identical on every OS; only connect differs. Windows: zero-prereq with protocol: \"v2ray\" (see connectWindows). macOS & Linux: native CLI sentinel-dvpncli (see connectMacLinux). Fedora unsupported (SELinux blocks VPN interfaces).","connectMacLinux":{"tool":"sentinel-dvpncli","install":"go install github.com/sentinel-official/sentinel-dvpncli@latest (Go 1.24+); binary lands in $(go env GOPATH)/bin","nativeDeps":"The CLI does NOT bundle a tunnel — it shells out. WireGuard nodes run `wg-quick up` (install wireguard-tools: `apt install wireguard-tools` / `brew install wireguard-tools` / `pacman -S wireguard-tools`). V2Ray nodes run `v2ray run --config` (install a `v2ray` binary on PATH). Most nodes are WireGuard; install wireguard-tools at minimum. Bringing the interface up needs sudo.","why":"Flag-driven, non-interactive — good for agents. Trade-off vs Windows: you install the tunnel binary yourself (Windows setup() auto-fetches it).","steps":["keys add: printf '%s\\n\\n' \"$MNEMONIC\" | sentinel-dvpncli keys add agent --keyring.backend test  (import the SAME wallet whose sentinelAddr you sent to x402. keys add is INTERACTIVE — no --recover flag: line 1 answers the mnemonic prompt, the blank line 2 accepts the default empty BIP-39 passphrase. A single-line echo would hang on the passphrase prompt.)","session-start: sentinel-dvpncli tx session-start <nodeAddress> --subscription-id <subscriptionId> --tx.fee-granter-addr <feeGranter> --tx.from-name agent --keyring.backend test --rpc.chain-id sentinelhub-2 --output-format json  (operator fee-grants the gas)","resolve session id: sentinel-dvpncli query sessions --account-addr <sent1...> --subscription-id <subscriptionId> --output-format json — session-start does NOT print the new id cleanly, so query it back and take the newest entry (.result[-1].id).","connect: sentinel-dvpncli connect <sessionId>  (takes the SESSION id, not the subscription id; needs no key — it only queries the session and builds the tunnel. WireGuard nodes may need sudo to bring the interface up)"],"teardown":"sentinel-dvpncli tx session-cancel <sessionId>","defaults":"--rpc.addrs https://rpc.sentinel.co:443, --rpc.chain-id sentinelhub-2, --keyring.name sentinel","fedora":"Not supported on Fedora — SELinux blocks VPN interfaces. macOS, Ubuntu, Debian, Arch and other mainstream distros work out of the box."},"connectWindows":{"package":"blue-js-sdk/ai-path","recommended":"connect({ mnemonic, subscriptionId, feeGranter, nodeAddress, protocol: \"v2ray\" })","v2ray":"protocol: \"v2ray\" = zero prereq. Userspace SOCKS5; connect() auto-downloads the binary to ~/.sentinel-sdk/bin (no admin, no manual install). ~70% of nodes (~630).","wireguard":"protocol: \"wireguard\" = ~30% of nodes, faster, but needs admin ONCE (MSI install). The SDK gates on admin BEFORE payment, so a non-admin box wastes no funds. Pin \"v2ray\" if you cannot elevate.","noProtocol":"Omitting protocol searches both types and may pick a WireGuard node that fails the admin gate (no funds lost). Pin \"v2ray\" if admin is not guaranteed.","requestHint":"To force a V2Ray node, POST { sentinelAddr, protocol: \"v2ray\" }. GET /nodes?protocol=v2ray lists them."},"connect":{"package":"blue-js-sdk/ai-path","platform":"Windows (JS tunnel). macOS/Linux use connectMacLinux.","fn":"connect({ mnemonic, subscriptionId, feeGranter, nodeAddress, protocol: \"v2ray\" })","protocolNote":"On Windows pin protocol: \"v2ray\" (zero admin) unless you have admin. See connectWindows.","argsFrom":"Pass response.success fields directly. mnemonic is from createWallet().","returns":{"connected":"boolean","ip":"string","protocol":"wireguard | v2ray"},"gasCost":"0 P2P — operator fee-grants MsgStartSession"},"disconnect":{"package":"blue-js-sdk/ai-path","fn":"disconnect()  (Windows JS path)","cli":"macOS/Linux: sentinel-dvpncli tx session-cancel <sessionId>","note":"Ends the session on-chain (also fee-granted) and tears down the tunnel."},"errors":{"FEE_GRANT_NOT_FOUND":"Server provisioned but fee grant missing — retry POST","FEE_GRANT_EXPIRED":"Subscription expired — purchase a new tier","FEE_GRANT_EXHAUSTED":"Spend limit consumed — purchase a new tier"}},"retry":{"networkErrors":"Idempotent on the agent side — re-POST is safe if no 200 arrived. Settlement only happens on a 2xx response, and the EIP-3009 nonce prevents double-charge.","after200":"Provisioning is complete. If connect() fails, call GET /agent/:sentinelAddr to verify state before retrying connect()."},"docs":{"llmsTxt":"/llms.txt","readme":"https://github.com/Sentinel-Bluebuilder/x402","manifesto":"https://github.com/Sentinel-Bluebuilder/x402/blob/master/MANIFESTO.md"},"seeAlso":{"autonomous":"https://autonomous.sentinel.co","autonomousLlmsTxt":"https://autonomous.sentinel.co/llms.txt","note":"Fully self-funded path: the agent holds its own P2P and pays nodes directly per-GB. No x402 server, no operator. Separate site."}}