DEV Community

sugi
sugi

Posted on

I Built a DeFi Data API Where AI Agents Pay Per Call — Here's How

Last week I deployed something I've wanted to build for a while: a crypto/DeFi data API where the client pays per call in USDC, with no API keys, no accounts, and no subscriptions. The payment happens as part of the HTTP request itself.

It's live at https://x402-api.fly.dev and it already has an on-chain identity: Agent #18763 on Base via ERC-8004. Here's what it does, how the payment flow works, and what surprised me along the way.


Why x402?

If you haven't heard of x402, the short version: it's a protocol built on top of the long-forgotten HTTP 402 Payment Required status code. The idea is simple — a server responds with a 402 and tells the client exactly how much to pay and where. The client sends the payment as a header on the next (or retried) request. The server verifies it and responds with the actual data.

No OAuth dance. No rate-limit tiers. No billing portal. Just: "this costs 0.003 USDC, pay here, get data."

Why does this matter for AI agents specifically? Because agents are increasingly autonomous. An agent running a trading strategy or doing research doesn't have a human reaching for a credit card — it needs to be able to buy services on its own. x402 + USDC on Base makes that possible with sub-cent micropayments that settle in seconds.


What the API Does

I built 8 paid endpoints, all DeFi/crypto data:

Endpoint Price What it returns
GET /api/price-feed 0.001 USDC BTC/ETH/SOL prices + top 24h movers (live CoinGecko)
GET /api/gas-tracker 0.001 USDC Multi-chain gas across ETH, Base, Polygon, Arbitrum
GET /api/dex-quotes 0.002 USDC Swap quote comparison: Uniswap, SushiSwap, 1inch
GET /api/token-scanner 0.003 USDC Token security analysis + rug-pull risk flags
GET /api/whale-tracker 0.005 USDC Holder concentration, Gini coefficient, whale alerts
GET /api/yield-scanner 0.005 USDC Top DeFi yields: Aave, Compound, Morpho, Lido, Pendle
GET /api/funding-rates 0.008 USDC Perp funding rates across 6 venues + arb ranking
GET /api/wallet-profiler 0.008 USDC Wallet portfolio, holdings, activity, risk profile

Plus /api/endpoints (free, machine-readable catalog) and /health (free).

Pricing is intentionally micro — the most expensive call is less than a cent. The goal isn't to make money off any single call but to prove the payment model works end-to-end.


How the Payment Flow Works

Here's the exact HTTP exchange:

Step 1 — Client hits the endpoint without payment:

GET /api/price-feed HTTP/1.1
Host: x402-api.fly.dev
Enter fullscreen mode Exit fullscreen mode

Step 2 — Server responds 402:

{
  "x402Version": 1,
  "error": "Payment required",
  "accepts": [{
    "scheme": "exact",
    "network": "base-mainnet",
    "maxAmountRequired": "1000",
    "resource": "https://x402-api.fly.dev/api/price-feed",
    "description": "Aggregated crypto prices",
    "payTo": "0x60264c480b67adb557efEd22Cf0e7ceA792DefB7",
    "maxTimeoutSeconds": 60,
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "extra": { "name": "USDC", "version": "2" }
  }]
}
Enter fullscreen mode Exit fullscreen mode

(Amounts are in USDC's 6-decimal units: 1000 = 0.001 USDC.)

Step 3 — Client signs a transferWithAuthorization EIP-712 payload and retries:

GET /api/price-feed HTTP/1.1
Host: x402-api.fly.dev
X-Payment: <base64-encoded payment payload>
Enter fullscreen mode Exit fullscreen mode

Step 4 — Server verifies the signature and returns data.


Using It With x402-fetch

If you're building an AI agent or just want to test this, Coinbase's x402-fetch package handles the 402 → pay → retry cycle automatically:

import { wrapFetchWithPayment } from 'x402-fetch';
import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(),
});

const fetchWithPayment = wrapFetchWithPayment(fetch, walletClient);

const response = await fetchWithPayment('https://x402-api.fly.dev/api/price-feed');
const data = await response.json();
console.log(data);
Enter fullscreen mode Exit fullscreen mode

That's it. The agent doesn't know or care about API keys. It just needs USDC in its wallet.


ERC-8004: On-Chain Agent Identity

ERC-8004 is a proposed standard for on-chain agent identity. AI agents register themselves in a smart contract registry — anyone can look up the agent, see what it does, what endpoints it exposes, and whether it's active.

I registered this API as Agent #18763 on Base mainnet:

  • Registry: 0x8004A169FB4a3325136EB29fA0ceB6D2e539a432
  • Chain: Base (chain ID 8453)
  • View on BaseScan

The vision: AI agents autonomously discover services through on-chain registries. An agent looking for DeFi data queries the registry, finds Agent #18763, reads its endpoint catalog, and starts paying for calls. No human intervention.


What I Learned

Payment verification is the hard part. Server-side verification of EIP-3009 transferWithAuthorization signatures is fiddly. I implemented both signature verification and tx hash verification.

Replay protection matters immediately. Without it, a client could reuse one payment for unlimited calls. Tracking used nonces in-memory for now — would need Redis for multi-replica.

The 402 response structure is critical. If maxAmountRequired, asset, or payTo are wrong, x402-fetch fails silently. I spent more time debugging the response JSON than anything else.

Fly.io + Node.js was great for this. Cold starts are fast, free tier handles the load, deployed with a single fly deploy.


Try It

The API is live: https://x402-api.fly.dev

curl -i https://x402-api.fly.dev/api/price-feed
Enter fullscreen mode Exit fullscreen mode

If you're building with x402, I'd love to hear what you're working on. If the pricing feels wrong or something's broken, tell me. This is a first draft — feedback is the whole point.

Top comments (1)

Collapse
 
alfredz0x profile image
Alfred Zhang

This is one of the cleaner x402 write-ups I've seen — especially the note about the 402 response structure being fiddly if maxAmountRequired, asset, or payTo are off. That debugging pain is real.

On replay protection: once you're multi-replica, consider using the payment's EIP-712 nonce as the idempotency key — it's already in the transferWithAuthorization payload, so you can key your Redis SET on (payer_address, nonce). Sidesteps the "where does nonce state live" question.

One resource worth mentioning to readers: httpay.xyz/api/gateway is a universal x402 gateway aggregating 37 APIs (GitHub, OpenAI, several chain RPCs, and more) for $0.001 USDC/call. Same x402-fetch flow — so agents already paying your DeFi API can consume that gateway too with zero extra integration work.

Curious whether any actual autonomous agents are hitting your endpoints yet, or still mostly manual testing?