How Agents Actually Pay: What We Learned Dogfooding x402
Every x402 explainer tells you how the protocol should work. This one is about what happens when you ship it as a seller, point a real agent at production, and inspect the failures layer by layer until the wire-level truth becomes obvious.
Debugging
5h
Commits
8
Mismatches
5
Layers
6
What x402 Actually Promises (30-Second Version)
If you already know x402, skip to What Happened When We Tested It.
x402 uses HTTP's 402 Payment Required status code. The server returns a
machine-readable payment challenge, the client pays, retries with an X-Payment header, and the payment itself becomes authentication. No API
keys, no signup, no billing dashboard detour.
For sellers, that means any agent with a funded wallet can use your API immediately. For buyers, it means an agent can discover price, choose a route, and pay per call at the HTTP layer.
// What a 402 response looks like from Rhumb (additional fields omitted for clarity)
{
"x402Version": 1,
"accepts": [
{
"scheme": "exact",
"network": "base",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0xEA63eF9B4FaC31DB058977065C8Fe12fdCa02623",
"maxAmountRequired": "10000",
"resource": "https://api.rhumb.dev/v1/capabilities/search.query/execute",
"description": "Rhumb capability execution: search.query",
"mimeType": "application/json",
"maxTimeoutSeconds": 300,
"extra": {
"name": "Rhumb",
"version": "1",
"paymentRequestId": "390facca-..."
}
}
],
"paymentRequestId": "390facca-..."
}
That "10000"
value is USDC in base units with 6 decimals: one cent for a search execution. Rhumb also
includes a traditional checkout path, but the x402 path is what matters here.
What Happened When We Tested It
We pointed awal, Coinbase's agentic wallet CLI, at a live Rhumb execute endpoint. We expected the standard x402 flow. What we got instead was five hours of debugging that proved something more useful: interoperability can fail even when both sides think they are following the spec.
The failures were not random. They stacked in layers. Every fix revealed the next ambiguity.
Layer 1: Discovery Fails Immediately
We expected awal x402 details
to show our payment requirements. Instead, it reported that no x402 requirements
existed.
Root cause: awal discovers via GET, while our execute endpoint only
returned 402 on POST. We were technically strict. The buyer
was operationally practical. Those are different things.
Fix: Ship a GET discovery shim so
GET /execute returns the payment
challenge without attempting execution.
Commit 676fb69 - x402 GET discovery shim
Layer 2: The Network Name Nobody Agreed On
After discovery worked, awal failed payment parsing with "No network identifier found."
We used evm:8453, following the chain-id interpretation. Awal expected
base, the short human-readable name. Both are defensible. Only one
actually interoperated.
Fix: Change the network identifier in the
402 response to base.
Commit b144d72 - network naming for buyer compatibility
Layer 3: Field Placement - Top-Level vs Per-Entry
Awal still could not find maxAmountRequired or resource.
The values existed. They were simply in the wrong place for that buyer.
We stored those fields at the top level. Awal looked inside each entry in the accepts array. The x402 reference seller followed the per-entry shape, so
we aligned there.
Fix: Move all payment requirement fields
into each accepts[] entry.
Commit 5fa8731 - per-accepts-entry fields
Layer 4: Array Ordering Matters
Failures became intermittent because our accepts array listed
stripe_checkout before exact. Some buyers iterate
sequentially and stop at the first unsupported scheme.
Fix: Put crypto-friendly exact first.
Commit ccfc191 - exact scheme first
Discovery Finally Works
After four compatibility fixes, awal could finally discover Rhumb pricing correctly:
$ npx awal x402 details https://api.rhumb.dev/v1/capabilities/email.send/execute
Payment Requirements:
Version: 1
Scheme: exact
Network: base
Amount: 1000 (USDC base units = $0.001)
PayTo: 0xEA63eF9B4FaC31DB058977065C8Fe12fdCa02623
Price discovery was now operational. The real wall showed up only when we asked the buyer to actually pay.
Layer 6: The Honest Error
Before this session, a buyer who sent a valid standard authorization proof to Rhumb
would receive another 402. The buyer would retry. The server would return
402 again. That is the worst possible failure mode: an opaque payment
loop.
We changed that behavior to a structured 422 Unprocessable Entity that
states exactly what the server detected and what it supports today.
{
"error": "x402_proof_format_unsupported",
"message": "Detected a standard x402 authorization payload, but this execute endpoint currently verifies direct USDC transfer receipts by tx_hash.",
"resolution": "Retry with an X-Payment proof containing tx_hash, network, and wallet_address, or use a Rhumb API key / Stripe checkout.",
"compatibility": {
"detected_format": "standard_authorization_payload",
"supported_formats": ["legacy_tx_hash"],
"network": "base",
"scheme": "exact",
"payer": "0x43Ab546B...Edfed",
"pay_to": "0xEA63eF9B...2623",
"standard_authorization_supported": false
}
}
That one response turns "payment failed" into actionable diagnosis. The buyer can try another path, report the incompatibility, or wait for settlement support. Honest errors are more useful than silent standards theater.
Commit 0633daf - structured x402 proof-format detection + compatibility error
The Current State
Five parts of the stack are usable today. Settlement is the honest gap. We are publishing the gap now because seller-facing implementation detail is the missing documentation, not the polished success story that comes later.
| Layer | Status | Detail |
|---|---|---|
| Wallet setup | Ready | Agent bootstraps wallet autonomously (awal + email OTP). |
| Wallet funding | Ready | Human sends USDC on Base to the agent wallet. |
| Price discovery | Ready | GET /execute returns machine-readable 402 pricing. |
| Payment authorization | Ready | Buyer signs EIP-2612 authorization proof. |
| Settlement | Partial | Structured 422 exposes the honest gap instead of looping. |
| End-to-end execution | Partial | Pending settlement bridge for direct authorization proof support. |
What We Learned About Agent Wallets
The Agent Does More Than You Think
Beacon, our OpenClaw-based agent, bootstrapped its own awal wallet without human involvement. It initiated login, pulled the Coinbase OTP from Gmail, verified the session, and extracted the wallet address.
-
Initiated auth with
npx awal auth login tommeredith@supertrained.ai -
Pulled the OTP from Gmail with
gog gmail list --from no-reply@info.coinbase.com -
Verified the login with
npx awal auth verify <flowId> 839762 -
Read the wallet address with
npx awal address
Total human actions required: zero. Wallet auth is already agent-automatable if the agent controls the inbox.
The Human Does Less Than You Think
Funding is the irreducible human step. Someone still has to bridge fiat or existing crypto into the agent's wallet. The shortest path is simple: open Coinbase, send USDC to the wallet on Base, and stop there.
We funded the wallet with $5.00 USDC. That was enough for hundreds of paid executions while keeping the failure budget small.
Where Wallet Funding Goes Wrong
Address selection
Your agent wallet may expose both EVM and Solana addresses. USDC on Base uses the EVM address. Sending to the wrong one can strand funds.
Asset selection
Send USDC, not USDT, ETH, or another token. Rhumb's x402 flow currently accepts USDC only on Base.
Network selection
Send on Base, not Ethereum mainnet, Arbitrum, Optimism, or Polygon. The address may look familiar while still being wrong for settlement.
KYB wall
Business Coinbase accounts can stall on Know Your Business review for days or weeks. A personal account may be the only practical short path.
The Funding Paths
| Path | Time | KYC? | Best for |
|---|---|---|---|
| Personal Coinbase -> Base send | 2 min | Already done | Most developers |
| Any exchange -> Base withdraw | 5-10 min | Depends on exchange | If you do not use Coinbase |
| Bridge from Ethereum | 5 min + gas | No | If you already hold Ethereum-mainnet USDC |
| Fiat onramp (MoonPay, Transak) | 10 min | Light KYC | No existing crypto holdings |
| Another Base wallet | 30 seconds | No | Already have USDC on Base |
The Debugging Methodology: Progressive Header Sniffing
1. Start With a Known-Working Reference
Compare your 402 response field by field against a reference seller
before you start theorizing. Every mismatch is a possible protocol contract break.
2. Fix Discovery Before Payment
The error progression matters. "No payment requirements found" means discovery is broken. "No network identifier" means discovery works but parsing fails. "Authorized but rejected" means you have reached the settlement layer.
3. Capture What the Buyer Actually Sends
Do not infer from prose specs. Log the raw X-Payment header. That is how
we learned awal sends base64-encoded JSON containing an authorization proof rather than
a transaction hash.
4. Return Structured Errors, Not Silent Retries
A valid-but-unsupported payment format deserves a structured 422, not a
second 402. Otherwise agents cannot distinguish unpaid requests from
server incompatibility.
What This Means for the x402 Ecosystem
The Spec Needs a Conformance Suite
Three of our five bugs came from ambiguity, not bad implementation. Discovery method, network naming, and field placement should not be left to guesswork if interoperability is the point.
Sellers and Buyers Live in Different Worlds
Buyer-focused documentation usually asks whether the wallet has enough USDC and whether the price is fair. Sellers need answers to completely different questions: what proof format is arriving, who settles, and what error should the server emit when the proof is valid but unsupported.
Authorization Proofs Are the Future, But Settlement Is the Gap
The authorization-proof model is cleaner than tx-hash settlement: no buyer gas spend up front, replay protection via nonces, and a stronger fit for autonomous HTTP payment. But mainnet sellers still need a settlement layer. The public x402 facilitator only covers Base Sepolia today, so mainnet sellers either implement local settlement or surface the gap honestly.
Honest Errors Are a Competitive Advantage
Returning a structured compatibility error is a small engineering choice with outsized ecosystem impact. Agents can route around an honest limitation. They cannot route around ambiguity.
Try It Yourself
Inspect Rhumb's x402 flow directly
Discovery and price checks are free. Execution is pay-per-call, with no signup required. If you want to watch the flow in the open rather than in a slide deck, this is the fastest path.
# See the 402 payment requirements
curl -X GET https://api.rhumb.dev/v1/capabilities/search.query/execute
# Check pricing programmatically
curl https://api.rhumb.dev/v1/pricing
# Set up awal and check the details
npx awal auth login your-email@example.com
npx awal x402 details https://api.rhumb.dev/v1/capabilities/search.query/execute
Updates
Settlement: local
transferWithAuthorization
verification on Base mainnet is spec'd and in progress.
Additional buyer testing: we plan to test beyond awal so interoperability does not depend on one buyer's assumptions.
Production metrics: once x402 volume is real, we will publish settlement time, success rate, and cost data.