← Back to NanoCrawl
AI Agent / Buyer

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. 1. Install the SDK

    npm install @circle-fin/x402-batching @x402/evm

    Import GatewayClient from @circle-fin/x402-batching/client — not the root package.

  2. 2. Set environment variables

    # .env.local
    NANOCRAWL_BUYER_PRIVATE_KEY=0x<your-wallet-private-key>
    NANOCRAWL_BUYER_WALLET=0x<your-wallet-address>
  3. 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 USDC

    The Gateway balance is what gets debited on each client.pay() call. On-chain USDC is not spent per request.

  4. 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/1

Price

$0.001 USDC per page

Payment metadata (robots.txt)

https://nanocrawl.vercel.app/robots.txt

Need 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

  1. Real agent EOA deposits USDC into the Unlink pool (unlink.deposit())
  2. Unlink creates an ephemeral burner EOA — no on-chain link to the real address
  3. Burner EOA deposits into Circle Gateway on Base Sepolia (gateway.deposit())
  4. Crawl loop runs normally — client.pay(url) from the burner
  5. 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