Written by the Token Tails team. Facts checked against live data on ; sources are listed at the end.
x402 donations use the HTTP 402 Payment Required status to let a program, such as an AI agent, pay over plain HTTP: the server answers 402 with what it wants, the agent signs a USDC authorization and retries with it in a header, and the server answers 200. For a donation, the server can set payTo to the charity’s own wallet, so the money goes straight from the agent to the shelter and never touches the app in between.
This guide explains the flow, shows how we built it for a cat shelter with two payment schemes, and says plainly what has and has not run on mainnet.
Key takeaways
- x402 is an open standard: a 402 response lists the payment requirements, and the client retries with a signed payment in a header (
X-PAYMENTin x402 v1,PAYMENT-SIGNATUREin v2). - For USDC on EVM chains, the standard
exactscheme uses an EIP-3009transferWithAuthorization; a facilitator verifies it, settles it and pays the gas. - For gifts, set
payToto the shelter’s own wallet, not to a splitter contract. - Our second scheme,
onchain-receipt, needs no facilitator: the agent pays the split itself and the server checks the receipt. - Status:
exactpassed the x402.org facilitator’s verify step on a testnet. No mainnet x402 payment has happened yet.
How x402 works in four steps
x402 describes itself as “an open, neutral standard for internet-native payments”: when a request arrives without payment, “the server responds with HTTP 402, prompting the client to pay and retry.” Coinbase’s developer docs break the handshake into nine steps; for a donation they come down to four:
- Request. The agent calls a URL, for example
GET /shelter/agent/cat-card. - 402 with requirements. The server answers 402 with a JSON body. Each entry in
acceptsnames ascheme, anetwork, amaxAmountRequiredin the asset’s base units, theasset(the USDC contract), thepayToaddress and amaxTimeoutSeconds. - Signed payment. The agent signs a payment that fits one entry and retries the same request with a base64
X-PAYMENTheader. - Verify and settle. The server asks a facilitator to verify the payment, does its work, asks the facilitator to settle, and answers 200 with the resource and an
X-PAYMENT-RESPONSEheader that carries the transaction.
Those are the x402 v1 names, which the examples below use. Version 2 renames the headers (X-PAYMENT becomes PAYMENT-SIGNATURE, X-PAYMENT-RESPONSE becomes PAYMENT-RESPONSE), sends the requirements in a PAYMENT-REQUIRED header, and names networks in CAIP-2 form, such as eip155:84532 instead of base-sepolia. Our endpoint answers in both versions and reads either payment header.
Nothing here needs an account, an API key or a card form, which is why x402 suits agents: a program can read a price, decide, and pay within a cap you give it.
The exact scheme for gifts: payTo is the shelter’s wallet
For tokens that support it, such as USDC, exact on EVM chains uses EIP-3009 (the v2 scheme spec also allows Permit2 for other ERC-20 tokens). The agent signs a TransferWithAuthorization from its wallet to payTo for the exact amount, with a random nonce and a short validity window. The facilitator submits it to the USDC contract and pays the gas. The signer never sends a transaction.
Our v1 402 body for exact on a testnet looks like this (shape from the Shelter Rail README):
{ "x402Version": 1, "error": "payment required",
"accepts": [{ "scheme": "exact", "network": "base-sepolia", "maxAmountRequired": "10000",
"payTo": "<the shelter's own wallet>", "asset": "<USDC>", "maxTimeoutSeconds": 120,
"extra": { "name": "USDC", "version": "2" } }] }
10000 is 0.01 USDC, because USDC’s ERC-20 interface uses 6 decimals.
Why not pay the ShelterSplit contract? Our USDC payment splitter pays every shelter in one transaction, but only when someone calls donate or disburse on it. transferWithAuthorization is a plain transfer: USDC would land in the contract without any split logic running, and it would sit there until the owner swept it. Anyone can also submit a transferWithAuthorization, so you cannot make a contract’s own code run as part of it. (DonateRouter solves this for gasless gifts with receiveWithAuthorization; see our EIP-3009 gasless donations guide.) Sending to the shelter’s wallet directly keeps the standard flow standard, and the money moves in one hop.
On a mainnet, our server only offers exact while payTo is the one wallet that chain’s split pays, read from the chain. Since 16 October 2026 that is Pink Paw’s wallet. Pink Paw (Rožinė pėdutė) is a cat shelter in Kaunas, Lithuania; Token Tails created the wallet, shelter staff hold the recovery phrase, and Token Tails keeps a recovery backup.
Our two schemes on one endpoint
The Token Tails API sells one small card at GET /shelter/agent/cat-card: a shelter cat’s name, photo and shelter. The whole price goes to shelters.
exact (standard) |
onchain-receipt (custom) |
|
|---|---|---|
| What the agent does | Signs an EIP-3009 authorization | Sends its own transaction to ShelterSplit with the memo x402:<nonce> |
payTo |
The shelter’s wallet | The ShelterSplit contract |
| Facilitator | Yes; it settles and pays the gas | None; the server reads the receipt over RPC |
| Chains | Networks a facilitator supports | Every chain with a split, including Arc and Tempo |
| Splits across several shelters | No | Yes |
onchain-receipt exists because standard facilitators may not support every chain we use. The agent pays the split (donate on Arc, approve plus disburse elsewhere, disburseWithMemo on Tempo), then retries with X-PAYMENT holding the transaction hash and the nonce. The server checks that the receipt succeeded and that the split emitted payout events with that memo adding up to the price.
When both are offered, accepts holds only the exact entry, because off-the-shelf clients such as x402-fetch parse every entry and throw on an unknown scheme. The custom offers move to a top-level onchainReceipts field.
Client code with payAndFetch
The Shelter Rail SDK (MIT, no dependencies) has an x402 client that handles both schemes:
import { payAndFetch } from "./src/sdk.mjs";
const { response, paid } = await payAndFetch("https://<api-host>/shelter/agent/cat-card", {
maxAmountBase: 10_000n, // cap: 0.01 USDC (6 decimals) for exact and token offers
provider: window.ethereum, // or signTypedData: async (typedData) => sig, account: "0x..."
});
console.log(await response.json(), paid?.txHash);
At least one cap is required: maxAmountBase for 6-decimal offers and maxAmountWei for native USDC on Arc (18 decimals). payAndFetch refuses any price above its cap, pays at most once per call, and passes any non-402 response straight through. For an agent that runs without a person watching, the cap in code is useful, but a cap the chain enforces is stronger; that is the idea behind our CappedSpender contract.
The repo also has examples/agent-pay.mjs, a Node agent that refuses any chain that is not a known testnet and, without --yes, only prints the offers.
Replay and abuse protection
Payments that can be retried need to be counted exactly once. What the server does:
- Nonces expire and are spent once. An
onchain-receiptnonce must be one the server issued, unused, and less than 600 seconds old. - A transaction pays for one card. Every accepted transaction hash is stored under a unique index; a second use gets a 402 that says so.
- The authorization is claimed first. For
exact, the server records the signer and the EIP-3009 nonce before it calls the facilitator, so two identical requests in parallel cannot both settle. - Read back from the chain. After settlement, the server re-reads the USDC
Transferlog. A payment it cannot confirm on chain is stored but left out of the public totals. - Prices are per chain, in that chain’s units, and every refusal is a fresh 402 whose
errorsays why.
Status, stated honestly
- The
exactflow was tested on Base Sepolia, a testnet: the off-the-shelfx402-fetchclient parsed our 402, signed, and its payment passed our server’s checks and the public x402.org facilitator’s/verify. A full settlement through that facilitator has not been run yet. - No x402 payment of either scheme has happened on any mainnet. You can check: x402 payments carry an
x402:memo, and /shelter-payouts lists every mainnet payout with its memo. - On mainnet,
exactis not offered yet: it still needs a facilitator account and the server settings for it. A mainnet chain gets any x402 offer only after the shelter’s wallet check passes there.
We would rather publish this as working, open code with a testnet result than claim traffic that does not exist.
When x402 fits a nonprofit, and when a button is better
x402 fits when the payer is a program: an AI agent with a budget, a paid API whose fee goes to a cause, or a “pay a cent to unlock this” step in a tool. It is machine-readable, needs no account, and with payTo set to the charity’s wallet the app never holds the money.
For people, a crypto donation button is usually better: a person wants to choose an amount, see their wallet prompt and get a thank-you, not handle a 402. Many nonprofits will want both: the button for supporters, and an x402 endpoint for agents.
Whichever you choose, publish who holds the receiving wallet and let anyone check the payouts on chain.
Frequently asked questions
Who pays the gas in an x402 payment?
With the standard exact scheme, the facilitator submits the signed USDC authorization and pays the gas. The agent only signs. With our custom onchain-receipt scheme, the agent sends its own transaction and pays its own gas.
Can the agent or the facilitator change payTo?
No. payTo, the amount and the validity window are inside the EIP-3009 signature. Changing any of them makes the signature invalid. The server, not the agent, chooses payTo, and ours only offers the wallet the chain's split pays.
Does x402 need a facilitator?
The standard exact scheme uses one to verify and settle the payment. It is not required by HTTP 402 itself: our onchain-receipt scheme has no facilitator, because the server reads the transaction receipt from the chain directly.
Has Token Tails received an x402 payment on mainnet?
Not yet. The exact scheme passed the public x402.org facilitator's verify step on Base Sepolia, a testnet. No mainnet x402 payment of either scheme has happened so far.
Check it yourself
Facts checked against live data on . Live figures change: the links below always show the current ones.
- x402 (official site)(opens in a new tab)
- Coinbase Developer Platform: how x402 works(opens in a new tab)
- x402 reference implementation (GitHub)(opens in a new tab)
- x402: migrating from v1 to v2(opens in a new tab)
- x402 exact scheme on EVM (spec)(opens in a new tab)
- EIP-3009: Transfer With Authorization(opens in a new tab)
- Shelter Rail SDK with payAndFetch (MIT)(opens in a new tab)
- Live payouts
- Impact: totals with dates and sources
- The open-source payout contracts (MIT)(opens in a new tab)




