VetoVetoDocs
Guides

Merchant privacy

What an on-chain settlement reveals, what per-checkout receiving addresses hide, and the honest tradeoffs — plus where pooling fits for full revenue privacy later.

x402 settles on a public chain. That's what makes a receipt verifiable by anyone — and it's also what makes your revenue legible to anyone willing to read the ledger. This guide is an honest account of what's exposed, what you can do about it today with per-checkout receiving addresses, and where fuller privacy (pooling) fits later.

Read this as engineering, not a guarantee.

On-chain privacy is a spectrum of tradeoffs, not a switch. Nothing here makes settlement anonymous. The goal is to reduce what a passive observer can trivially aggregate — and to be clear about what still leaks.

What a settlement reveals

Each x402 settle is a USDC transfer the chain records permanently:

  • Your receiving address and the amount, timestamped.
  • The payer address (the agent's wallet).
  • A link, via the merchant receipt, from that on-chain transfer to a specific order.

If every order pays into one receiving address, that address becomes a public revenue meter: anyone can sum your turnover, count your orders, and chart your daily volume — without your cooperation. That's the baseline to improve on.

Today: per-checkout receiving addresses

Receiving is non-custodial and merchant-supplied — you bring the address; Veto only describes where the agent should pay. Nothing in the protocol requires that address to be the same across checkouts. The near-term privacy posture is to rotate the receiving address per checkout (or per small batch): derive a fresh address, point that session's pay_to at it, and sweep later.

rotating receiving per checkout (self-hosted sketch)
// Derive a fresh receiving address for THIS checkout (e.g. an HD wallet path you control),
// then build the config with that address. The manifest/quote advertise it as pay_to.
const address = deriveReceivingAddress(orderIndex); // your wallet's next address

const checkout = createCheckout({
  merchant: { id: 'acme', name: 'Acme', domain: 'shop.acme.example' },
  catalog,
  receiving: { x402: { chain: 'base', address, asset: 'USDC' } },
  policy: BALANCED(),
});

The receiving address lives on CheckoutConfig.receiving and is what the quote's pay_to points at. Rotating it is a deployment pattern you implement around the SDK — you own the key derivation and the sweep. The SDK is non-custodial; it never holds funds and never derives keys for you.

What rotation buys you

  • A passive observer can no longer point at one address and read your whole book.
  • Orders aren't trivially linkable to each other by a shared destination.

What rotation does not buy you — be honest

  • Amounts and timing are still public. Each transfer's value and timestamp are on-chain.
  • Sweeping re-links. The moment you consolidate rotated addresses into one treasury wallet, chain analysis can cluster them back together. Privacy from rotation lasts until you sweep.
  • Payer-side correlation. A repeat buyer's wallet can still link its own purchases across your rotated addresses.
  • Operational cost. More addresses means more key management and more sweep transactions (gas, bookkeeping). Rotation is a real engineering tax, not a free toggle.

Rotation raises the cost of aggregating your revenue. It does not make it private.

Later: pooling for full revenue privacy

The fuller story is pooling — many merchants' inflows settle into a shared pool, and payouts to each merchant are decoupled from the individual on-chain receipts. Done right, pooling breaks the direct, public line from "this transfer" to "this merchant's revenue," which rotation alone can't.

That capability is on the roadmap, not shipped. We'd rather say so plainly than imply a guarantee that doesn't exist yet. Pooling also carries its own tradeoffs you should weigh before you'd want it:

  • A custody/trust boundary. A pool that decouples payouts is, by construction, a party that briefly intermediates funds — a departure from the strictly non-custodial posture of per-checkout receiving. That's a real tradeoff, not a strict upgrade.
  • Verifiability tension. Mutual receipts work because the receipt points at a concrete on-chain settlement. Pooling has to preserve a verifiable link from an order to a real settlement without re-exposing the per-merchant revenue it's trying to hide. That's the hard part, and why it isn't a checkbox.
  • Compliance and reconciliation get more involved when inflows and payouts are decoupled.

Choosing a posture

The bottom line

  • Today: non-custodial, merchant-supplied receiving. Use one address for simplicity, or rotate per checkout to make revenue harder to aggregate — knowing amounts, timing, and sweeps still leak.
  • Later: pooling for fuller revenue privacy, with a real custody/verifiability tradeoff we won't paper over.

Privacy here is a dial you turn against operational cost and trust assumptions — not a setting that makes a public chain private.