Skip to main content

Command Palette

Search for a command to run...

x402 v2 Complete Guide - No More Version Confusion

v1 vs v2 differences, migration checklist, and working code for agent-to-agent payments.

Published
5 min read
U
I'm building payment rails for agent-to-agent payments

x402 v2 Complete Guide - No More Version Confusion

There's a Reddit thread from three weeks ago where a developer compiled everything about x402 into a single post because "a lot of the documentation is confusing due to differences between v1 and v2." That shouldn't be necessary. So here's the definitive reference.

v1 vs v2: What Actually Changed

x402 v1 was a proof of concept. Coinbase published it, it worked, and people started building on it. Then v2 shipped with breaking changes and no migration guide. That's where the confusion started.

Here's what's different:

Aspectv1v2
Payment headerX-PAYMENT with base64-encoded JSONX-PAYMENT with structured binary encoding
Token supportUSDC on Base onlyUSDC on Base, Etherlink, and any EVM chain
Facilitator modelSingle facilitator per serverMultiple facilitator support, facilitator discovery
Response codes402 Payment Required with JSON body402 Payment Required with structured X-PAYMENT-REQUIRED header
SettlementImmediate on-chain verificationDeferred settlement option (batch mode)
Signature schemeEIP-191 personal signEIP-712 typed data (structured, verifiable)

The biggest change is the signature scheme. v1 used personal_sign (EIP-191) - just signing a message string. v2 uses EIP-712 typed structured data, which means wallets can display exactly what's being signed. Better UX, better security, but completely incompatible signatures.

How x402 v2 Works (Step by Step)

1. Client Makes a Request

$ curl https://api.example.com/expensive-endpoint

2. Server Responds with 402

HTTP/1.1 402 Payment Required
X-PAYMENT-REQUIRED: {"scheme":"exact","network":"base","maxAmountRequired":"1000000","resource":"/expensive-endpoint","facilitator":"0xFac...","description":"API call - 1 USDC"}

The X-PAYMENT-REQUIRED header tells the client: what to pay, how much, on which chain, and to which facilitator.

3. Client Signs and Pays

import { createx402Payment } from 'agentwallet-sdk/x402';

const paymentHeader = await createx402Payment({
  amount: '1000000',           // 1 USDC (6 decimals)
  network: 'base',
  facilitator: '0xFac...',
  resource: '/expensive-endpoint',
  signerPrivateKey: process.env.AGENT_PRIVATE_KEY,
});

4. Client Retries with Payment

$ curl https://api.example.com/expensive-endpoint \
  -H "X-PAYMENT: ${paymentHeader}"

5. Server Verifies and Serves

The server (or its facilitator) verifies the EIP-712 signature, confirms the USDC transfer on Base, and returns the response.

Setting Up an x402 Server (v2)

Here's a minimal Express server that accepts x402 payments:

import express from 'express';
import { verifyX402Payment, X402Middleware } from 'agentwallet-sdk/x402';

const app = express();

// Protect any route with x402
app.use('/api/premium', X402Middleware({
  amount: '1000000',           // 1 USDC per request
  network: 'base',
  facilitatorAddress: process.env.FACILITATOR_ADDRESS,
  rpcUrl: 'https://mainnet.base.org',
}));

app.get('/api/premium/data', (req, res) => {
  res.json({ data: 'premium content' });
});

app.listen(3000);

The middleware handles the 402 response, payment verification, and settlement. Your route handler only runs after payment clears.

Common Mistakes (and How to Avoid Them)

1. Using v1 signatures with v2 servers. If you're getting "invalid signature" errors, check which EIP your signing code uses. personal_sign (EIP-191) won't work with a v2 facilitator expecting EIP-712. There's no backwards compatibility.

2. Wrong USDC decimals. USDC has 6 decimals, not 18. 1000000 = 1 USDC. 1000000000000000000 = 1 trillion USDC. The number of people who've accidentally set their price to a trillion dollars is non-zero.

3. Hardcoding the facilitator address. Facilitators can change. Use the facilitator discovery endpoint if your SDK supports it, or at minimum make it a config value, not a constant.

4. Not handling the 402 response in agent loops. If your agent hits a 402 and doesn't have a payment handler, it'll either crash or loop forever. Build the payment flow into your agent's tool-use layer, not as an afterthought.

x402 v2 on Multiple Chains

v2 added multi-chain support. The network field in the payment-required header tells the client which chain to use. Currently live:

  • Base - The original and most liquid. 115M+ total x402 transactions.
  • Etherlink - Tezos L2. Lower fees, growing ecosystem.
  • Any EVM chain - The spec is chain-agnostic. If USDC exists on the chain and there's a facilitator, x402 works.

Your agent should read the network field and route to the correct chain. Don't assume Base.

x402 vs Traditional API Keys

Here's the question developers actually ask: why use x402 instead of a Stripe subscription?

x402 wins when:

  • Your users are AI agents, not humans (agents don't fill out Stripe Checkout forms)
  • You want per-request pricing, not monthly subscriptions
  • You want permissionless access (no API key registration, no KYC for $2 API calls)
  • Your service is consumed by many agents making small, infrequent requests

Traditional billing wins when:

  • Your customers are humans who want invoices
  • Usage is predictable and monthly billing is simpler
  • You need to identify customers for compliance
  • Transaction amounts are large enough that gas fees are negligible

For agent-to-agent commerce, x402 is the clear answer. For human SaaS, keep your Stripe integration.

Migration Checklist: v1 to v2

If you're running a v1 x402 server or client, here's what to change:

  1. Update signature generation from personal_sign (EIP-191) to EIP-712 typed data
  2. Update the 402 response format to use the structured X-PAYMENT-REQUIRED header
  3. Update payment header parsing on the server side (binary encoding, not base64 JSON)
  4. Test with a v2 facilitator (the v1 facilitator won't validate v2 signatures)
  5. Update your USDC contract address if you're on a new chain
  6. Add multi-chain support to your client if you want Etherlink or other chains

The agent-wallet-sdk x402 module handles all of this. If you're using the SDK, update to v5.0+ and the migration is automatic.

agent-wallet-sdk on npm

This article was written with AI assistance. All technical claims, code, and architectural decisions were validated by the author.