Skip to main content

Agent-to-Provider

A self-contained demo that runs both an Express provider and an agent in a single script. This is the easiest way to see the full x402 payment flow end-to-end.

What it does

  1. Starts an Express server on port 3001 with a paywalled /search endpoint ($0.001 per call)
  2. After 500ms, launches an agent that connects to the provider
  3. The agent checks its balance, makes a paid request, and prints the results
  4. The provider logs the received payment
  5. The script exits after the payment completes

Source

import express from 'express'
import { Crumb } from 'crumb-alpha-sdk'
import { createGatewayMiddleware } from '@circle-fin/x402-batching/server'

const AGENT_PRIVATE_KEY = process.env.TEST_PRIVATE_KEY!
const PROVIDER_ADDRESS = process.env.CRUMB_WALLET_ADDRESS!
const PORT = 3001

// ── Provider ──────────────────────────────────────────────

const app = express()
app.use(express.json())

const gateway = createGatewayMiddleware({
sellerAddress: PROVIDER_ADDRESS,
description: 'Demo search endpoint',
})

app.post('/search', gateway.require('$0.001'), (req: any, res) => {
if (req.payment) {
console.log(`[Provider] Received ${req.payment.amount} USDC`)
}
res.json({
results: [
{ title: 'Demo result 1', relevance: 0.95 },
{ title: 'Demo result 2', relevance: 0.87 },
],
})
})

// ── Agent ─────────────────────────────────────────────────

async function runAgent() {
const crumb = new Crumb({
privateKey: AGENT_PRIVATE_KEY,
chain: 'arcTestnet',
onLowBalance: (bal) => console.log(`[Agent] Low balance: ${bal} USDC`),
})

console.log(`[Agent] Address: ${crumb.address}`)
console.log(`[Agent] Balance: ${await crumb.balance()} USDC`)

const result = await crumb.fetch(`http://localhost:${PORT}/search`, {
method: 'POST',
body: { query: 'test query' },
maxPayment: 0.01,
})

console.log('[Agent] Response:', JSON.stringify(result.data, null, 2))
console.log(`[Agent] Paid: ${result.formattedAmount} USDC`)
console.log(`[Agent] Tx: ${result.txHash}`)
process.exit(0)
}

// ── Start ─────────────────────────────────────────────────

app.listen(PORT, () => {
console.log(`[Provider] Running on http://localhost:${PORT}`)
setTimeout(() => runAgent().catch(console.error), 500)
})

Running

npx tsx --env-file=.env examples/agent-to-provider/index.ts

Expected output

[Provider] Running on http://localhost:3001
[Provider] Price: $0.001 per call

[Agent] Address: 0x22b2...
[Agent] Balance: 10.0 USDC

[Provider] Received 0.001 USDC

[Agent] Response: {
"results": [
{ "title": "Demo result 1", "relevance": 0.95 },
{ "title": "Demo result 2", "relevance": 0.87 }
]
}
[Agent] Paid: 0.001 USDC
[Agent] Tx: 0xabc...

Demo complete.