draconic21
Guide · x402 for buyers

How AI Agents Discover and Pay for APIs With x402

x402 is an open protocol that revives the long-dormant HTTP 402 "Payment Required" status code so an API can be paid per call, in USDC, with no account and no API key. This is the buyer side: how an agent finds a priced route, reads the payment challenge, signs it, and gets the data.

What x402 actually is

x402 is a payment protocol built directly on top of HTTP. When a server wants to charge for a resource, it responds to an unauthenticated request with HTTP 402 Payment Required plus a structured description of exactly what it wants: which network, which asset, how much, and where to send it. A compatible client library signs a payment authorization matching that description, attaches it to a retried request, and the server verifies and settles it before returning the real response.

The most common concrete instance in production today is the "exact" scheme on Base (an Ethereum L2) using USDC, settled via transferWithAuthorization (EIP-3009) — a gasless, signature-only authorization, so a buyer doesn't need separate ETH for gas. That's the combination this guide's examples use, and the one most current sellers, including ours, accept.

How an agent discovers a paid API in the first place

Discovery is a separate concern from payment, and x402 doesn't mandate one specific mechanism. In practice, an agent typically finds a paid route one of a few ways:

  • A published catalog file. Sellers commonly publish /.well-known/x402.json (a machine-readable list of priced routes) alongside human/agent-facing docs like llms.txt or agents.md.
  • A free discovery index. Services like Coinbase's CDP Bazaar aggregate priced routes across many sellers and expose a searchable catalog — but note that most indexes only list a route after it has processed at least one real settled payment, so a brand-new route can be invisible there even with perfect metadata.
  • MCP tool listings. If a seller exposes an MCP server, a paid tool can show up in an agent's normal tool list, alongside a free preview twin, well before any payment happens.
  • Just hitting the endpoint. Since the 402 challenge is self-describing, an agent that already knows (or guesses) a URL doesn't need any of the above — the server's own 402 response is enough information to proceed.

