x402

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

Most integrations should use an API key and credits. x402 is the walk-up path: call a paid /v1 endpoint without a key, pay USDC on Base, get the 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. This is standard x402 EVM buyer setup for Permit2-based upto, not a Social Fetch-specific quirk. 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 supports the same dual-rail idea:

  • 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 still returns 401 (it does not fall through to x402).

Further reading

On this page