Skip to main content

What is x402?

x402 is an open payment protocol built on HTTP. When a server requires payment, it returns an HTTP 402 Payment Required response with a signed payment specification. The client signs a USDC TransferWithAuthorization and retries the request with the signature in the X-PAYMENT header. No API keys. No accounts. No redirects.

How it works with the checkout API

Agent                    Checkout API              Base (blockchain)
  │                           │                           │
  ├──POST /v1/checkout────────▶│                           │
  │◀──── 402 + payment requirements ──────────────────────│
  │                           │                           │
  │  [sign TransferWithAuthorization]                     │
  │                           │                           │
  ├──POST /v1/checkout + X-PAYMENT header ───────────────▶│
  │◀──── 202 {requestId} ────│                           │
  │                           │                           │
  ├──GET /v1/checkout/{id}────▶│                           │
  │◀──── {status: "processing"}                           │
  │   (poll every 5s)         │                           │
  │                           │                           │
  ├──GET /v1/checkout/{id}────▶│                           │
  │◀──── {status: "completed", orderNumber}               │
  │                           ├──USDC transfer────────────▶│
If the order requires a second payment (e.g. shipping adjustment), the poll response returns authorization_required and the agent calls POST /v1/checkout/{id}/authorize — which also triggers a 402 / sign / retry cycle.

Using the SDK

The simplest way to handle x402 is with the official SDK:
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { registerExactEvmScheme } from "@x402/evm/exact/client";

const client = new x402Client();
registerExactEvmScheme(client, { signer });

const fetchWP = wrapFetchWithPayment(fetch, client);

const res = await fetchWP("https://checkout-agent.credpay.xyz/v1/checkout", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(checkoutBody),
});
The signer must implement the ClientEvmSigner interface:
interface ClientEvmSigner {
  address: `0x${string}`;
  signTypedData: (message: EIP712Message) => Promise<`0x${string}`>;
  readContract: (args: ReadContractArgs) => Promise<unknown>;
}

Manual implementation

If you prefer to implement the payment flow manually:
  1. Make the initial request to /v1/checkout
  2. On a 402 response, parse the payment requirements from the response
  3. Sign a TransferWithAuthorization for USDC on Base (0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913, chain ID 8453)
  4. Retry the request with the X-PAYMENT header set to the encoded payment payload
The SDK handles expiry, nonce generation, and encoding automatically. Manual implementation is only recommended if you have a specific reason not to use it.