๐Ÿ“… Historical page. This content reflects minia2a as of its publication date and is kept for the record. Current model: x402 pay-per-call in USDC on Base only, 5 free trial calls per signed wallet, no credits and no top-up rail. โ†’ See current

Build an AI Agent That Pays for APIs

โš ๏ธ Update (2026-09-11): this post predates the 2026-09-06 retirement of the deposit-and-credit rail. Sending USDC to the platform wallet no longer credits a balance โ€” after your 5 free trial calls, each call is paid individually over x402. See the payment docs. Also: a trial call is 5 per signed wallet and must carry X-Wallet-Signature + X-Trial-Timestamp alongside ?wallet= โ€” a bare ?wallet= is a hard 400. The Python class below takes a sig= argument but never sends it as a header, so its calls land on 400. See 400 vs 402 vs -32602 for the current mechanics.

August 10, 2026 ยท Iris ยท minia2a blog

Your AI agent can call a gas price API, a web scraper, a CAPTCHA solver, or a Polymarket data feed โ€” and pay for each call in USDC, automatically, without an API key, without a subscription. This tutorial walks through building one in Python, from discovery to payment.

We'll build an agent that:

  1. Discovers available APIs with free trials
  2. Calls them to verify they work
  3. Registers for credits when trials run out
  4. Pays per call in USDC via x402

Everything runs from a single Python file. No browser. No signup form. Just code.

The Architecture: 3 Steps

An agent that pays for APIs needs to do three things. Each maps to a real HTTP call:

Step 1 โ€” Discover: find an API

GET /api/services

Returns every available endpoint with price, category, trial count, and health status. Your agent picks the ones it needs.

Step 2 โ€” Trial: test before paying

GET /x402/{service}?trial=1

First 5 calls are free per registered wallet. The response includes real data. Your agent verifies the API actually returns what it needs before committing money.

Step 3 โ€” Pay: after trials, spend credits or USDC

POST /api/v1/register-simple {"name":"my-agent","wallet":"0x...","signature":"0x..."}
GET /x402/{service}?wallet=0x...

Register to get 5 free trial calls and a wallet. After credits run out, send USDC on Base to buy more. Each API call deducts credits automatically.

Full Working Agent

Here's the complete Python agent. Save it as agent.py and run it:

#!/usr/bin/env python3
"""
x402 Agent โ€” discovers APIs, claims free trials, pays for calls.
No API keys. No subscriptions. Just HTTP 402 + USDC.
"""

import requests
import json
import time
import sys

BASE = "https://minia2a.uk"

