/api/v1/buy-credits endpoint described here were replaced by direct USDC payment via x402 (existing credits migrated to microUSDC, 1 credit = 1/200 USDC). Current flow: pay per call in USDC via x402 · 5 free trial calls per signed wallet.Your AI agent can call APIs. But can it pay for them?
This tutorial walks through the complete flow: registering an agent wallet, discovering paid APIs, making free trial calls, and spending credits when trials run out. No API keys. No KYC. No credit card. Just HTTP.
The protocol is x402 โ HTTP 402 Payment Required, repurposed for stablecoin micropayments. It's processed $50 billion in volume across 200 million transactions. Your agent can use it today.
By the end of this tutorial, you'll have a Python agent that:
Register with your own self-custody wallet + EIP-191 signature, and get 5 free trial calls. No gas. No KYC.
curl -X POST https://minia2a.uk/api/v1/register-simple \
-H "Content-Type: application/json" \
-d '{"name": "my-research-agent", "wallet": "0x...", "signature": "0x..."}'
Response:
Save the wallet address. That's your agent's identity and payment method.
328 services are live. Here's how your agent finds the ones it needs:
# List all services
curl https://minia2a.uk/api/services
# Search for specific capabilities
curl "https://minia2a.uk/api/services?q=gas"
# Get a specific service's details
curl https://minia2a.uk/api/services/x402-gas
The most popular endpoints (by trial volume):
5 free trial calls shared across all endpoints, per registered wallet. Your agent can try before committing.
# Free trial โ register a wallet
curl "https://minia2a.uk/x402/gas"
# Pass parameters
curl "https://minia2a.uk/x402/gas?chain=base"
# POST with JSON body
curl -X POST https://minia2a.uk/x402/find \
-H "Content-Type: application/json" \
-d '{"q": "bitcoin price prediction 2026"}'
Each response includes trial status:
After 5 free trial calls the endpoint returns HTTP 402 and names the price. A trial call is two halves โ the wallet and a signature over minia2a trial:<wallet>:<serviceId>:<unix_ts>:
# Spend a free trial call โ a trial is two halves, wallet AND signature.
export WALLET=0xYOUR_WALLET SERVICE=x402-gas TS=$(date +%s)
export SIG=0xYOUR_SIGNATURE # EIP-191 personal_sign of: minia2a trial:$WALLET:$SERVICE:$TS
curl "https://minia2a.uk/x402/gas?wallet=$WALLET" \
-H "X-Wallet-Signature: $SIG" -H "X-Trial-Timestamp: $TS"
# -> 200
Any other endpoint works the same way โ swap the path and the service id in the signed message.
When that wallet's trials are spent, the same URL answers 402 with the price and payTo โ the signal to pay per call, not to top anything up:
Retired 2026-09-06. This step used to tell you to send USDC to a platform address and claim credits. That rail is gone: /api/v1/buy-credits returns 404, and USDC sent to a minia2a address is not credited โ there is no deposit channel.
# There is no funding step. Keep the USDC in your own agent's wallet.
# Pay per call over x402 โ the 402 names the price and payTo:
curl -i "https://minia2a.uk/x402/gas"
# -> HTTP 402 + base64 PAYMENT-REQUIRED header
# settle that offer, then retry the same URL with:
# -H "PAYMENT-SIGNATURE: $SIGNATURE"
Or use Cloudflare Wallets, OSL AgentPay, or any x402-compatible wallet โ minia2a is facilitator-agnostic.
Here's a production-ready agent that discovers APIs, tries them, and spends credits:
#!/usr/bin/env python3
"""Agent that discovers, trials, and pays for x402 APIs."""
import requests
import json
import os
BASE = "https://minia2a.uk"
WALLET_FILE = os.path.expanduser("~/.agent-wallet.json")
class Agent:
def __init__(self, name="research-agent"):
self.name = name
self.wallet = None
self.credits = 0
self._load_or_register()
def _load_or_register(self):
"""Load existing wallet or register a new one."""
if os.path.exists(WALLET_FILE):
with open(WALLET_FILE) as f:
data = json.load(f)
self.wallet = data["wallet"]
self.credits = data.get("credits", 0)
print(f"Loaded wallet: {self.wallet[:10]}... "
f"({self.credits} credits)")
return
# Register new agent (V5 self-custody: wallet + EIP-191 signature)
r = requests.post(f"{BASE}/api/v1/register-simple",
json={"name": self.name, "wallet": WALLET,
"signature": SIG})
if r.status_code == 200:
data = r.json()
self.wallet = data["wallet"]
self.trials = data.get("trials", 5)
with open(WALLET_FILE, "w") as f:
json.dump({"wallet": self.wallet,
"credits": self.credits}, f)
print(f"Registered! Wallet: {self.wallet[:10]}... "
f"Credits: {self.credits}")
else:
raise Exception(f"Registration failed: {r.text}")
def discover(self, query=None):
"""Find available APIs."""
url = f"{BASE}/api/services"
if query:
url += f"?q={query}"
r = requests.get(url)
return r.json() if r.status_code == 200 else []
def call(self, endpoint, method="GET", params=None, json_body=None):
"""Call an x402 endpoint. Uses trials first, then credits."""
url = f"{BASE}/x402/{endpoint}"
# If we have a wallet, always include it for credit tracking
if self.wallet:
if params is None:
params = {}
params["wallet"] = self.wallet
if method == "GET":
r = requests.get(url, params=params)
else:
r = requests.post(url, params=params, json=json_body)
# Handle 402: trials exhausted, using credits
if r.status_code == 402:
data = r.json()
if data.get("_trial"):
remaining = data["_trial"].get("credits_remaining", 0)
self.credits = remaining
if remaining == 0:
raise Exception("No credits remaining. "
"Buy credits at /buy.html")
return data
# Success or trial response
result = r.json() if r.status_code == 200 else {"error": r.text}
# Track credit usage from response
cr = result.get("credits_remaining")
if cr is not None:
self.credits = cr
# Update stored credits
if os.path.exists(WALLET_FILE):
with open(WALLET_FILE) as f:
data = json.load(f)
data["credits"] = cr
with open(WALLET_FILE, "w") as f:
json.dump(data, f)
return result
def run(self, task):
"""Execute a task by chaining API calls."""
print(f"\n๐ค Agent '{self.name}' executing: {task}\n")
# Step 1: Find relevant APIs
services = self.discover(task.split()[0])
if not services:
print("No services found for this task.")
return
# Show top 3 matches
print(f"Found {len(services)} services. Top 3:")
for s in services[:3]:
print(f" โข {s['id']}: {s.get('name', s['id'])} "
f"({s.get('priceCents', '?')}ยข/call)")
# Step 2: Call the best match
best = services[0]["id"]
print(f"\nCalling {best}...")
result = self.call(best)
print(f"Result: {json.dumps(result, indent=2)[:300]}")
print(f"Credits remaining: {self.credits}")
# โโ Usage โโ
if __name__ == "__main__":
agent = Agent("gas-tracker")
# Discover gas-related APIs and call one
agent.run("gas")
# Call a specific endpoint with parameters
result = agent.call("polymarket",
params={"market": "trump-2028"})
print(json.dumps(result, indent=2))
Query parameters work everywhere: curl, browsers, Python requests, AI SDKs. Headers require SDK-specific configuration. The ?wallet= pattern is the lowest-friction integration path โ your agent appends one parameter and it works.
Agents can't evaluate an API before calling it. Free trials let your agent test 5 different endpoints, find the one that returns the right data, then commit credits. It's the same model as SaaS free trials, adapted for machine consumers.
The endpoint returns HTTP 402 with credits_remaining: 0. Your agent can catch this and either switch to a free alternative, notify a human, or pause until credits are purchased. The protocol doesn't silently fail โ it explicitly signals payment state.
~/.agent-wallet.json. Never hardcode it. The wallet is your agent's identity โ treat it like an API key.
Once your agent can pay for APIs, the design space opens up:
.agent-budget file with daily spending limits. Your agent checks it before each call._trial field is your audit trail โ credits spent, endpoint called, timestamp.The agent economy doesn't need a new payment protocol. HTTP 402 has been in the spec since 1997. What's new is that it actually works now โ USDC settlement on Base, 2-second finality, sub-cent fees, and 150,000 endpoints that accept it.
Your agent can join the economy today. The first 5 calls are free (per registered wallet).