> ## Documentation Index
> Fetch the complete documentation index at: https://selat.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# x402

> The x402 payment protocol. Inbound USDC on EVM via Circle Gateway.

**x402** is an open payment protocol from Coinbase that revives the [HTTP 402](/docs/primers/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). Inbound to SELAT is USDC on EVM via Circle Gateway. The settlement mechanics differ by ecosystem: EVM chains use off-chain EIP-712 signatures over an [ERC-3009](/docs/primers/http-402) authorization, while Solana uses a signed SPL Token transfer.

<Note>
  x402 is one of the two paid-rail protocols SELAT can use; the other is [MPP on Tempo](/docs/primers/mpp-tempo). A Gateway-capable upstream defaults to x402 (same-rail passthrough); otherwise MPP is the default and x402 is opt-in (`preferProtocol: "x402"` / `--prefer-x402`).
</Note>

## 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:

| Field                          | Meaning                                                                       |
| ------------------------------ | ----------------------------------------------------------------------------- |
| `scheme`                       | The payment scheme — `exact` for x402 production payments.                    |
| `network`                      | A CAIP-2 network id, e.g. `eip155:8453` for Base.                             |
| `asset`                        | The token contract to pay in (USDC on most chains).                           |
| `payTo`                        | The recipient address.                                                        |
| `amount` / `maxAmountRequired` | The price in token base units. v2 uses `amount`; v1 uses `maxAmountRequired`. |
| `maxTimeoutSeconds`            | How long the authorization stays valid.                                       |
| `extra`                        | Scheme 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.

<Tip>
  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.
</Tip>

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](/docs/selat-sdk/signers):

<CardGroup cols={1}>
  <Card title="Circle Agent Wallet" icon="shield">
    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.
  </Card>

  <Card title="Raw private key" icon="key">
    Dev only. `--raw-key` / `SELAT_PRIVATE_KEY` signs in-process via viem, bypassing Circle MPC.
  </Card>

  <Card title="Remote signer" icon="server">
    For an HSM, KMS, or external wallet service that signs the typed data over a callback.
  </Card>
</CardGroup>

<Note>
  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.
</Note>

### Same-rail passthrough vs cross-protocol routing

Every paid call goes through the SELAT Router via its `/proxy?target=` endpoint — including upstreams that themselves accept Gateway-batched x402. (Earlier selat-pay versions paid Gateway-capable upstreams directly, bypassing the router; that mode was removed so every call is quoted, recorded, and reconciled.) What the upstream's `accepts` list controls is the **outbound protocol**: when it contains an `exact` entry on the expected `eip155:<chainId>` network whose `extra.name` is `GatewayWalletBatched`, the router settles the upstream leg as a **same-rail Gateway passthrough** (`routed-x402`, no cross-protocol translation); otherwise it translates to MPP or x402 `exact` on the outbound leg (EIP-3009 on EVM, TransferChecked on Solana). The payment payload is built by the SDK and sent base64-encoded in a payment-signature header, always signed in the one `GatewayWalletBatched` shape against the router's own 402 quote.

<Note>
  Cross-protocol calls (Gateway in → MPP/erc-3009 out) carry the router's flat, transparent \~5% markup. Same-rail Gateway passthrough is currently quoted **at par** (0%) — that is the operator's live behavior, not a protocol guarantee. The per-call 402 quote is always authoritative; inspect it with `--probe-only`.
</Note>

You **fund** on 7 EVM chains via Circle Gateway and the router **settles** merchants on Circle Gateway, Base, Tempo, or Solana — see [Chains](/docs/chains) for the full inbound/outbound split. Every deposit is gasless; Base also supports [`selat fund --method eco`](/docs/selat-cli) fast deposits (a \~30-second credit, settling into Gateway on Polygon).

## Solana

Agents pay in on EVM via Circle Gateway. The router settles x402 exact on Solana (SPL) outbound. Solana is not a fund chain.

x402 defines an SVM `exact` scheme: an **account-based SPL Token transfer**, not an EIP-712 authorization. Coinbase's reference implementation and the `@x402/svm` package implement that path — a signed Solana transaction that transfers USDC (an SPL Token) to the accept's `payTo`.

<Note>
  You still sign only the Gateway-batched quote.
</Note>

## When to prefer x402 vs MPP

* **x402** is the open Coinbase standard. A Gateway-capable upstream defaults to `routed-x402` — same-rail Gateway passthrough with no cross-protocol translation, currently quoted at par by the router.
* **MPP** is SELAT's default for upstreams without a Gateway-batched accept, and settles on [Tempo](/docs/primers/mpp-tempo).
* Route precedence in the payer: a free upstream is served as a logged passthrough (`routed-free`); a Gateway-capable upstream defaults to `routed-x402`; otherwise MPP wins (`routed-mpp`), falling back to `routed-x402` when only non-Gateway x402 is offered. `--prefer-x402` and `--prefer-mpp` override the default; they are mutually exclusive.
* Pass `preferProtocol: "x402"` (SDK) or `--prefer-x402` (CLI) to opt out of the MPP default.

## Next

* [HTTP 402 Payment Required](/docs/primers/http-402)
* [MPP on Tempo](/docs/primers/mpp-tempo)
* [Nanopayments powered by Circle Gateway](/docs/primers/nanopayments-gateway)
* [SELAT Router SDK](/docs/selat-sdk) · [Signers](/docs/selat-sdk/signers) · [selat CLI](/docs/selat-cli)
