x402

Pay per request with USDC on Base via x402. Exact and Upto schemes, Permit2 for metered tools, when you still need an API key.

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.

Routes that download or host media

Routes that copy media to our CDN charge for the files actually delivered, so the price depends on the request:

RequestOptions in the challengeYou pay
No media asked for (no downloadMedia / hostMedia)exact at the base priceThe base price
downloadMedia=true or hostMedia=trueupto first, then exact at the same maximumupto: only what was downloaded or hosted. exact: the maximum
GET /v2/instagram/media/{media}?include=files, GET /v1/tiktok/videos/downloadupto first, then exact at the maximumupto: the base price if no media was found, the full price otherwise. exact: the full price

A buyer that registers only ExactEvmScheme keeps working on every one of these routes and pays the maximum, as it always has. Register UptoEvmScheme as well to pay only what a credit payer would be charged. @x402/fetch picks the first option your client supports, so an upto-capable client uses upto automatically.

These routes: Instagram posts (downloadMedia), post download, profile posts, reels and tagged posts (hostMedia); TikTok videos (downloadMedia), video download and profile videos (hostMedia); Facebook profile posts, reels and photos (hostMedia). Pay-per-request MCP tools follow the same rule.

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 and a PAYMENT-REQUIRED header. The JSON body tells you to send an API key (most callers); the header is the x402 challenge.

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 has two endpoints:

  • https://api.socialfetch.dev/mcp — OAuth or x-api-key. Tools bill credits on your account (whoami, balance, and NL Ask always need this endpoint). No credentials returns 401.
  • https://api.socialfetch.dev/x402/mcp — anonymous walk-up. Paid tools challenge with x402; attach payment meta and settle in USDC (Exact + Upto, same Permit2 rule as HTTP).

Invalid Bearer or x-api-key returns 401 on either endpoint — no x402 fallback.

Further reading

On this page