BLUEHUBDEV

x402 payment flow

Pay-per-call USDC on Base. One signature, no accounts, no API keys.

The 4-step flow

  1. Client POSTs the request normally.
  2. Server returns HTTP 402 Payment Required with payment instructions (recipient, USDC amount, asset address).
  3. Client signs an EIP-3009 TransferWithAuthorization for that amount.
  4. Client retries with the X-Payment header → server validates, settles USDC, returns the real result.

Step 1 — Request without payment

HTTP request

POST https://blueagent.dev/api/x402/honeypot-check
Content-Type: application/json

{ "token": "0x..." }

Step 2 — Server returns 402

HTTP response

HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "accepts": [{
    "scheme":    "exact",
    "network":   "eip155:8453",
    "asset":     "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo":     "0xb058a1e305d9c720aa5b1bf42b6f2f6294b03b5f",
    "maxAmountRequired": "50000",
    "extra":     { "name": "USD Coin", "version": "2" }
  }]
}

maxAmountRequired is in USDC base units — 6 decimals. 50000 = $0.05.

Step 3 — Sign the authorization

Sign an EIP-3009 typed data structure with your wallet. Most wagmi / viem hooks handle this in one call:

TypeScript (viem)

import { signTypedData } from "viem/actions";

const signature = await signTypedData(walletClient, {
  account,
  domain: {
    name:              "USD Coin",
    version:           "2",
    chainId:           8453,
    verifyingContract: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
  },
  types: {
    TransferWithAuthorization: [
      { name: "from",        type: "address" },
      { name: "to",          type: "address" },
      { name: "value",       type: "uint256" },
      { name: "validAfter",  type: "uint256" },
      { name: "validBefore", type: "uint256" },
      { name: "nonce",       type: "bytes32" },
    ],
  },
  primaryType: "TransferWithAuthorization",
  message: {
    from:        account.address,
    to:          payTo,
    value:       BigInt(maxAmountRequired),
    validAfter:  0n,
    validBefore: BigInt(Math.floor(Date.now() / 1000) + 300),
    nonce:       randomBytes32(),
  },
});

Step 4 — Retry with X-Payment

HTTP request

POST https://blueagent.dev/api/x402/honeypot-check
Content-Type: application/json
X-Payment: <base64({ signature, authorization })>

{ "token": "0x..." }

Server validates the signature, settles USDC on-chain via the CDP x402 facilitator, runs the tool, returns the real JSON response.

💡 Use a client SDK

The whole flow is ~3 lines with @coinbase/x402 — handles 402 detection, signature, retry. No need to manually wire EIP-3009 unless you want to.

Quick reference

  • Network: Base mainnet (eip155:8453)
  • Asset: USDC native (0x833589fCD6…02913)
  • Facilitator: Coinbase CDP x402
  • Settlement window: validBefore set to ~5 min by convention
  • Revenue split: 80% to API provider, 20% to Hub treasury