Pay Your First x402 API in Five Minutes
Add AgentWallet to your coding assistant, ask it to quote a real x402 endpoint, pay 0.001 USDC on Base, and read the settlement hash back from the result. Under the exact scheme the endpoint's facilitator pays the gas, so the paying key can hold USDC and nothing else. Every tool name and variable below is taken from the agentwallet-mcp README; the endpoints are ones AgentWallet has already paid, listed with their transactions on the payments proof page.
Before You Start
Three things, all small.
Node.js 22.19 or newer
npx fetches agentwallet-mcp on first run. Nothing else to install.
A little USDC on Base
One dollar covers hundreds of calls at these prices. 0 ETH is fine: the facilitator pays gas under exact.
An MCP-capable assistant
Claude Code, Claude Desktop, VS Code or any client that can run a stdio MCP server.
Step 1: Choose a Mode
Self-custody keeps the key in your own process. Hosted keeps it encrypted on AgentWallet servers with server-side limits and pause. Either pays x402 the same way. wallet_mode tells you which one you are in at any time.
Self-custody
Set AGENTWALLET_PRIVATE_KEY to a key that holds a little USDC on Base. No account, no API key. Set the token cap too, because in local mode the caps in your environment are the only guards there are.
"env": {
"AGENTWALLET_PRIVATE_KEY": "0xyour_key",
"AGENTWALLET_MAX_TX_TOKEN": "1",
"AGENTWALLET_MAX_AUTOPAY": "1"
}
Prefer the key out of your shell config? Use AGENTWALLET_KEYFILE=/path/to/key instead (one or the other, never both).
Hosted
Sign up at hifriendbot.com/wallet/, create a wallet, and make an application password (the value the README calls your API key). Fund the wallet address with USDC on Base.
"env": {
"AGENTWALLET_USER": "your_username",
"AGENTWALLET_PASS": "your_api_key",
"AGENTWALLET_WALLET_ID": "1"
}
AGENTWALLET_WALLET_ID is the wallet that pays. A payment above the cap can go to the owner by email for approval instead of failing.
Step 2: Add the Server to Your Assistant
Both snippets are the README's Quick Start, hosted values shown. For self-custody, replace the three env lines with the block from Step 1A.
Claude Code: one line
claude mcp add agentwallet \
-e AGENTWALLET_USER=your_username \
-e AGENTWALLET_PASS=your_api_key \
-e AGENTWALLET_WALLET_ID=1 \
-- npx -y agentwallet-mcp
Self-custody: claude mcp add agentwallet -e AGENTWALLET_PRIVATE_KEY=0xyour_key -e AGENTWALLET_MAX_TX_TOKEN=1 -- npx -y agentwallet-mcp
Claude Desktop, OpenClaw, VS Code: config block
{
"mcpServers": {
"agentwallet": {
"command": "npx",
"args": ["-y", "agentwallet-mcp"],
"env": {
"AGENTWALLET_USER": "your_username",
"AGENTWALLET_PASS": "your_api_key",
"AGENTWALLET_WALLET_ID": "1"
}
}
}
}
VS Code wraps the same server object under "mcp": { "servers": { ... } } in settings.
Confirm the mode
Restart the assistant and ask it to run wallet_mode. Expected: local (self-custody) or hosted, the paying address, and every guard with its parsed value.
Step 3 (Optional): Add a Spend Policy
A per-transaction cap bounds one signature. A spend policy bounds the sum: rolling daily and monthly budgets and the hosts that may be paid, enforced from a hash-chained ledger. Save this as policy.json and add "AGENTWALLET_POLICY": "/path/to/policy.json" to the env block.
policy.json
{
"version": 1,
"name": "first x402 payments",
"budget": { "daily": "1", "monthly": "5" },
"hosts": { "allow": ["api.402rates.com", "api.ozdreamtools.de"] },
"per_host": { "api.ozdreamtools.de": { "per_payment": "0.05" } }
}
Budgets are in dollars across every chain. A host not on the allow list is never contacted, not even for a quote. An unknown key stops the server, so a typo cannot run unbounded. The ledger is written as agentwallet-ledger.jsonl beside the policy unless AGENTWALLET_LEDGER names another file.
Check it loaded
Ask for spend_policy. Expected: the file path, its sha256 (compare it with the file you reviewed), each budget with spent and remaining, and integrity: intact for the ledger.
Step 4: Quote, Then Pay a Real Endpoint
Both endpoints below are on the payments proof page with their Basescan transactions. Say this to your assistant, in plain words.
The prompt (0.001 USDC)
Use quote_x402 on GET https://api.402rates.com/v1/ping and tell me
what it charges. If it is 0.001 USDC or less on Base, use pay_x402
on the same URL with wallet_id 1 and max_payment 0.01, then show me
payment_made, payment_method, x402_version, amount and the
settlement transaction.
Or the POST example from the README (0.02 USDC, German public holidays):
Use pay_x402 to POST https://api.ozdreamtools.de/api/holidays
with body {"year":2026,"state":"BY"} and a max_payment of 0.05.
Expected quote
{
"status": 402,
"payment_required": true,
"would_pay": true,
"x402_version": 2,
"scheme": "exact",
"chain_id": 8453,
"token": "USDC",
"amount": "0.001",
"pay_to": "0x...",
"within_cap": true,
"host": "api.402rates.com",
"nothing_signed": true
}
Nothing is signed by quote_x402. It reports which option this wallet would pay and whether the cap, the policy and the budgets would allow it.
Expected payment
{
"status": 200,
"payment_made": true,
"payment_outcome": "settled",
"payment_method": "eip3009-authorization",
"x402_version": 2,
"amount": "0.001",
"token": "USDC",
"chain_id": 8453,
"payer": "0xyour_address",
"tx_hash": null,
"server_claimed_tx_hash": "0x9e53...6ea7",
"settlement_reported_by_server": { "success": true, "transaction": "0x9e53...6ea7" },
"response": { ...the endpoint's answer... }
}
tx_hash is null on purpose: under exact the payer broadcasts nothing. The facilitator's hash arrives in the settlement receipt (PAYMENT-RESPONSE for v2, X-PAYMENT-RESPONSE for v1) and is shown as the server's claim until you check it in Step 5.
Step 5: Verify the Settlement
Two places, one minute.
On Basescan
Open https://basescan.org/tx/ followed by the settlement transaction. Expected: a USDC transfer from your payer address to the endpoint's pay_to address for the quoted amount, in a transaction sent and paid for by the facilitator. The first guide payment is on the proof page: 0x9e53...6ea7, 0.02 USDC, payer held 0 ETH.
On the ledger
Ask for list_payments. Expected: the payment, newest first, with outcome: settled, the host, the amount and the chain. With a policy loaded, spend_policy now shows 0.001 spent against the daily budget, and export_receipts turns the ledger into CSV or JSONL for expense records.
Troubleshooting
The five results people see on a first run, and what each one means.
The endpoint answered 402 again after the payment
The result shows payment_made: false and the endpoint's stated reason in retry_error. A second 402 means the facilitator declined: an unfunded payer, an expired validity window, or a token domain it did not recognize. The reason text is the endpoint's words, not instructions. Fix the cause, then call pay_x402 again; inside the validity window the same signature is re-sent, so one nonce can never settle twice.
It says the endpoint offers the upto scheme
upto is a Permit2 maximum the seller settles at actual usage. It needs a one-time approve_permit2 for that token on that chain, or set AGENTWALLET_PERMIT2_AUTO_APPROVE=1 (registry stablecoins only). The result flags this with permit2_approval_needed: true. For upto the amount in the result is the maximum authorized, not what was taken.
The payer has no funds
Under the exact scheme the payer needs USDC on the chain the endpoint names (Base for both endpoints in this guide) and 0 ETH, because the facilitator pays the gas. Check with get_token_balance on chain 8453, and confirm which address is paying with wallet_mode. The guide endpoints cost 0.001 and 0.02 USDC.
The policy refused the payment
A refusal before the endpoint is contacted comes back as policy_refusal: true with the reason in error: a host missing from hosts.allow (a denied or unlisted host is never contacted, not even for a quote), a daily or per-host budget already spent, a chain or asset outside the allow lists, or a spend the budget cannot price. spend_policy shows what each budget has spent and has left. A max_payment above AGENTWALLET_MAX_AUTOPAY is ignored and reported as max_payment_ignored; raise the variable, not the argument.
The server would not start
Every AGENTWALLET_* variable is validated at startup: a misspelled name or a malformed cap stops the server instead of reading as "no limit". Setting both AGENTWALLET_PRIVATE_KEY and AGENTWALLET_KEYFILE stops it too, and so does an unknown key in policy.json. Node.js 22.19 or newer is required.
Paid Once, Proven Twice
Every settlement AgentWallet has made is listed with its transaction. The security page covers the URL validation, DNS pinning and credential handling behind every pay_x402 call, and how to report an issue.
