DEV Community

Nikhil Ranka
Nikhil Ranka

Posted on

x402 Explained: HTTP-Native Micropayments for AI Agents (With Real Code)

x402 Explained: HTTP-Native Micropayments for AI Agents (With Real Code)

When building autonomous AI agents, we quickly run into an architectural bottleneck: monetization and resource allocation.

Traditional payment systems (Stripe, credit cards) are designed for humans. They require interactive OAuth flows, billing portals, and KYC. API keys mitigate this, but they require upfront manual provisioning, subscription commitments, and trust between the parties.

For an autonomous agent roaming the web, discovering services dynamically, and paying for atomic units of computation (e.g., "summarize this PDF for $0.01"), traditional infrastructure fails.

This is where x402 comes in. It is a implementation pattern utilizing the standard HTTP status code 402 Payment Required combined with ultra-low-cost L2 blockchains (like Base) and stablecoins (like USDC). It enables friction-free, machine-to-machine micropayments natively over standard HTTP headers.


The x402 Protocol Flow

The x402 handshake mimics standard challenge-response authentication protocol patterns.

┌──────────┐                 GET /api/resource                 ┌──────────┐
│          │──────────────────────────────────────────────────>│          │
│          │  402 Payment Required                             │          │
│          │  X-402-Payment-To: 0xAddress...                   │          │
│          │  X-402-Amount: 10000 (0.01 USDC)                  │          │
│  Agent   │  X-402-Token: 0x833... (USDC)                     │  Service │
│ (Client) │  X-402-Chain-Id: 8453 (Base)                      │ Provider │
│          │  X-402-Invoice-Id: uuid-123                       │ (Server) │
│          │<──────────────────────────────────────────────────│          │
│          │                                                   │          │
│          │  ─── Execute L2 Transaction (Base) ───            │          │
│          │                                                   │          │
│          │  GET /api/resource                                │          │
│          │  X-402-Payment-Proof: 0xTxHash...                 │          │
│          │  X-402-Invoice-Id: uuid-123                       │          │
│          │──────────────────────────────────────────────────>│          │
│          │  200 OK + Resource Data                           │          │
│          │<──────────────────────────────────────────────────│          │
└──────────┘                                                   └──────────┘
Enter fullscreen mode Exit fullscreen mode
  1. Discovery & Challenge: The agent requests a resource. The server denies it with an HTTP 402 Payment Required status, returning headers detailing the cost, target wallet, token contract, chain ID, and a unique invoice ID.
  2. Settlement: The agent resolves this on-chain by executing a token transfer.
  3. Redemption: The agent repeats the HTTP request, including the transaction hash as proof of payment. The server verifies the transaction on-chain and returns the payload.

The Code

Below is a complete, runnable TypeScript implementation of both the Agent (Client) and the Service Provider (Server) using standard modern web tools: Express for the server, and viem for EVM interactions on Base.

1. The Client (AI Agent Execution Loop)

The agent needs to intercept a 402 response, parse the payment instructions, sign and submit the transaction, and retry the request.


typescript
import { createWalletClient, http, erc20Abi } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { base } from 'viem/chains';

const PRIVATE_KEY = process.env.AGENT_PRIVATE_KEY as `0x${string}`;
const account = privateKeyToAccount(PRIVATE_KEY);

const client = createWalletClient({
  account,
  chain: base,
  transport: http('https://mainnet.base.org')
});

async function fetchPaidResource(url: string) {
  // 1. Initial Attempt
  let response = await fetch(url, { method: 'GET' });

  if (response.status === 402) {
    console.log('Payment Required (402). Parsing details...');
Enter fullscreen mode Exit fullscreen mode

Top comments (0)