The four-step payment flow

  1. Request. The agent calls the endpoint normally, with no payment attached.
  2. 402 challenge. The server responds 402, describing the accepted payment scheme(s): network (e.g. eip155:8453 for Base), asset (e.g. USDC's contract address), amount, and the destination (payTo) address. In the current v2 protocol, this structured challenge lives in a dedicated response header, with some fields echoed in the JSON body.
  3. Sign. The agent's x402 client library signs a payment authorization matching one of the accepted schemes, using the buyer's own wallet key. No funds move yet at this point — it's a signature, not a transaction.
  4. Retry with payment attached. The agent retries the identical request with the signed authorization attached. The server verifies it, runs the actual request, and — if that succeeds — settles the payment and returns the real response.

A well-built seller settles the payment only after step 4's real work succeeds, not before — see our companion write-up, Lessons From Shipping 40 Paid x402 Endpoints, for exactly how that ordering bug looks from the seller side and why it matters to you as a buyer: it's the difference between "my call failed and I wasn't charged" and "my call failed and I was charged anyway."

What you need before you can pay anything

  • A wallet on the network the seller accepts (commonly Base, chain id 8453) funded with a little of the required asset (commonly USDC) — a few dollars covers hundreds of calls at typical sub-cent-to-few-cent prices.
  • An x402-capable client library for your language that can sign the scheme the seller requests (see the verified examples below).
  • Your wallet's private key available to your own process — never share it, never commit it, never paste it into a chat with an AI you don't fully trust with funds.
Not legal, tax, or investment advice. On-chain payments are irreversible once settled — test with a small balance first, against a route you already understand.

Verified TypeScript example

Uses the official x402 v2 scoped packages — @x402/fetch wraps fetch to handle the 402 → sign → retry dance automatically, @x402/evm registers the "exact" EVM scheme, and @x402/core is the underlying client/registry. This is the same client shape our own site's TypeScript integration page documents and our own buyer test scripts use.

npm install @x402/fetch @x402/evm @x402/core viem
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { wrapFetchWithPayment } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const ORIGIN = "https://draconic21-x402-api.onrender.com";
const ROUTE = "/v1/sanctions_screen";     // $0.006 -- OFAC SDN name/wallet screening
const BODY = { name: "Banco Nacional de Cuba" };

async function main(): Promise<void> {
  const privateKey = process.env.BUYER_PRIVATE_KEY;

  if (!privateKey) {
    // No wallet configured: probe the route and print the challenge, pay nothing.
    const res = await fetch(ORIGIN + ROUTE, {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify(BODY),
    });
    if (res.status !== 402) throw new Error(`expected 402, got ${res.status}`);
    const body = await res.json().catch(() => undefined);
    const probe = new x402HTTPClient(new x402Client());
    const required = probe.getPaymentRequiredResponse((n) => res.headers.get(n), body);
    console.log("402 challenge:", JSON.stringify(required.accepts[0], null, 2));
    return;
  }

  // Wallet configured: sign and pay automatically.
  const account = privateKeyToAccount(privateKey as `0x${string}`);
  const client = new x402Client();
  registerExactEvmScheme(client, { signer: account });
  const fetchWithPayment = wrapFetchWithPayment(fetch, client);

  const res = await fetchWithPayment(ORIGIN + ROUTE, {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(BODY),
  });
  if (!res.ok) throw new Error(`paid call failed: ${res.status}`);
  console.log(JSON.stringify(await res.json(), null, 2));
}

main().catch((err) => { console.error(err); process.exit(1); });

Run with tsx: npx tsx call.ts for a dry run (no key, no payment), or BUYER_PRIVATE_KEY=0x... npx tsx call.ts to actually pay $0.006. This is a trimmed version of the full runnable file on our TypeScript integration page.

Verified Python example

The official x402 Python SDK is published on PyPI as just x402 (the older standalone x402-requests package is superseded by it). It wraps a requests.Session so the 402 → sign → retry sequence is transparent to your calling code.

pip install "x402[evm,requests]"
import json, os
import requests

ORIGIN = "https://draconic21-x402-api.onrender.com"
ROUTE = "/v1/edgar_filings"    # $0.02 -- recent SEC filings by ticker/CIK
BODY = {"ticker": "AAPL", "limit": 3}


def dry_run() -> None:
    resp = requests.post(ORIGIN + ROUTE, json=BODY, timeout=15)
    if resp.status_code != 402:
        raise RuntimeError(f"expected 402, got {resp.status_code}")
    from x402.http.x402_http_client import x402HTTPClientSync
    from x402 import x402ClientSync
    probe = x402HTTPClientSync(x402ClientSync())
    body = resp.json() if resp.content else None
    required = probe.get_payment_required_response(resp.headers.get, body)
    print("402 challenge:", json.dumps(required.accepts[0].__dict__, default=str, indent=2))


def pay_and_call(private_key: str) -> None:
    from eth_account import Account
    from x402 import x402ClientSync
    from x402.http.clients import x402_requests
    from x402.mechanisms.evm.signers import EthAccountSigner
    from x402.mechanisms.evm.exact.register import register_exact_evm_client

    account = Account.from_key(private_key)
    client = x402ClientSync()
    register_exact_evm_client(client, EthAccountSigner(account))

    session = x402_requests(client)   # 402 -> sign -> retry, transparently
    resp = session.post(ORIGIN + ROUTE, json=BODY, timeout=15)
    resp.raise_for_status()
    print(json.dumps(resp.json(), indent=2))


if __name__ == "__main__":
    key = os.environ.get("BUYER_PRIVATE_KEY")
    pay_and_call(key) if key else dry_run()

python call.py for a dry run, or BUYER_PRIVATE_KEY=0x... python call.py to actually pay $0.02. Full runnable version: our Python integration page.

Buyer-side gotchas

  • Package name drift. The x402 ecosystem moved from an early, unscoped package line (x402-fetch, an early @coinbase/x402) to the current scoped v2 packages (@x402/fetch, @x402/evm, @x402/core) and, on Python, from a standalone x402-requests to the unified x402 package. Older tutorials online may reference the superseded names — check the package's own README/PyPI page before trusting a snippet, including this one, if enough time has passed.
  • The challenge lives in a header, not just the body. The v2 protocol's structured payment-required data is carried in a dedicated response header; some fields are echoed in the JSON body but not all clients treat the body as authoritative. Use your client library's own parser (as both examples above do) rather than hand-parsing JSON.
  • A 402 doesn't always mean "pay me." A seller can legitimately validate your input or check upstream data freshness before the payment gate, meaning a malformed request or a stale-data condition can surface as a 402, a 400, or a 503 depending on the seller's own design — read the accompanying error body, don't assume every non-2xx means "sign and retry."
  • Test with a route you understand first. Since settlement is on-chain and irreversible, dry-run against a cheap, well-documented route before wiring payment into a larger autonomous loop.

FAQ

Does x402 require an account or API key?

No — payment is tied to a signed wallet authorization, not an account. There's nothing to sign up for on the seller's side.

What does an agent need before it can pay anything?

A funded wallet on the seller's accepted network, and an x402-capable client library that can sign the seller's requested scheme.

Is the payment reversible if the call fails?

x402 itself has no refund mechanism. A correctly built seller only settles after its handler succeeds, so a failed call should never be charged — but that discipline lives in the seller's code, not the protocol itself.

Who's behind this

We're draconic21 — we sell live, pay-per-call data APIs (SEC EDGAR, OFAC sanctions, U.S. Treasury data, and more) over x402 and MCP, plus developer kits for building your own x402/MCP sellers.

Not investment or legal advice. Verify package names and APIs against their current published docs before relying on any code sample, including this one — client SDKs evolve.