An agent hits its spending cap, opens a request, and sends a person a link. The human pays with their own wallet — that payment is the approval — and the agent fetches the signed grant.
git clone https://github.com/nirholas/x402-approval-page && npm install && npm run dev| Route | Price | What you get back |
|---|---|---|
POST /requests | free | The approval link, the poll URL, and a one-time agentToken. Free by design — an agent that already hit its cap shouldn't pay more to ask for help. |
GET /requests/:id | $0.001 | The signed outcome as of right now: pending, approved (with the grant token and the human's on-chain receipt), declined (with their note), or expired. |
POST /requests/:id/approve | the amount itself | The human's route. Priced dynamically at exactly what the agent asked them to authorize, so the 402 challenge is the invoice. Returns the signed grant. |
POST /requests/:id/decline | free | Decline with an optional note, or withdraw your own request with the agentToken. Nobody should pay to say no. |
GET /a/:id · GET /requests · POST /verify | free | The human's page, recent requests, and signature verification. |
Call a paid route. The server answers 402 Payment Required with an accepts array holding both rails.
The 402 offers two rails — USDC on Base and USDC on Solana. The human's wallet picks one in the modal; the agent's x402 client picks one for its polls.
That rail's facilitator verifies and settles on-chain. The server holds no key and pays no gas.
The signed grant arrives in the response body — decision, amount, merchant, timestamp, and the transaction hash — with the receipt in X-PAYMENT-RESPONSE.
npm install && npm run dev # on :4040, both rails live open http://localhost:4040/ # play both sides # the agent half: opens a request, then polls until you decide PRIVATE_KEY=0xAgentWallet npx tsx examples/agent-client.ts
| Rail | Network | Asset | Pays to | Facilitator |
|---|---|---|---|---|
| EVM | base-sepolia (default) · base | USDC | 0x40252CFDF8B20Ed757D61ff157719F33Ec332402 | x402.org/facilitator |
| Solana | solana (default) · solana-devnet | USDC | WwwuGbqHrwF5RG89KhUbmRWEvjnRH9k5kVM5p7T3WwW | facilitator.payai.network |
Both entries appear in every 402. Pay in USDC on Base or Solana — your client picks the rail. Set PAY_TO_ADDRESS / SOLANA_PAY_TO_ADDRESS to receive the funds yourself.
A separate approved flag leaves two things to reconcile: a decision, and money that may or may not have moved. Here there is one event. The human's payment settles on-chain and the same response hands back a signed grant — decision, amount, merchant, timestamp, transaction hash — that the agent can present as proof that a person authorized this specific purchase for this specific amount.
That is also why the approve route has no fixed price. It is priced dynamically at the request's own amountUsd, so the 402 challenge is the invoice. Ask for $0.05 and the challenge says maxAmountRequired: "50000". A request that is already decided or expired has no price at all and answers 409 rather than taking money for nothing.
The approval page is server-rendered so the person sees this request — who is asking, for what, how much, and why the agent couldn't decide alone — before any wallet appears. The button is @three-ws/x402-payment-modal from the CDN: it reads the dual-rail 402 and drives Phantom for Solana or an EVM wallet for Base.
Its SIWX re-entry matters here more than anywhere else in the suite — someone who approves several of these a day signs in once instead of every time. Its client-side spending caps give the human the same guardrail the agent has.
| Repo | Role |
|---|---|
| x402-agent-wallet | Policy checks that tell an agent when it needs approval. |
| x402-mcp-commerce | The commerce toolbox whose spending-cap errors point here. |
| x402-agent-sandbox | Rehearse the whole escalation flow against fake merchants first. |
Agents find this service via skill.md and the machine-readable /.well-known/x402 manifest — indexable by x402scan.com, the x402 Bazaar, and agentic.market. Questions: nichxbt@gmail.com.