x402 Dogfood · March 27, 2026 · Updated March 27, 2026 · Pedro Nunes

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 5: Authorization Proofs Are Not Transaction Hashes

We expected a completed transfer receipt. Instead, production header logging showed a signed authorization payload in X-Payment.

                {
  "x402Version": 1,
  "scheme": "exact",
  "network": "base",
  "payload": {
    "authorization": {
      "from": "0x43Ab546B...Edfed",
      "to": "0xEA63eF9B...2623",
      "value": "10000",
      "validAfter": "...",
      "validBefore": "...",
      "nonce": "0x..."
    },
    "signature": "0x..."
  }
}
              

This is an EIP-2612 transferWithAuthorization permit. The buyer is not saying "I already paid." The buyer is saying "Here is my signed permission to settle this payment." That is a different settlement model from the tx-hash flow we built.

Dimension tx_hash (what we built) Authorization proof (what awal sends)
Settlement timing Pre-settled. Buyer pays first. Post-settled. Seller or facilitator settles later.
On-chain gas Buyer pays gas. Facilitator or seller pays gas.
Replay protection Unique transaction hash. Nonce plus validity window.
Verification Look up transaction on chain. Verify signature, then settle.
Seller risk Effectively zero once confirmed. Seller trusts that settlement will succeed.

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.

  1. Initiated auth with npx awal auth login tommeredith@supertrained.ai
  2. Pulled the OTP from Gmail with gog gmail list --from no-reply@info.coinbase.com
  3. Verified the login with npx awal auth verify <flowId> 839762
  4. 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

Warning

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.

Warning

Asset selection

Send USDC, not USDT, ETH, or another token. Rhumb's x402 flow currently accepts USDC only on Base.

Warning

Network selection

Send on Base, not Ethereum mainnet, Arbitrum, Optimism, or Polygon. The address may look familiar while still being wrong for settlement.

Warning

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.