class X402Agent:
    def __init__(self):
        self.wallet = None
        self.credits = 0
        self.session = requests.Session()
        self.session.headers.update({"User-Agent": "x402-agent-tutorial/1.0"})

    # โ”€โ”€ Discovery โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    def discover(self, category=None, max_price=5):
        """Find available APIs. Filter by category and max price in cents."""
        r = self.session.get(f"{BASE}/api/services")
        r.raise_for_status()
        services = r.json()["services"]

        results = []
        for s in services:
            if category and s.get("category") != category:
                continue
            if s.get("priceCents", 0) > max_price:
                continue
            results.append({
                "id": s["id"],
                "name": s["name"],
                "price": s.get("priceCents", 0),
                "category": s.get("category", "unknown"),
                "endpoint": s["endpoint"],
                "trials": s.get("trialCount", 0),
            })
        return sorted(results, key=lambda x: x["trials"], reverse=True)

    # โ”€โ”€ Trial โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    def try_service(self, service_id):
        """Call an API with free trial. Returns data or 402 if exhausted."""
        url = f"{BASE}/x402/{service_id.replace('x402-', '')}?trial=1"
        r = self.session.get(url)

        if r.status_code == 200:
            return {"ok": True, "data": r.json()}
        elif r.status_code == 402:
            info = r.json()
            return {
                "ok": False,
                "exhausted": True,
                "message": info.get("message", "Trial limit reached"),
                "trials_max": info.get("trialsMax", 0),
            }
        else:
            return {"ok": False, "error": f"HTTP {r.status_code}"}

    # โ”€โ”€ Registration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    def register(self, name="my-agent", wallet=WALLET, sig=SIG):
        """Register to get 5 free trial calls (self-custody wallet + EIP-191 sig)."""
        # V5 self-custody: your agent holds the key. Generate wallet + signature
        # with the one-liner at https://minia2a.uk/sdk, then POST all three fields.
        r = self.session.post(
            f"{BASE}/api/v1/register-simple",
            json={"name": name, "wallet": wallet, "signature": sig}
        )
        if r.status_code == 200:
            data = r.json()
            self.wallet = wallet
            print(f"โœ… Registered! Wallet: {self.wallet[:10]}... "
                  f"Credits: {data.get('trials', 5)}")
            self._fetch_credits()
            return True
        else:
            print(f"Registration failed: {r.json().get('error', 'unknown')}")
            return False

    def _fetch_credits(self):
        """V5 removed the per-wallet balance endpoint (/api/v1/credits โ†’ 404).
        Remaining trial calls come back in each 402 response; platform
        numbers live at /api/stats."""
        if not self.wallet:
            return
        r = self.session.get(f"{BASE}/api/stats")
        if r.status_code == 200:
            trials = r.json().get("trials", {})
            print(f"๐Ÿ“Š Platform trials used: {trials.get('totalUsed')}")

    # โ”€โ”€ Paid call โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    def call_with_credits(self, service_id):
        """Call API using credits from wallet."""
        if not self.wallet:
            print("โŒ Register first to get a wallet")
            return None

        url = f"{BASE}/x402/{service_id.replace('x402-', '')}?wallet={self.wallet}"
        r = self.session.get(url)

        if r.status_code == 200:
            self._fetch_credits()
            return {"ok": True, "data": r.json()}
        elif r.status_code == 402:
            info = r.json()
            print(f"Credits exhausted: {info.get('credits_remaining', 0)} remaining")
            return {"ok": False, "need_payment": True, "info": info}
        else:
            return {"ok": False, "error": f"HTTP {r.status_code}"}

    # โ”€โ”€ Orchestration โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

    def find_and_call(self, keyword, max_price=5):
        """Discover APIs matching a keyword, trial the top one, then pay if needed."""
        print(f"\n๐Ÿ” Searching for: {keyword}")

        all_services = self.discover(max_price=max_price)
        matches = [s for s in all_services if keyword.lower() in s["name"].lower()]

        if not matches:
            print(f"   No services found matching '{keyword}'")
            return None

        print(f"   Found {len(matches)} matching services:")
        for m in matches[:5]:
            print(f"   โ€ข {m['name']} โ€” {m['price']}ยข/call, {m['trials']}+ trials")

        # Trial the most popular one
        best = matches[0]
        print(f"\n๐Ÿงช Trying: {best['name']} (free trial)")

        result = self.try_service(best["id"])
        if result["ok"]:
            print(f"   โœ… Trial worked! Got data.")
            return result

        if result.get("exhausted"):
            print(f"   โš ๏ธ  Trials exhausted. Need registration.")
            if not self.wallet:
                if self.register(keyword.replace(" ", "-")):
                    print(f"\n๐Ÿ”„ Retrying with credits: {best['name']}")
                    time.sleep(1)
                    return self.call_with_credits(best["id"])
            else:
                return self.call_with_credits(best["id"])

        return result


# โ”€โ”€ Demo โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

if __name__ == "__main__":
    agent = X402Agent()

    # 1. See what's available
    print("โ•โ•โ• Available Crypto APIs โ•โ•โ•")
    crypto = agent.discover(category="crypto", max_price=3)
    for s in crypto[:5]:
        print(f"  {s['name']:30s} {s['price']:3d}ยข  {s['trials']:5d}+ trials")

    # 2. Try one for free
    print("\nโ•โ•โ• Free Trial Demo โ•โ•โ•")
    gas = agent.try_service("x402-gas")
    if gas["ok"]:
        data = gas["data"]
        if isinstance(data, dict):
            # Print first 3 keys
            keys = list(data.keys())[:5]
            for k in keys:
                v = str(data[k])[:80]
                print(f"  {k}: {v}")

    # 3. If trials exhausted, register and pay
    if not gas["ok"] and gas.get("exhausted"):
        print("\nโ•โ•โ• Registration โ•โ•โ•")
        agent.register("tutorial-agent")
        print("\nโ•โ•โ• Paid Call โ•โ•โ•")
        result = agent.call_with_credits("x402-gas")
        if result and result["ok"]:
            print("  โœ… Paid call succeeded!")

    print("\nโ•โ•โ• Agent complete โ•โ•โ•")

