Build a Paying Agent
Give your AI agent a wallet. Let it fetch paid web content automatically using the x402 protocol — no gas, no on-chain transactions per request.
Quickstart
1. Install the SDK
npm install @circle-fin/x402-batching @x402/evm
Import
GatewayClientfrom@circle-fin/x402-batching/client— not the root package.2. Set environment variables
# .env.local NANOCRAWL_BUYER_PRIVATE_KEY=0x<your-wallet-private-key> NANOCRAWL_BUYER_WALLET=0x<your-wallet-address>
3. Fund the Gateway balance (once)
import { GatewayClient } from '@circle-fin/x402-batching/client' const client = new GatewayClient({ chain: 'arcTestnet', privateKey: process.env.NANOCRAWL_BUYER_PRIVATE_KEY, }) // One-time: move on-chain USDC into the Gateway await client.deposit('1') // deposit 1 USDCThe Gateway balance is what gets debited on each
client.pay()call. On-chain USDC is not spent per request.4. Fetch paid content
// Handles the full x402 round-trip automatically: // GET → 402 → sign EIP-3009 off-chain → retry with PAYMENT-SIGNATURE const result = await client.pay('https://nanocrawl.vercel.app/products/1') console.log(result.response) // the paid content (JSON) console.log(result.transaction) // Circle settlement UUID
MCP Server Integration
To give Claude or any MCP-compatible agent a paying wallet, wrap client.pay() as an MCP tool:
server.tool('fetch_paid_page', {
url: z.string().url(),
budget: z.number().optional(),
}, async ({ url }) => {
const result = await client.pay(url)
return { content: [{ type: 'text', text: JSON.stringify(result.response) }] }
})The agent sees a normal tool call. Payment happens transparently.
How Payment Works
x402 payments use EIP-3009 off-chain authorization. No gas. No on-chain transaction per page. Your agent signs a USDC transfer intent; Circle Gateway settles it in batches on Arc.
The seller verifies the signature via Circle Gateway and delivers the content. A PAYMENT-RESPONSE header confirms settlement with a UUID you can audit.
Each request includes a unique nonce so payments cannot be replayed. Include a payment-identifier UUID for idempotency — safe to retry on network failure.
Test Against NanoCrawl
Endpoint
https://nanocrawl.vercel.app/products/1Price
$0.001 USDC per pagePayment metadata (robots.txt)
https://nanocrawl.vercel.app/robots.txtNeed test USDC? Get it from faucet.circle.com, then call client.deposit().
Private Payments via Unlink
By default, your agent's wallet address is visible on-chain as a Gateway participant. For agents where data-source privacy matters — trading bots, research agents — you can shield your identity using Unlink, a ZK privacy pool on Base Sepolia.
How it works
- Real agent EOA deposits USDC into the Unlink pool (
unlink.deposit()) - Unlink creates an ephemeral burner EOA — no on-chain link to the real address
- Burner EOA deposits into Circle Gateway on Base Sepolia (
gateway.deposit()) - Crawl loop runs normally —
client.pay(url)from the burner - Session ends: burner withdraws remaining USDC, returns to Unlink pool, key destroyed
On-chain, observers see only "a burner funded from the Unlink pool paid X USDC" — the real agent's identity and spending pattern are shielded.
// Use Base Sepolia for the Unlink flow (Unlink is deployed here, not Arc)
const burner = await BurnerWallet.create()
await burner.fundFromPool(unlinkClient, { token: USDC, amount: '5000000' })
const gateway = new GatewayClient({
chain: 'baseSepolia', // ← Base Sepolia, not arcTestnet
privateKey: burner.privateKey,
})
await gateway.deposit('5.00')
// Crawl loop — identical to the standard flow
for (const url of urls) {
await gateway.pay(url)
}
// Session end — return funds, dispose burner
await gateway.withdraw(remaining)
await burner.depositToPool(unlinkClient, { ... })
burner.deleteKey()NanoCrawl accepts payments on both Arc Testnet and Base Sepolia. No seller-side changes needed — the 402 response advertises both networks.
Full Interface Contract
Detailed HTTP spec: 402 format, PAYMENT-SIGNATURE structure, idempotency, shared test wallet.
View INTERFACE_CONTRACT.md