AgentBIT
← Blog · September 2, 2026

x402 payments fail on Base mainnet but work on Sepolia? Check your EIP-712 domain name

The symptom

Our x402 seller had a fully working end-to-end flow on Base Sepolia: HTTP 402 challenge, EIP-3009 TransferWithAuthorization signed by the buyer, verified and settled through the Coinbase CDP facilitator. First real payment on Base mainnet (eip155:8453), same code:

HTTP 402
{"error": "invalid_payload", "errorCode": "PAYMENT_VERIFICATION_FAILED"}

No revert reason, no hint about which field is wrong. The authorization amounts, addresses and timestamps were all correct.

The root cause

EIP-3009 authorizations are EIP-712 typed signatures, and the EIP-712 domain includes the token contract's name. That name is part of the signed digest — if the client signs against the wrong name, the signature recovers to a different address and verification fails.

Here is the catch nobody tells you about:

NetworkUSDC contractEIP-712 domain name
Base Sepolia (eip155:84532)0x036CbD53842c5426634e7929541eC2318f3dCF7eUSDC
Base mainnet (eip155:8453)0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913USD Coin

Same token, same version (2), different domain name per deployment. You can confirm it in the official x402 repo (python/x402/mechanisms/evm/constants.py) or by calling name() on each contract.

The fix

Your 402 response's accepts[].extra tells the buyer what to sign against. Make it per-network instead of hardcoding "USDC":

// seller side: PaymentRequirements.extra — per-network config
'extra' => [
    'name'    => $network === 'eip155:8453' ? 'USD Coin' : 'USDC',
    'version' => '2',
]

// buyer side (viem): sign against exactly what the seller advertises
const signature = await account.signTypedData({
  domain: {
    name: req.extra.name,          // do NOT hardcode "USDC"
    version: req.extra.version,
    chainId: Number(req.network.split(":")[1]),
    verifyingContract: req.asset,
  },
  types: { TransferWithAuthorization: [ /* EIP-3009 fields */ ] },
  primaryType: "TransferWithAuthorization",
  message: authorization,
});

After shipping this, the exact same payment settled on the first retry.

Takeaways

  • Never hardcode the EIP-712 domain name for a token — read it per network, ideally from the chain itself.
  • As a seller, put the correct extra.name in the 402 so compliant clients cannot get it wrong.
  • invalid_payload from a facilitator almost always means "the signature does not recover to from" — check the domain fields before anything else.
AgentBIT is a pay-per-call API platform for AI agents built on x402 — no signup, no API keys, USDC on Base. Machine-readable entry points: catalog.json · llms.txt · aggregated x402 discovery API · framework integrations.