What's Happening Inside

Trial Flow (anonymous)

Every IP gets 5 free trial calls, shared across all endpoints. The server tracks this by IP โ€” no account needed. When trials run out, the server returns HTTP 402 with a JSON body telling the agent how to register:

HTTP/2 402 Payment Required x-trials-exhausted: 5 { "_trial": true, "message": "5 free trials used โ€” unlock 5 more trials...", "register": "POST /api/v1/register-simple {name, wallet, signature}", "trialsGranted": 5, "trialsMax": 5 }

Your agent reads the 402, extracts the registration endpoint, and registers programmatically. No human clicks a signup form.

Credit Flow (registered)

After registration, your agent gets a wallet address and 5 free trial calls. Each API call deducts 1โ€“5 credits depending on the endpoint price. The server returns credits_remaining in the response so your agent knows when it's running low:

HTTP/2 200 OK { "ethereum": {"slow": "1.23", "standard": "1.45", "fast": "1.67"}, "credits_remaining": 497 }

Payment Flow (USDC)

When the 5 free trial calls run out, your agent pays per call in USDC via x402. Standard APIs cost ~$0.005โ€“0.015 per call. Premium APIs (AI inference, heavy compute) cost more and are paid directly per call.

Real Use Cases

Here's what agents are actually doing with this pattern today:

Agent TypeAPIs CalledCost/hr
DeFi monitorgas, price oracle, swap safety, fee history~$0.02
Research crawlerweb scrape, search, summarize, web-retrieve~$0.08
Security auditortoken security, contract scan, email verify, DNS~$0.05
Market analystPolymarket, fear-greed, sentiment, funding rate~$0.04

At under $0.10/hour for most workloads, agents can be always-on without worrying about API bills. The pay-per-call model means you only pay for what you use โ€” no monthly minimum, no unused subscription.

Adding LLM Decision-Making

The agent above discovers and calls APIs mechanically. The real power comes when you add an LLM that decides which API to call based on the task:

def decide_and_call(self, task: str) -> dict:
    """Ask an LLM which API to use, then call it."""
    services = self.discover()

    # Build a prompt with available tools
    tools_desc = "\n".join(
        f"- {s['name']}: {s['price']}ยข โ€” {s['trials']}+ trials"
        for s in services[:20]
    )

    prompt = f"""You can call these APIs:
{tools_desc}

Task: {task}

Return JSON: {{"service": "x402-name", "reason": "..."}}"""

    # Call your LLM of choice
    response = your_llm(prompt)  # Claude, GPT, etc.
    choice = json.loads(response)

    # Try the chosen service
    result = self.try_service(choice["service"])
    if not result["ok"] and result.get("exhausted"):
        result = self.call_with_credits(choice["service"])

    return {"choice": choice, "result": result}

The agent's workflow becomes: task โ†’ LLM selects API โ†’ trial call โ†’ if 402, pay โ†’ return result. The LLM is the brain. The x402 marketplace is the hands.

One File, No Dependencies

Everything above runs with just pip install requests. No SDK. No API key provisioning. Bring your own self-custody wallet (the platform never holds your key). The agent discovers, trials, registers, and pays โ€” all in HTTP.

This is what makes the x402 model different from traditional API marketplaces. Your agent doesn't need a human to create accounts, manage keys, or fund wallets. It handles the full lifecycle: discovery โ†’ trial โ†’ payment โ†’ delivery.

Try it: browse 328 live endpoints, each with free trials. Your agent can be paying for its own API calls in under 10 minutes.