x402

Pay per API call in USDC on Base — no API key required.

Use an API key and credits for most integrations. x402 lets you call paid /v1 routes without a key — pay USDC on Base, same JSON back.

Account routes (/v1/whoami, /v1/balance) and NL Ask (POST /v1/ask) always need an API key. They are not on the x402 rail.

Paid endpoints are also discoverable in the Coinbase x402 Bazaar catalog (HTTP and MCP).

How it works

  1. Call a paid endpoint without x-api-key.
  2. Read HTTP 402 and the PAYMENT-REQUIRED header (Base64 JSON — amount, network, pay-to, scheme).
  3. Sign the payment (wallet or @x402/fetch).
  4. Retry the same request with PAYMENT-SIGNATURE.
  5. On success, use the JSON body as usual; PAYMENT-RESPONSE is the settlement receipt.

Price matches the Starter pack list rate: $0.014 per credit. Metering is the same as the credits rail (including attempt floors on some search endpoints).

Optional: send a payment-identifier so retries stay idempotent.

Exact vs upto

The PAYMENT-REQUIRED challenge includes a scheme. Register both schemes on your buyer client so every paid route works.

SchemeWhen you see itBuyer setup
exactFlat-price routes (most endpoints)Sign each request. USDC uses EIP-3009 — no on-chain approve
uptoMetered routes (e.g. list/search that charge per returned record)Authorize a ceiling; settle charges only what was used. Needs a one-time Permit2 approve (below)

If you only register ExactEvmScheme, metered/upto calls will fail after the payment challenge.

One-time Permit2 approve

For upto on Base, your buyer wallet must approve the canonical Permit2 contract to spend USDC once:

  • USDC (Base): 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
  • Permit2: 0x000000000022D473030F116dDEE9F6B43aC78BA3

Call USDC.approve(Permit2, maxUint256) (or a large allowance) from the paying wallet. Exact / EIP-3009 routes do not need this. Standard x402 Permit2 setup — see the CDP / x402 buyer docs.

Distinguish HTTP 402

KindHow to tellWhat to do
Creditserror.code = "insufficient_credits" (API key present)Top up credits
x402 challengePAYMENT-REQUIRED header + error.code = "payment_required"Pay USDC and retry
Settle failederror.code = "payment_settlement_failed"Not a successful response — retry only with a new payment if needed

Do not treat every 402 as "out of credits." For walk-up pay, look for the PAYMENT-REQUIRED header. Full envelopes: Errors.

Try unpaid

curl -i "https://api.socialfetch.dev/v1/twitter/profiles/elonmusk"

Expect 402, a PAYMENT-REQUIRED header, and a JSON body pointing at this page (and the API-key quickstart).

Pay from Node

Install the official buyer helpers, then wrap fetch. Register Base (eip155:8453) and both Exact and Upto schemes.

npm install @x402/fetch @x402/evm viem
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { UptoEvmScheme } from "@x402/evm/upto/client";
import { privateKeyToAccount } from "viem/accounts";

const signer = privateKeyToAccount(
  process.env.EVM_PRIVATE_KEY as `0x${string}`,
);

const client = new x402Client()
  .register("eip155:8453", new ExactEvmScheme(signer))
  .register("eip155:8453", new UptoEvmScheme(signer));

const fetchWithPayment = wrapFetchWithPayment(fetch, client);

const res = await fetchWithPayment(
  "https://api.socialfetch.dev/v1/twitter/profiles/elonmusk",
);

console.log(res.status, await res.json());
console.log(res.headers.get("PAYMENT-RESPONSE"));

Keep the private key server-side. Prefer the official buyer quickstart for other languages (Go, Python, etc.).

MCP

MCP uses the same dual-rail model:

  • OAuth → tools bill credits on your account (whoami, balance, and NL Ask always need OAuth).
  • Anonymous (no Bearer) → paid tools challenge with x402; attach payment meta and settle in USDC (Exact + Upto, same Permit2 rule as HTTP).

Invalid Bearer returns 401 — no x402 fallback.

Further reading

On this page