cd /news/ai-agents/how-i-put-a-data-product-behind-x402… · home › topics › ai-agents › article
[ARTICLE · art-143595] src=dev.to ↗ pub= topic=ai-agents verified=true sentiment=↑ positive

How I put a data product behind x402 so AI agents can buy it with USDC

A developer built Scout Packs, a B2B lead-pack data product gated behind Coinbase's x402 protocol so AI agents can pay per purchase in USDC on Base without accounts, API keys, or subscriptions. The implementation returns HTTP 402 responses with machine-readable payment terms, verifies on-chain settlement via an X-Payment header, and exposes a /.well-known/x402 manifest plus an MCP server with list_packs and buy_pack tools. Packs sell for $9 (25 leads), $15 (50 leads), and $25 (100 leads), delivered as JSON.

by read3 min views2 publishedOct 2, 2026

I sell verified B2B lead packs. For a one-off campaign, a $49/month data seat is a terrible deal — and for an AI agent, a subscription signup is a non-starter. Agents can't fill out billing forms. So I put the product behind x402: HTTP 402 "Payment Required", resurrected as a machine checkout. Here's exactly how it works, with the real shapes and flows.

x402 (from Coinbase) turns the 402 status code into a payment handshake an agent can complete without human help:

402 with machine-readable payment terms in the body.X-Payment header carrying proof of payment. No accounts, no API keys, no OAuth dance for the buyer — the wallet is the identity, and the retry loop is the session.

The 402 body isn't an error page. It's an offer. Here's the actual structure I return:

{
  "x402Version": 1,
  "error": "Payment required",
  "accepts": [
    {
      "scheme": "exact",
      "network": "base",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "payTo": "0xYourTreasuryWallet",
      "maxAmountRequired": "9000000",
      "maxTimeoutSeconds": 300,
      "resource": "https://scoutpacks-tunnel-1.loca.lt/buy/pack-25",
      "description": "25 verified B2B leads, JSON",
      "mimeType": "application/json"
    }
  ]
}

The fields that matter:

payTo — your treasury wallet. The agent pays this address directly.maxAmountRequired — in the asset's base units. USDC has 6 decimals, so 9000000 = $9.00. This is the single most common bug I see: people write dollars and charge micro-cents.asset — the token contract (above is USDC on Base).network — base here. Match your payTo wallet to a chain you actually monitor.scheme — exact means exact-amount settlement.resource — which endpoint the terms apply to. I also serve a machine-readable manifest at /.well-known/x402 so agents can discover the catalog and terms before touching a paid endpoint — cheaper than learning via 402s.

Client side (the agent's wallet code):

import requests

URL = "https://scoutpacks-tunnel-1.loca.lt/buy/pack-25"

resp = requests.get(URL)
if resp.status_code == 402:
    terms = resp.json()["accepts"][0]
    payment_payload = sign_transfer(terms)  # base64, per the x402 spec
    resp = requests.get(URL, headers={"X-Payment": payment_payload})

resp.raise_for_status()
leads = resp.json()  # 200 — the goods

Server side (FastAPI-style):

@app.get("/buy/{pack_id}")
def buy(pack_id: str, x_payment: str | None = Header(default=None)):
    pack = CATALOG[pack_id]
    if x_payment is None:
        return JSONResponse(status_code=402, content=payment_terms(pack))
    verify_onchain(x_payment, pack)  # re-check amount, asset, recipient, settlement
    return deliver(pack)             # JSON leads: instant for the 25-pack

Three things worth internalizing:

maxTimeoutSeconds bounds how long the quote is valid; re-quote after it lapses./.well-known/x402 manifest, and delivery should all read the same catalog object. If price lives in three places, it will drift. Raw HTTP is fine, but agents live in tool-calling land. The repo ships an MCP server with two tools:

list_packs() — returns the catalog: pack sizes, prices, and exactly what each pack contains. No payment needed; this is the menu.buy_pack(pack_id) — runs the pay-and-retry flow above and returns the leads JSON. The MCP server reads the same catalog the 402 endpoint uses, so the menu and the checkout can never disagree. The pattern generalizes: list_* (free, discoverable) + buy_* (402-gated) is a good shape for any agent-sold data product.

Scout Packs is the live implementation of everything above: verified B2B lead packs for AI agents — 25 leads for $9, 50 for $15, 100 for $25. Every lead ships as JSON: company, contact, title, published email, plus the source URL it was verified against.

list_packs / buy_pack): If you're selling anything to agents — data, compute, API access — stop minting API keys and start returning 402s. The wallet is the account.

── more in #ai-agents 4 stories · sorted by recency
── more on @coinbase 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/how-i-put-a-data-pro…] indexed:0 read:3min 2026-10-02 · —