Skip to main content
x402 is an open payment protocol from Coinbase that revives the HTTP 402 status code. The server answers a request with 402 Payment Required and a payment challenge; the client signs a payment payload that satisfies the challenge and resends it in an HTTP header; the server verifies and settles before returning the resource. The protocol is now stewarded under the Linux Foundation. x402’s production scheme is exact — pay a specific amount of a specific asset (typically USDC). The settlement mechanics differ by ecosystem: EVM chains use off-chain EIP-712 signatures over an ERC-3009 authorization, while Solana uses a signed SPL Token transfer.
x402 is one of the two paid-rail protocols SELAT can use; the other is MPP on Tempo. Among routed rails, MPP is the default — x402 is opt-in (preferProtocol: "x402" / --prefer-x402).

The x402 challenge

A SELAT/x402 402 challenge is a JSON object with an x402Version and an accepts[] array. Each accept entry describes one way to pay:
FieldMeaning
schemeThe payment scheme — exact for x402 production payments.
networkA CAIP-2 network id, e.g. eip155:8453 for Base.
assetThe token contract to pay in (USDC on most chains).
payToThe recipient address.
amount / maxAmountRequiredThe price in token base units. v2 uses amount; v1 uses maxAmountRequired.
maxTimeoutSecondsHow long the authorization stays valid.
extraScheme metadata — extra.name, extra.verifyingContract, extra.version.
The payer takes asset, payTo, and the EIP-712 verifyingContract from the live challenge rather than a static table, so a per-chain address list is never hardcoded.
Prices are token base units. USDC has 6 decimals, so divide by 1,000,000 for the USD amount — the payer falls back amount ?? maxAmountRequired to support both x402 v1 and v2 challenges.
SELAT detects x402 from a probe in two forms:
  • A base64-encoded JSON payment-required: response header.
  • A www-authenticate: X402 requirements="<base64 PaymentRequired JSON>" header (used by some services alongside the body header).
(MPP, by contrast, is detected from a www-authenticate: Payment ... challenge.)

Base (EVM)

On Base and other EVM chains, x402 payments are signed off-chain with EIP-712 typed data and settled in USDC. The signed object is an ERC-3009 TransferWithAuthorization:
TransferWithAuthorization {
  from        address
  to          address
  value       uint256
  validAfter  uint256
  validBefore uint256
  nonce       bytes32
}
USDC implements transferWithAuthorization natively, so a facilitator can submit the signed authorization on-chain — the payer needs no gas. SELAT signs exactly this shape (see GATEWAY_AUTH_TYPES in the payer).

Signer paths

The SDK and CLI support three signer models — see the Signers reference:

Circle Agent Wallet

The default. Signing goes through the Circle CLI (circle wallet sign typed-data), keeping keys in Circle’s MPC and out of the application process.

Raw private key

Dev only. --raw-key / SELAT_PRIVATE_KEY signs in-process via viem, bypassing Circle MPC.

Remote signer

For an HSM, KMS, or external wallet service that signs the typed data over a callback.
Circle Agent Wallets are smart-contract accounts (SCA). For a Gateway-batched payment, the authorization’s from must be the owner EOA that the SCA signature recovers to — not the SCA address. SELAT resolves this by signing a throwaway authorization in the exact GatewayWalletBatched EIP-712 domain and recovering the signer.

Direct (Gateway-batched) vs routed

When the upstream’s accepts list contains an exact entry on the expected eip155:<chainId> network whose extra.name is GatewayWalletBatched, SELAT settles DIRECT — batched through Circle Gateway, bypassing the router with no markup. Otherwise it routes the x402 payment through the SELAT Router via its /proxy?target= endpoint. Either way the payment payload is built by the SDK and sent base64-encoded in a payment-signature header. Supported EVM chains track Circle Gateway plus Arc: Base, Optimism, Arbitrum, and Arc. Base, Optimism, and Arbitrum also support gasless selat fund --method eco deposits (settling into Gateway on Polygon); Arc requires --raw-key (Circle’s MPC signer can’t sign Arc yet) and has no Eco funding. For the authoritative list your runtime accepts, run npx @selat-ai/selat-pay --list-chains.

Solana

x402 also defines an SVM path. Coinbase’s reference implementation and the @x402/svm package implement the exact scheme using SPL Token transfers, and Coinbase’s hosted facilitator lists Solana among its supported networks. The Solana model is account-based, not EIP-712: the client builds and signs a Solana transaction containing an SPL Token transfer, serializes it, and sends it in the payment header; the server deserializes, verifies, simulates, submits, and confirms. The payer needs a Solana keypair, a USDC Associated Token Account, USDC balance, and an RPC connection.
This is a protocol-level description of x402 on Solana, not a SELAT capability claim. In SELAT’s own code, Solana appears only in network normalization and discovery filters — there is no Solana signing or payment path in the payer or CLI today, and the supported settlement chains are EVM (Base/Optimism/Arbitrum/Arc). SELAT does not currently settle x402 on Solana.

When to prefer x402 vs MPP

  • x402 is the open Coinbase standard. SELAT can settle it DIRECT (Gateway-batched, no router markup) on Circle-supported chains — making direct Gateway-batched x402 the no-markup default route.
  • MPP is SELAT’s default among routed rails and settles on Tempo.
  • Route precedence in the payer: a free upstream is served as a logged passthrough; otherwise the default (no flag) prefers direct Gateway-batched, then routed MPP, then routed x402. --prefer-x402 swaps the routed order to x402-then-MPP (direct still wins); --prefer-mpp forces MPP even over direct.
  • Pass preferProtocol: "x402" (SDK) or --prefer-x402 (CLI) to opt out of the MPP default for routed payments.

Next