bondwire

x402 pay-per-inference, settled on Arc with StreamPay

An autonomous agent pays per API call over the x402 pattern (HTTP 402 Payment Required), with the payment settled on-chain in USDC on Arc using StreamPay as the settlement rail. No human in the loop, no API keys, no off-chain invoicing, the 402 → 200 transition is bound to a live on-chain payment.

This is the missing piece for the agentic economy: a server can charge a machine per request and get paid per second of use, and the buyer agent only spends for what it actually consumes.

The “model” behind /inference here is a deterministic stub, this demo proves the payment rail and the 402 gate, not a language model. Swap runInference() in server.js for any real engine and the billing is already done.

How it works

buyer agent                         x402 server (payee)                 Arc Testnet
-----------                         -------------------                 -----------
GET /inference            ───────▶  402 Payment Required
                          ◀───────  { scheme: streampay, payTo, asset: USDC, … }

createStream(payTo, 0.30 USDC, 60s) ───────────────────────────────────▶  StreamPay #N

GET /inference?stream=N   ───────▶  reads stream on-chain (active? recipient? vested?)
                                    withdraw() the vested seconds  ─────▶  USDC moves
                          ◀───────  200 { result, settlementTx }       (real Arc tx)
   …repeat per call (server pulls the seconds vested since the last call)…

cancel(N)                 ───────────────────────────────────────────▶  reclaim unused

Why streaming instead of one transfer per call? Because the agentic billing model is metered: a stream lets the server pull continuously while it works, settles many calls against a single committed budget, and lets the buyer cap and reclaim its spend, all properties a bare per-call transfer does not give you.

Run it

Needs Node 18+ and two funded Arc-Testnet burner keys (USDC is the gas token; get test USDC at https://faucet.circle.com). The server wallet auto-tops-up from the agent on first run.

npm install
cp .env.example .env        # fill AGENT_PRIVATE_KEY + SERVER_PRIVATE_KEY (dedicated burners)
./run.sh                    # bootstrap → start server → run agent → tee to demo-run.log

Or drive the two sides yourself:

SERVER_PRIVATE_KEY=0x… node server.js          # terminal 1, the paid endpoint
AGENT_PRIVATE_KEY=0x…  node agent.js            # terminal 2, the buyer agent

See a verified end-to-end transcript with live arcscan links in SAMPLE_RUN.md.

Files

File What
server.js The 402-gated /inference endpoint; verifies the stream on-chain and settles via StreamPay withdraw().
agent.js The autonomous buyer: hits 402, opens the stream, polls paid calls, reclaims the remainder.
bootstrap.js Funds the server wallet’s gas (USDC) from the agent if it is low.
run.sh One-command end-to-end demo.

Arc Testnet reference

   
RPC https://rpc.testnet.arc.network
Chain ID 5042002
Gas token USDC (native), 0x3600000000000000000000000000000000000000
StreamPay 0x6C2Ae6f8Ba7c0259EABa8ef4048C8BFc68BAB262
Explorer https://testnet.arcscan.app
Faucet https://faucet.circle.com

Security