← Back to Blog
x402HTTP 402PaymentsUSDCBaseCryptoAPI

x402: The Payment Protocol That Makes HTTP 402 Useful

By BluePages Team·April 2, 2026·5 min read

HTTP 402 Payment Required has been in the HTTP spec since 1997. For nearly 30 years, it sat there with the note "reserved for future use." That future is here. The x402 protocol gives 402 an actual implementation -- one designed for machines paying machines.

What Problem Does x402 Solve?

Today, API monetization works like this: a developer signs up for your service, gets an API key, enters a credit card, and integrates your API into their application. This flow assumes a human in the loop at every step.

AI agents break this model. An autonomous agent that discovers your API at runtime cannot fill out a signup form, enter credit card details, or wait for an email confirmation. It needs to pay and access the API in a single HTTP round-trip.

x402 enables exactly that. The entire payment negotiation happens within standard HTTP headers, with no out-of-band registration required.

The x402 Flow

Here is the complete request lifecycle:

Step 1: Agent Makes a Normal Request

curl -X GET https://api.example.com/premium/data \
  -H "Accept: application/json"

Step 2: Server Responds with 402 and Payment Requirements

HTTP/1.1 402 Payment Required
X-Payment-Amount: 1000
X-Payment-Currency: USDC
X-Payment-Network: base
X-Payment-Address: 0x1234567890abcdef1234567890abcdef12345678
X-Payment-Nonce: abc123def456
Content-Type: application/json

{
  "error": "payment_required",
  "message": "This endpoint requires payment",
  "payment": {
    "amount": "1000",
    "currency": "USDC",
    "network": "base",
    "recipient": "0x1234567890abcdef1234567890abcdef12345678",
    "nonce": "abc123def456",
    "description": "Premium data access - single request"
  }
}

The amount is in the smallest unit of the currency. For USDC (6 decimals), 1000 means $0.001.

Step 3: Agent Makes the Payment On-Chain

The agent constructs and submits a USDC transfer on Base:

const tx = await walletClient.writeContract({
  address: USDC_BASE_ADDRESS,
  abi: erc20Abi,
  functionName: "transfer",
  args: [recipientAddress, BigInt(amount)],
});

// Wait for confirmation
const receipt = await publicClient.waitForTransactionReceipt({ hash: tx });

Step 4: Agent Retries with Payment Proof

curl -X GET https://api.example.com/premium/data \
  -H "Accept: application/json" \
  -H "X-Payment-Proof: 0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890" \
  -H "X-Payment-Nonce: abc123def456"

Step 5: Server Verifies and Responds

The server verifies the transaction on-chain:

  1. Checks the transaction hash exists on Base
  2. Confirms it is a USDC transfer to the correct recipient address
  3. Validates the amount matches or exceeds the required payment
  4. Checks the nonce to prevent replay attacks
  5. Returns the requested data
HTTP/1.1 200 OK
Content-Type: application/json

{
  "data": { ... }
}

Why USDC on Base?

Three properties make USDC on Base the right choice for machine payments:

Stablecoin eliminates price risk. If an agent pays 0.001 USDC, the API provider receives exactly $0.001 in value. With volatile tokens, the value of a payment could shift between the transaction and the confirmation.

Base has sub-cent transaction fees. A USDC transfer on Base costs fractions of a cent in gas. This makes micropayments economically viable. On Ethereum mainnet, a $3 gas fee would make a $0.001 API call absurd.

Settlement is final and verifiable. The server can verify payment by reading the blockchain directly. No payment processor, no chargebacks, no reconciliation delays. The proof is cryptographic.

Server-Side Verification

Here is how a server verifies payment proof using viem:

import { createPublicClient, http, parseAbiItem } from "viem";
import { base } from "viem/chains";

const client = createPublicClient({
  chain: base,
  transport: http(),
});

async function verifyPayment(txHash: string, expectedAmount: bigint, recipient: string) {
  const receipt = await client.getTransactionReceipt({ hash: txHash });

  // Find the USDC Transfer event
  const transferEvent = parseAbiItem(
    "event Transfer(address indexed from, address indexed to, uint256 value)"
  );

  const logs = receipt.logs.filter(
    (log) =>
      log.address.toLowerCase() === USDC_BASE_ADDRESS.toLowerCase()
  );

  for (const log of logs) {
    const decoded = decodeEventLog({
      abi: [transferEvent],
      data: log.data,
      topics: log.topics,
    });

    if (
      decoded.args.to.toLowerCase() === recipient.toLowerCase() &&
      decoded.args.value >= expectedAmount
    ) {
      return true;
    }
  }

  return false;
}

Key verification checks:

  • Transaction hash format: Reject malformed hashes before hitting the network
  • Confirmation count: Require at least 1 block confirmation to prevent reorg attacks
  • Recipient address: Verify the payment went to your address, not somewhere else
  • Amount: Confirm the transferred amount meets or exceeds the requirement
  • Nonce: Prevent the same transaction from being used to pay for multiple requests

How BluePages Implements x402

BluePages uses x402 as the payment layer for its skill directory. When an agent invokes a paid skill through BluePages, the flow is:

  1. Agent searches BluePages for a capability (e.g., "sentiment analysis")
  2. BluePages returns matching skills with pricing metadata
  3. Agent invokes the skill endpoint
  4. If payment is required, the endpoint returns 402 with x402 headers
  5. Agent pays via USDC on Base
  6. Agent retries with the transaction proof
  7. The skill executes and returns results

This means any API listed on BluePages can accept machine payments without building their own payment infrastructure. The x402 protocol handling is built into the platform.

Implementing x402 in Your API

Adding x402 support to an Express API takes about 50 lines of middleware:

function x402Middleware(priceInMicroUsdc: number) {
  return async (req, res, next) => {
    const proof = req.headers["x-payment-proof"];
    const nonce = req.headers["x-payment-nonce"];

    if (!proof) {
      const newNonce = crypto.randomUUID();
      storeNonce(newNonce); // Store for later verification

      return res.status(402).json({
        error: "payment_required",
        payment: {
          amount: String(priceInMicroUsdc),
          currency: "USDC",
          network: "base",
          recipient: WALLET_ADDRESS,
          nonce: newNonce,
        },
      });
    }

    // Verify the payment on-chain
    const valid = await verifyPayment(proof, BigInt(priceInMicroUsdc), WALLET_ADDRESS);
    if (!valid || !isValidNonce(nonce)) {
      return res.status(403).json({ error: "invalid_payment" });
    }

    consumeNonce(nonce);
    next();
  };
}

// Usage
app.get("/premium/data", x402Middleware(1000), (req, res) => {
  res.json({ data: "premium content" });
});

What Comes Next

x402 is still early. There are open questions around session-based payments (paying once for multiple requests), subscription models, and dispute resolution. But the core primitive -- machine-to-machine payment negotiated entirely through HTTP -- is working in production today.

If you are building an API that agents should be able to pay for, start by adding the 402 response with x402 headers. You can list it on BluePages to make it discoverable, and agents using the BluePages SDK will handle the payment flow automatically.

Share this article