DEV Community

minia2a
minia2a

Posted on • Originally published at minia2a.uk

Give Your AI Agent a Wallet — x402 Payment Protocol in Practice

The x402 protocol is simple: when an agent calls a paid API without payment, the server returns HTTP 402 with a payment invoice. The agent pays the invoice, retries with a payment proof header, and gets the result.

That's it. Three steps. No API keys, no signup, no monthly subscription. Here's how to implement it from scratch.

The Protocol in 3 Steps

Step 1: Agent calls → Server returns 402

curl -s https://minia2a.uk/x402/captcha-solve
Enter fullscreen mode Exit fullscreen mode

Response (HTTP 402):

{
  "error": "Payment Required",
  "type": "x402",
  "network": "base",
  "token": "USDC",
  "priceCents": 5,
  "recipient": "0xf16F0882de08315B438E9f3a2Abfb2d2E5d94ECA",
  "chainId": 8453
}
Enter fullscreen mode Exit fullscreen mode

The 402 response carries all the information an agent needs to pay: how much (5 cents USDC), to whom (the contract address), and on which chain (Base L2).

Step 2: Agent pays (but there's a catch)

You could send USDC on-chain and wait for confirmation. That works — it's fully trustless — but it takes ~15 seconds for Base block confirmation. For real-time API calls, that's too slow.

The x402 ecosystem has three facilitator options that handle this differently:

Facilitator Settlement Speed Trust Model
Coinbase CDP Pre-funded wallet ~2s Trust Coinbase
Cloudflare Wallets Pre-funded balance ~2s Trust Cloudflare
Direct on-chain Per-transaction ~15s Trustless
Free trial 15 calls free Instant No payment needed

The practical path: use free trials for exploration, Coinbase CDP for production.

Step 3: Agent retries with payment proof

# Using Coinbase CDP: sign a payment message
SIGNATURE=$(node sign-payment.js \
  --recipient "0xf16F0882de08315B438E9f3a2Abfb2d2E5d94ECA" \
  --amount 5 \
  --chain 8453)

curl -s https://minia2a.uk/x402/captcha-solve \
  -H "X-Wallet: 0xYOUR_WALLET" \
  -H "X-Payment-Signature: $SIGNATURE"
Enter fullscreen mode Exit fullscreen mode

Response (HTTP 200):

{
  "solved": true,
  "token": "recaptcha_v3_token_here",
  "cost": 5,
  "x-receipt": "rcpt_abc123def456"
}
Enter fullscreen mode Exit fullscreen mode

The x-receipt header contains a cryptographic receipt ID. You can verify it at any time:

GET /api/v1/receipts/rcpt_abc123def456 → { verified: true, hmach: "sha256:..." }
Enter fullscreen mode Exit fullscreen mode

Building a Real Agent with x402

Let's build a practical agent: a crypto market monitor that checks token security before trading.

// agent.js — A trading agent that pays for security checks
const BASE_URL = 'https://minia2a.uk/x402';

class PayingAgent {
  constructor(walletAddress, signer) {
    this.wallet = walletAddress;
    this.signer = signer;  // Function that signs x402 payment challenges
    this.remainingTrials = new Map();  // Track per-endpoint trials
  }

  async call(serviceId, params = {}) {
    const url = `${BASE_URL}/${serviceId}?${new URLSearchParams(params)}`;

    // Attempt 1: Try without payment (use free trial)
    let res = await fetch(url);

    if (res.status === 200) {
      const remaining = res.headers.get('X-Trials-Remaining');
      console.log(`[trial] ${serviceId}${remaining} trials left`);
      return res.json();
    }

    // Got 402 — need to pay
    if (res.status === 402) {
      const invoice = await res.json();
      return this.payAndRetry(url, invoice);
    }

    throw new Error(`Unexpected status: ${res.status}`);
  }

  async payAndRetry(url, invoice) {
    console.log(`[pay] $${invoice.priceCents/100} USDC to ${invoice.recipient.slice(0,10)}...`);

    // Sign the payment challenge
    const signature = await this.signer({
      recipient: invoice.recipient,
      amount: invoice.priceCents,
      chainId: invoice.chainId,
      token: invoice.token
    });

    // Retry with payment proof
    const res = await fetch(url, {
      headers: {
        'X-Wallet': this.wallet,
        'X-Payment-Signature': signature,
      }
    });

    if (res.status === 200) {
      const receipt = res.headers.get('X-Minia2a-Receipt');
      console.log(`[paid] receipt: ${receipt}`);
      return res.json();
    }

    // Payment failed
    const error = await res.json();
    throw new Error(`Payment failed: ${error.error}`);
  }
}

// Usage
const agent = new PayingAgent(
  '0xYourWallet',
  signWithCoinbaseCDP  // Your signing function
);

// Check if a token is a honeypot before trading
const security = await agent.call('token-security', {
  address: '0xTOKEN_TO_CHECK',
  chain: 'ethereum'
});

if (security.risk === 'LOW') {
  console.log('Safe to trade');
  // Execute trade...
} else {
  console.log(`⚠️ Risk: ${security.risk}${security.details}`);
}
Enter fullscreen mode Exit fullscreen mode

The Free Trial Model

Every endpoint on the marketplace comes with 15 free trial calls. No wallet needed for trials — the server tracks by IP:

// curl -v shows trial headers
// < X-Trials-Remaining: 14
// < X-Trials-Total: 15
Enter fullscreen mode Exit fullscreen mode

When trials run out, you get the 402. The flow is designed so agents can explore and integrate without upfront payment. Pay only when the service proves useful.

This matters because 97% of free credits on the marketplace are unspent. Agents try a few calls, get what they need, and leave. The payment path only activates for ongoing, high-volume use — which is exactly the right behavior.

Framework Integration

LangChain

npm install @minia2a/langchain
Enter fullscreen mode Exit fullscreen mode
import { Minia2aToolkit } from '@minia2a/langchain';

const toolkit = new Minia2aToolkit({
  wallet: process.env.AGENT_WALLET,
  signer: coinbaseSigner,
});

// Search for services
const services = await toolkit.search('captcha');
// → [{ id: 'x402-captcha-solve', priceCents: 5, description: '...' }]

// Call a service with auto-payment
const result = await toolkit.call('x402-captcha-solve', {
  sitekey: 'XXX',
  url: 'https://example.com'
});
// Payment handled automatically via x402 flow
Enter fullscreen mode Exit fullscreen mode

Direct HTTP (Any language)

The protocol is HTTP-native. No SDK needed:

import requests

def call_x402(service_id, params, wallet, signer):
    url = f"https://minia2a.uk/x402/{service_id}"
    resp = requests.get(url, params=params)

    if resp.status_code == 200:
        return resp.json()

    if resp.status_code == 402:
        invoice = resp.json()
        sig = signer(invoice['recipient'], invoice['priceCents'])
        resp = requests.get(url, params=params, headers={
            'X-Wallet': wallet,
            'X-Payment-Signature': sig,
        })
        return resp.json()

    raise Exception(f"HTTP {resp.status_code}")
Enter fullscreen mode Exit fullscreen mode
// Go agent
func (a *Agent) CallX402(serviceID string, params url.Values) ([]byte, error) {
    u := fmt.Sprintf("https://minia2a.uk/x402/%s?%s", serviceID, params.Encode())
    resp, _ := http.Get(u)

    if resp.StatusCode == 402 {
        var invoice X402Invoice
        json.NewDecoder(resp.Body).Decode(&invoice)
        sig := a.SignPayment(invoice)
        req, _ := http.NewRequest("GET", u, nil)
        req.Header.Set("X-Wallet", a.WalletAddr)
        req.Header.Set("X-Payment-Signature", sig)
        resp, _ = http.DefaultClient.Do(req)
    }

    return io.ReadAll(resp.Body)
}
Enter fullscreen mode Exit fullscreen mode

Why HTTP 402 Instead of API Keys

The fundamental difference:

API Keys x402 (HTTP 402)
Setup Sign up, get key, store in .env Wallet address (you already have one)
Billing Monthly invoice, credit card Per-call, settled instantly
Agent-native No — keys are human-managed Yes — wallets are agent-managed
Multi-service One key per service One wallet, any x402 service
Discovery Read docs, find pricing page 402 response IS the pricing page
Revocation Rotate keys manually Stop paying = stop calling

For humans, API keys are fine. For agents — autonomous software making thousands of decisions per minute — the friction of key management breaks the autonomy loop. An agent that needs a human to sign up for each new API is not autonomous.

The 402 flow makes API access programmable: discover → call → get invoice → pay → retry → get result. All in code. No human in the loop.

The Receipt Layer

Every x402 call returns a cryptographic receipt:

{
  "id": "rcpt_x402_captcha_2026-08-07T14-22-11Z_abc123",
  "type": "trial",
  "service_id": "x402-captcha-solve",
  "fee_cents": 0,
  "hmac": "sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
}
Enter fullscreen mode Exit fullscreen mode

Receipts serve three purposes:

  1. Auditability — agents can prove they called a service and got a result
  2. Dispute resolution — if a service returns garbage, the receipt is cryptographic evidence
  3. Accounting — multi-agent systems can track spending across sub-agents

Verification is public: anyone with the HMAC secret can verify a receipt. Service providers can publish verification endpoints. Agents can audit their own spending.

What I'd Build Next

After integrating x402 into several agents, here's what the ecosystem needs:

  1. A wallet-aware agent framework — LangChain, CrewAI, and ElizaOS should ship with agent.wallet as a first-class primitive. Not an add-on. Built in.

  2. Service discovery via natural language — "I need to check if this smart contract is safe" → agent searches the marketplace, finds token-security, calls it, pays, gets result. Current state: you need to know the exact service ID. That's fine for developers, not for agents.

  3. Reputation on-chain — services should accumulate on-chain reputation scores. Did the CAPTCHA solver actually solve the CAPTCHA? Did the token audit catch the honeypot? Reputation makes the marketplace self-policing.

  4. Budget constraints as codeagent.setDailyBudget(5.00, 'USDC') and the agent self-regulates. No runaway spending. No surprise bills. Part of the wallet primitive.

The Numbers (Real Data, August 2026)

From a live marketplace with 323 services:

  • #1 most-called service: CAPTCHA solving (1,280 calls, 133 users)
  • #2: Persistent memory/key-value store (1,401 calls)
  • Conversion rate: 16.5% of trial users register wallets
  • Credit utilization: 2.8% of free credits are actually used

The market is small but real. 322 unique agents have made API calls. 53 have on-chain wallets. $12.75 in settled transactions.

The infrastructure works. The habits haven't caught up yet.


Code examples use the minia2a.uk marketplace (323 services, 15 free trials per endpoint, USDC on Base). The x402 protocol is an open standard being formalized as an IETF draft. Implementations exist in Go, Node.js, and Python.

Top comments (1)

Collapse
 
swapnoneel123 profile image
Swapnoneel Saha

the receipt layer and the daily budget are the pieces that make this usable beyond a demo. i would also bind each payment proof to the request method, path, amount, and a short expiry, then reject a reused receipt. a small failure table for timeout after payment and retry after a duplicate response would help show how the agent avoids double charges. that would make the payment loop easier to trust.