A minimal end-to-end proof-of-concept showing how an AI agent can autonomously pay for API access using the x402 protocol, Circle USDC, and Circle's Arc testnet (Circle's own EVM-compatible L1).
Client (AI agent) Server (paid API) Facilitator (local)
───────────────── ───────────────── ───────────────────
GET /risk-profile ──────────► 402 Payment Required
◄────────── { accepts: [{ network: "arc-testnet", price: "$0.01" }] }
sign EIP-3009
TransferWithAuthorization
GET /risk-profile ──────────► decode X-PAYMENT header
X-PAYMENT: <sig> POST /verify ────────────► isValid: true
POST /settle ────────────► tx on Arc chain ✅
◄────────── 200 { risk_score: 87, ... }
Key facts:
- No Circle API key required — uses local private keys
- Payment signed client-side with viem EIP-712 / EIP-3009
- Local facilitator handles verify + on-chain USDC settlement
- $0.01 USDC transferred per API call, settled on Arc testnet
| Field | Value |
|---|---|
| Chain ID | 5042002 |
| RPC | https://rpc.testnet.arc.network |
| USDC | 0x3600000000000000000000000000000000000000 |
| Explorer | https://testnet.arcscan.app |
| Faucet | https://faucet.circle.com |
npm installThe x402 package (v1.1.0) doesn't include Arc testnet in its built-in network list. Apply the patch:
node patch-x402.mjsThis adds arc-testnet (chain ID 5042002) to the SupportedEVMNetworks, EvmNetworkToChainId, and USDC config in all x402 dist files (both ESM and CJS).
Note: Re-run this after
npm installsince it modifiesnode_modules.
npm run setupCopy the output into .env:
CLIENT_PRIVATE_KEY=0x...
SERVER_PRIVATE_KEY=0x...
SERVER_ADDRESS=0x...
Go to https://faucet.circle.com, select Arc Testnet + USDC, and fund both the client and server addresses printed by npm run setup.
# Terminal 1 — payment facilitator (verify + settle on Arc chain)
npm run facilitator
# Terminal 2 — paywalled API server
npm run server
# Terminal 3 — AI agent client
npm run clientExpected output (client):
Wallet: 0xF8eBf...
Calling http://localhost:4021/risk-profile ...
Got 402. Payment required: { scheme: "exact", network: "arc-testnet", ... }
Payment payload network: arc-testnet
Payment signed. Retrying with X-PAYMENT header...
✅ Payment complete! Response:
{
"risk_score": 87,
"risk_level": "high",
"recommendation": "block_transaction"
}
Expected output (facilitator):
[FACILITATOR] verify called, network: arc-testnet
[FACILITATOR] verify result: {"isValid":true,"payer":"0x..."}
[FACILITATOR] settle called, network: arc-testnet
[FACILITATOR] settle result: {"success":true,"transaction":"0x...","network":"arc-testnet"}
Express server on port 4021. Uses x402-express middleware to gate GET /risk-profile behind a $0.01 USDC payment requirement. Points to the local facilitator at http://localhost:4022.
Express server on port 4022. Implements the x402 facilitator protocol (/verify, /settle, /supported) using viem clients connected to Arc testnet. The wallet client is extended with publicActions (required for EIP-712 signature verification during settlement).
Simulates an AI agent that:
- Calls the API → receives 402 with payment requirements
- Signs an EIP-3009
TransferWithAuthorizationusing its Arc testnet wallet - Retries the request with the
X-PAYMENTheader - Receives the paid response
Generates client and server private keys and prints the addresses to fund.
The x402 protocol is a standard for HTTP micropayments:
- 402 Response — server returns payment requirements (scheme, network, amount, payTo address, asset)
- Client signs — EIP-3009
TransferWithAuthorizationpermits the server to pull USDC without a priorapprovetransaction - X-PAYMENT header — base64-encoded signed authorization sent with the retry request
- Facilitator verifies — checks signature validity, amounts, expiry
- Facilitator settles — submits
transferWithAuthorizationto the USDC contract on Arc, transferring funds - Server responds — returns the actual API response with
X-PAYMENT-RESPONSEheader
Arc is Circle's own EVM-compatible L1 where USDC is the native gas token, making it ideal for demonstrating USDC micropayments with minimal friction. The x402 library v1.1.0 doesn't include Arc in its built-in network list — this sample includes a patch script to add it.
circle-sample/
├── src/
│ ├── setup.ts # Generate keypairs
│ ├── server.ts # Paywalled API (port 4021)
│ ├── facilitator.ts # x402 facilitator (port 4022)
│ └── client.ts # Autonomous payment client
├── patch-x402.mjs # Adds arc-testnet to x402 node_modules
├── .env.example
├── package.json
└── tsconfig.json