A local CLI debugger for x402 — the HTTP-402-based agentic-payment protocol — on Base. Verified against real Base Sepolia + the production x402.org/facilitator, three independent live reconciliations on-chain (latest: 0x116ccf73…ba52).
Real-time capture of the RECONCILED ⚠ settled-but-server-thinks-not detection against live Base Sepolia + x402.org/facilitator. ~17 seconds, real on-chain tx. Cast file replayable with asciinema play examples/cast/e2e-timeout-reconciliation.cast.
- Your buyer's wallet was debited but the server says payment failed — the canonical coinbase/x402#1062 reconciliation gap.
x402trace proxy --reconciledetects it in seconds against live USDCTransferevents;x402trace inspectreplays captured logs offline. - You want to pre-flight a wallet before signing — USDC balance, EIP-3009 nonce status, wallet kind (EOA vs Smart Wallet).
x402trace validate <wallet> <service-url>is read-only and exits non-zero if the payment would fail. - You got a cryptic
Bad Gatewayor a generic 402 and need plain-English diagnosis.x402trace explain <jsonl-log>runs 10 diagnostic rules against captured payment state and tells you what was wrong, with actionable fixes per failure. - You're shipping an agent that pays for HTTP APIs and want a JSONL audit trail of every 402 / X-PAYMENT / settlement your client or server produced.
x402trace proxyrecords it.
BEFORE SIGNING DURING PAYMENT POST-SETTLEMENT ON FAILURE
──────────────────── ────────────────────── ────────────────────── ─────────────────────
┌──────────────────┐ ┌──────────────────┐ ┌────────────────────┐ ┌───────────────────┐
│ validate │ │ proxy │ │ inspect │ │ explain │
│ ───────── │ │ ───── │ │ ─────── │ │ ─────── │
│ Pre-flight a │ │ Live capture │ │ Offline replay │ │ Plain-English │
│ wallet against │ │ of every │ │ of a captured │ │ diagnosis of │
│ a service's │ │ X-PAYMENT │ │ log + re-run │ │ every failed │
│ 402 challenge │ │ exchange │ │ reconciliation │ │ exchange │
└──────────────────┘ └──────────────────┘ └────────────────────┘ └───────────────────┘
USDC balance JSONL audit log settled_on_chain actionable fix
EIP-3009 nonce Joins on-chain not_settled per failed rule
Wallet kind USDC Transfers value/recipient_ (10 rules)
by EIP-3009 nonce mismatch
You wire up x402 on Base Sepolia. A buyer sends X-PAYMENT. The facilitator broadcasts the EIP-3009 transferWithAuthorization — and then hangs. Your paymentMiddleware times out and your client gets back:
HTTP/1.1 502 Bad Gateway
content-type: text/plain
Bad Gateway
The buyer sees a failure. The buyer's wallet was actually debited. The on-chain receipt exists, but nothing in your logs points at it. You have no programmatic path to reconcile.
This is the #1062 gap. x402trace closes it.
Requires Node ≥ 20, pnpm, and a Base Sepolia test wallet funded with USDC + dust ETH. See
examples/README.mdfor the full prereq list.
# 1. Install
git clone https://github.com/fardinvahdat/x402trace.git
cd x402trace
pnpm install
# 2. Populate .env (one-time)
cp .env.example .env
$EDITOR .env # set PAYER_PRIVATE_KEY + RECEIVER_ADDRESS
# 3. Run the canonical #1062 demo (real Base Sepolia, ~17s)
./examples/e2e-timeout-reconciliation.shThe last line of output is the detection x402trace was built for:
RECONCILED ⚠ settled-but-server-thinks-not id=35d9aea1…
tx=0x116ccf73… value=1000 payer=0xADEe…B895 → payee=0xADEe…B895 gap=11904ms
That tx= field is a real Base Sepolia settlement — view it on basescan. An asciinema replay of the full run is committed at examples/cast/e2e-timeout-reconciliation.cast — asciinema play it locally.
npm install -g x402trace # or `pnpm add -g x402trace`, `npx x402trace --help`Requires Node ≥ 20.
┌────────┐ ┌────────────┐ ┌──────────┐ ┌─────────────────────┐
│ client │ ──► │ x402trace │ ──► │ your │ ──► │ x402.org/facilitator│
└────────┘ │ proxy │ │ server │ └──────────┬──────────┘
└──────┬─────┘ └──────────┘ │
│ ▲ │ /settle
│ │ slow/timeout broadcasts
│ │ ▼
│ ┌─────┴────────┐ ┌──────────────┐
│ │ reconcile │ ◄── │ Base Sepolia │
└──────────►│ engine │ │ USDC Transfer│
└──────────────┘ └──────────────┘
- Proxy — sits between the client and your x402 server. Captures every
X-PAYMENT/X-PAYMENT-RESPONSEheader to a JSONL log. - Decoder — turns each captured request into structured
PaymentRequirements/PaymentPayload/FacilitatorResponserecords. - Chain client — subscribes to Base Sepolia USDC
Transferevents, enriches each with the matching EIP-3009AuthorizationUsed.nonce. - Reconciliation engine — joins facilitator-rejected exchanges against on-chain transfers by
(payer, payee, value, nonce)and emitssettled_on_chain/not_settled/value_mismatch/recipient_mismatch.
Full architecture: ARCHITECTURE.md. Wedge rationale: DECISIONS.md → ADR-001. On-disk schema: src/decoder/schema.md.
# v0.1 — during/after payment
x402trace proxy --upstream <url> [--reconcile] [--log human|json] …
x402trace inspect <jsonl-log-file> [--log human|json] …
# v0.2 — before/explaining payment
x402trace validate <wallet> <service-url> [--strict] [--log human|json]
x402trace explain <jsonl-log-file> [--log human|json]The full pre/during/post-payment debugger:
validate <wallet> <service>— read-only pre-flight before signing. Fetches the 402, queries USDC balance + EIP-3009 nonce + wallet kind, runs 10 diagnostic rules, prints a plain-English report. Exits 0 if the payment would succeed, 2 if it would fail. Closes pain rank #4 (wallet-state pre-flight gap).explain <jsonl-log>— read a JSONL log produced byproxy --reconcile, find every exchange that didn'tsettled_on_chain, run the same rule engine against the captured state, print per-failure prose with actionable fixes. CI-friendly: exits 2 if any failures, 0 if clean. Closes pain rank #3 (generic 402 with no error reason).
The authoritative flag list is x402trace --help (or per-subcommand --help) — wired into the unit tests so it can't drift.
Compares your local package.json @x402/* versions and the service's 402 version hints against a bundled known-skew table. Catches the kind of multi-day debugging chase Myceliaman14 (Python SDK pre-v2 → TS V2 refactor) and Poteshniy (@x402/fetch 2.10.0 extension-echo bug) hit on Discord.
x402trace versions https://your-service.example/api/route
x402trace versions https://… --log jsonOutput names each match with severity (warning / blocking), the upstream evidence link (#2157, #2207), and a concrete fix. Exit 0 = no skew, 2 = at least one match.
When a payment works on one facilitator but fails on another (TerraDeed's CDP → xpay switch in the Discord transcript), --diff runs the same synthesised payload through both /verify endpoints in parallel and shows you exactly where they disagree.
# Built-in aliases: cdp, xpay, payai, x402.org. Full URLs also accepted.
x402trace validate 0xYourWallet https://your-service.example/api/route --diff cdp,xpay
# JSON output for CI; per-facilitator timeout knob
x402trace validate 0xYourWallet https://… --diff cdp,xpay --log json --diff-timeout-ms 5000Each row reports the per-facilitator HTTP status + body, captured rejection reason, and any X402-33 facilitator-aware rules firing (e.g. CDP minimum amount, throttling 403/429). Exit codes: 0 = at least one accepts, 2 = all reject, 3 = all timeout.
The headline of v0.3. Answers the question Discord operators are asking each other in real-time: "is my Bazaar / agentic.market integration implemented correctly, or is the bug upstream of me?"
# Default — Base Sepolia
x402trace bazaar-check https://your-service.example/api/route
# Mainnet (real funds in scope; banner printed)
x402trace bazaar-check https://your-service.example/api/route --chain base --rpc-url https://your-mainnet-rpc
# With a payer-hint (enables the self-payment guard)
x402trace bazaar-check https://your-service.example/api/route --payer-hint 0xYourPayerFour read-only checks compose into a single bottom-line verdict:
| Check | What it validates |
|---|---|
well-known |
/.well-known/x402 manifest exists with name + description + accepts[] |
challenge |
The protected endpoint returns 402 with a valid x402 v1/v2 body AND extensions.bazaar.{name, description} |
self-payment |
When --payer-hint is supplied, flags payer == payTo (CDP rejects this with a generic invalid_payload) |
indexing |
CDP discovery (/v2/x402/discovery/resources?payTo=…) returns non-empty resources (else: matches the #2207 upstream pattern) |
Exit codes:
0— looks correct2— found issues in your implementation (fix the failed check)3— your code looks correct; the bug is upstream (e.g. the canonical #2207 Bazaar indexing failure — 94 reports). The verdict prose names the GitHub issue so you don't have to map the symptom.
Scope notes:
- Read-only. Never signs, never broadcasts.
- The opt-in paid-pass mode (
--with-wallet) is deferred to v0.3.1 — see ADR-003. The static-analysis-only checks shipped here cover the dominant Discord pain (Bazaar indexing failure) without needing signing infrastructure.
x402trace v0.3 enables Base mainnet alongside the default Base Sepolia. The --chain flag (or BASE_CHAIN_ID env) selects the chain; default stays base-sepolia for backward compatibility.
# Default — Base Sepolia (unchanged)
x402trace proxy --upstream <url> --reconcile
# Base mainnet — RPC URL must be supplied; there is no built-in mainnet endpoint
x402trace proxy --upstream <url> --reconcile --chain base --rpc-url https://your-mainnet-rpc
# Validate a mainnet wallet (read-only)
x402trace validate 0xYourWallet https://your-service --chain base --rpc-url https://your-mainnet-rpcMainnet safety notes:
- x402trace never signs transactions and never broadcasts. The worst case from a misconfigured mainnet run is a failed read or a misleading reconciliation verdict.
- The buyer's wallet (which signs the EIP-3009 authorization) is upstream of x402trace. The buyer's risk model is unchanged.
- No mainnet RPC URL is shipped — supply your own via
--rpc-urlorBASE_RPC_URLenv. Mainnet startup prints a⚠ MAINNETbanner so accidental mainnet runs are visible at a glance. - CI never uses mainnet (CLAUDE.md hard rule #2). Don't commit a populated mainnet URL.
$ x402trace validate 0xADEeaf70…B895 https://example.com/api/weather
diagnose: ✓ would succeed
✓ network-match: network matches: base-sepolia
✓ recipient-match: recipient matches: 0x1111…1111
✓ value-sufficient: signed 1000 >= required 1000
✓ valid-before: validBefore=1778573803 is 300s in the future
✓ payer-balance: wallet has 5000000 USDC (raw), needs 1000
✓ nonce-fresh: nonce 0x000000… is fresh
✓ wallet-kind: wallet kind: eoa
✓ asset-address: asset is canonical Base Sepolia USDC
A failing run flips the headline to ✗ would fail and prints a fix: line under each failed rule.
$ x402trace explain ./x402trace.jsonl
─── exchange 94c15089… not_settled at 2026-05-12T08:13:18Z ───
diagnose: ✗ would fail
✗ valid-before: validBefore=1778573803 expired 97s ago (now=1778573900)
fix: re-sign the authorization with a later validBefore (typical: now + 300s)
explained 1 failed exchange(s), 0 decoder error(s) from 24 lines
Q: I see Bad Gateway from x402-fetch but my wallet was debited. What do I do?
That's the canonical coinbase/x402#1062. Run x402trace proxy --reconcile --upstream <your-server> between the buyer and your server; when the chain client matches the EIP-3009 nonce against a failed exchange you'll get a RECONCILED ⚠ settled-but-server-thinks-not record with the live tx hash.
Q: The facilitator returned invalid_payload with no explanation. How do I figure out why?
Save the captured 402 (proxy does this automatically) and run x402trace explain <log>. It runs 10 rules against the captured state — most invalid_payload cases turn out to be a validBefore expiry, value mismatch, or recipient mismatch, each rendered as a single failed rule with an actionable fix.
Q: Can I check whether a wallet can pay a service without actually signing?
Yes — x402trace validate <wallet> <service-url> is read-only. It fetches the 402, queries chain state (USDC balance, EIP-3009 nonce, wallet kind), runs the same rules explain uses. Exits 0 if would-succeed, 2 if would-fail.
Q: Does this work on mainnet? Not yet — v0.2 is Base Sepolia only per ADR-002. Mainnet support is on the v0.3 stretch list, gated on ≥1 week of clean testnet traffic.
Q: My supply-chain scanner shows transitive alerts on dependencies. Are these in x402trace?
No. As of v0.2.3 the runtime tree is commander + dotenv + viem + x402 only — the published dist/ imports nothing else. The test-tooling deps (hono, x402-fetch, x402-hono) are devDependencies and are not installed by npm i x402trace. Any wallet-SDK / WalletConnect / MetaMask transitives a scanner shows on the package come in via viem (read-only chain client). See SECURITY.md to report a vulnerability in x402trace itself.
- v0.1.0 (2026-05-12) — local proxy + timeout reconciliation. ADR-001.
- v0.2 (current) —
validate+explainon a shared diagnostic rule engine. ADR-002. - v0.3 stretch — mainnet, ERC-6492 wallet kind,
--diffcross-facilitator,bazaar-check, SDK-skewversionsaudit,--watchdaemon, reconciliation actions (webhook / auto-retry). Full list: SPEC.md § 5.
| Capability | x402trace | xpay | x402scan | x402lint |
|---|---|---|---|---|
| Local proxy + JSONL audit log | ✅ | — | — | — |
| Timeout reconciliation (catches #1062) | ✅ | partial | — | — |
| Pre-flight wallet check (no signing) | ✅ | — | — | — |
| Plain-English 402 diagnosis | ✅ | — | — | partial |
| Static config validation | partial | — | — | ✅ |
| Network explorer / discovery | — | — | ✅ | — |
| Spending controls | — | ✅ | — | — |
x402trace is the debugger in the x402 toolbox — built for the narrow, expensive moment when a payment fell into the gap between facilitator and chain. The other tools target adjacent jobs (routing, explorer, lint, controls) and compose well. Full comparison in SPEC.md § 8.
Personal project. PRs and bug reports welcome. Read in this order:
- CLAUDE.md — operating manual + hard rules
- TESTING.md — testing is a hard requirement, not a nice-to-have
- CONTRIBUTING.md — branching + PR workflow


