DEV Community

estell
estell

Posted on

Why Everyone Talks About x402 (This Week)

TL;DR

  • x402 revives HTTP 402 Payment Required for per-request payments.
  • Server replies 402 with how to pay; client retries with X-PAYMENT.
  • A facilitator verifies/settles on-chain; server returns 200.
  • Great fit for AI agents, paid APIs, and metered endpoints.

What is x402?

x402 is a protocol that embeds per-request payments straight into the HTTP flow. Instead of API keys or prepaid credits, your server can say “pay X in token Y on chain Z” via a 402 response. The client signs a payment payload and retries—result: no new transport, no exotic gateways—just HTTP.

Why it’s trending now

  • Fits how we already build: works with normal routes, middleware, and headers.
  • Perfect for agents: machine-to-machine payments without manual top-ups or accounts.
  • Lower integration friction: you can prototype with a thin client wrapper and a facilitator, then harden.

Developer mental model (fast)

  • It’s just HTTP: 402 to request payment, 200 on success, plus structured JSON and headers.
  • Two headers: client sends X-PAYMENT, server returns X-PAYMENT-RESPONSE (receipt/metadata).
  • Facilitator: handles on-chain verification/settlement so your app logic stays clean.

How it works (in one diagram)

Client ── GET /premium-data ───────────────▶ Server
        ◀─ 402 + { price, asset, chain } ────
Client signs payment payload
Client ── GET /premium-data + X-PAYMENT ───▶ Server
Server ── verify/settle ─▶ Facilitator ─▶ Chain
        ◀────────────────────────── 200 OK (+ X-PAYMENT-RESPONSE)
Enter fullscreen mode Exit fullscreen mode

Minimal code you can reason about

// Server (Express-style pseudo-code)
app.get("/premium", async (req, res) => {
  const payHeader = req.header("X-PAYMENT");
  if (!payHeader) {
    return res.status(402).json({
      x402Version: 1,
      accepts: [{
        scheme: "exact",
        network: "base-mainnet",
        asset: "USDC_ADDRESS",
        maxAmountRequired: "1000000", // 1 USDC (6 decimals)
        description: "Access: /premium",
        payTo: "0xMerchantAddress",
        resource: "/premium",
        mimeType: "application/json",
        maxTimeoutSeconds: 30
      }]
    });
  }

  const verified = await verifyAndSettle(payHeader); // via your facilitator
  if (!verified) return res.status(402).json({ error: "payment_required" });

  res.setHeader("X-PAYMENT-RESPONSE", buildReceipt(verified));
  return res.json({ data: "paid content" });
});
Enter fullscreen mode Exit fullscreen mode
// Client wrapper
async function fetchWithPay(url: string, init: RequestInit = {}) {
  const res = await fetch(url, init);
  if (res.status !== 402) return res;

  const reqs = await res.json();                 // payment requirements
  const choice = pick(reqs.accepts);             // choose chain/token
  const xPayment = await createPaymentHeader(choice); // wallet signs

  return fetch(url, { ...init, headers: { ...(init.headers||{}), "X-PAYMENT": xPayment }});
}

Enter fullscreen mode Exit fullscreen mode

Ship with eyes open

  • **Wallets & keys: **your client (or agent) must be able to sign. UX and limits matter.
  • Fees/finality: choose networks/tokens that make micro-payments sane; consider batching/deferred patterns.
  • Idempotency: protect against duplicates (receipts, request IDs).
  • Observability: log payment attempts, verification outcomes, and unlock decisions.

x402 & Embedded Wallets

If you want the x402 handshake without wrestling with wallet UX, key management, or gas policy, Openfort gives you embedded wallets, 4337/7702-ready flows, and paymaster/bundler infra that pairs neatly with per-request payments. We also wrote a dev-first explainer of the flow here: Inside x402: Enabling Payments with HTTP 402.

Have you put 402 in front of an endpoint yet? Share snippets below.

Top comments (0)