Discover, call, and pay for APIs — all from your agent, no API keys required
You've built an AI agent. It can reason, use tools, and interact with the world. But there's one thing it can't do: pay for the APIs it needs. Every useful API — weather, crypto prices, captcha solving, web scraping — requires an API key that a human had to register, verify, and fund.
x402 changes this. It's a protocol that lets your agent pay for API calls automatically, in USDC, at the moment of use. No API keys. No monthly subscriptions. No human in the loop. Your agent needs a crypto wallet with a few cents of USDC — that's it.
In this tutorial, you'll build an agent that discovers services on minia2a.uk (the largest x402 marketplace with 173+ services), calls one, handles the payment, and gets the result. All in Python, all running on your machine.
1. Your agent makes an HTTP request to an x402 endpoint.
2. The server responds with 402 Payment Required + a payment address + amount in USDC.
3. Your agent sends the payment on-chain (Base L2, ~1 second, sub-cent gas).
4. Your agent retries the request — this time with the transaction hash as proof.
5. The server verifies on-chain and returns the result.
That's it. Five steps. No OAuth dance, no credit card form, no email verification. Machine-to-machine payments, fully automated.
An agent that:
/x402/time service on minia2a1 Browse the marketplace
minia2a.uk lists every x402 service with its price, endpoint URL, and description. You can browse at minia2a.uk or query programmatically:
curl -s https://minia2a.uk/api/stats | python3 -c "
import json, sys
d = json.load(sys.stdin)
print(f'{d[\"services\"]} services, {d[\"agents\"]} registered agents')
# Top endpoints by usage
trials = sorted(d['trials']['byEndpoint'].items(), key=lambda x: x[1]['used'], reverse=True)[:5]
for name, data in trials:
print(f' /{name}: {data[\"used\"]} calls, {data[\"users\"]} users')
"
2 Call an endpoint and handle the 402
import requests
import os
from web3 import Web3
from eth_account import Account
# --- Config ---
ENDPOINT = "https://minia2a.uk/x402/time"
PRIVATE_KEY = os.environ["AGENT_WALLET_KEY"] # Never hardcode!
RPC_URL = "https://mainnet.base.org"
# --- Step 2a: Make the initial request ---
resp = requests.get(ENDPOINT)
print(f"Status: {resp.status_code}")
if resp.status_code == 402:
# Parse the payment details from headers
pay_address = resp.headers.get("x402-payment-address")
pay_amount_wei = int(resp.headers.get("x402-payment-amount", "0"))
pay_chain_id = int(resp.headers.get("x402-chain-id", "8453"))
pay_token = resp.headers.get("x402-payment-token", "USDC")
amount_usdc = pay_amount_wei / 1e6 # USDC has 6 decimals
print(f"Payment required: {amount_usdc} {pay_token} → {pay_address}")
print(f"Chain ID: {pay_chain_id} (Base)")
# --- Step 2b: Send the payment ---
w3 = Web3(Web3.HTTPProvider(RPC_URL))
account = Account.from_key(PRIVATE_KEY)
# Standard ERC-20 transfer
usdc_contract = w3.eth.contract(
address="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", # USDC on Base
abi=[{"constant":False,"inputs":[{"name":"to","type":"address"},
{"name":"value","type":"uint256"}],"name":"transfer",
"outputs":[{"name":"","type":"bool"}],"type":"function"}]
)
tx = usdc_contract.functions.transfer(
pay_address, pay_amount_wei
).build_transaction({
"from": account.address,
"nonce": w3.eth.get_transaction_count(account.address),
"gas": 100000,
"maxFeePerGas": w3.eth.gas_price,
"maxPriorityFeePerGas": w3.to_wei(0.001, "gwei"),
"chainId": pay_chain_id,
})
signed = account.sign_transaction(tx)
tx_hash = w3.eth.send_raw_transaction(signed.raw_transaction)
print(f"Payment sent! TX: {tx_hash.hex()}")
# Wait for confirmation
receipt = w3.eth.wait_for_transaction_receipt(tx_hash)
print(f"Confirmed in block {receipt['blockNumber']}")
# --- Step 2c: Retry with proof ---
resp2 = requests.get(ENDPOINT, headers={
"x402-transaction-hash": tx_hash.hex()
})
print(f"Retry status: {resp2.status_code}")
print(f"Result: {resp2.json()}")
else:
print(f"Unexpected status: {resp.status_code}")
print(resp.text[:200])
3 Save, set your key, and run
export AGENT_WALLET_KEY="your-private-key-here"
pip install web3 eth-account requests
python agent.py
Expected output:
Status: 402
Payment required: 0.01 USDC → 0xf16F...4ECA
Chain ID: 8453 (Base)
Payment sent! TX: 0xabc123...
Confirmed in block 23456789
Retry status: 200
Result: {"timestamp": "2026-08-01T09:15:00Z", "timezone": "UTC", ...}
Now let's wrap this in a reusable function your agent can call whenever it needs an x402 service:
import requests, os, time
from web3 import Web3
from eth_account import Account
class X402Agent:
"""An AI agent that can pay for x402 APIs automatically."""
USDC_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
USDC_ABI = [{"constant":False,"inputs":[{"name":"to","type":"address"},
{"name":"value","type":"uint256"}],"name":"transfer",
"outputs":[{"name":"","type":"bool"}],"type":"function"}]
def __init__(self, private_key: str, rpc_url: str = "https://mainnet.base.org"):
self.w3 = Web3(Web3.HTTPProvider(rpc_url))
self.account = Account.from_key(private_key)
self.usdc = self.w3.eth.contract(address=self.USDC_BASE, abi=self.USDC_ABI)
def call(self, url: str, method: str = "GET", json_data: dict = None, max_retries: int = 2) -> dict:
"""Call an x402 endpoint, pay if needed, return the result."""
for attempt in range(max_retries + 1):
if method == "GET":
resp = requests.get(url)
else:
resp = requests.post(url, json=json_data or {})
if resp.status_code == 200:
return {"ok": True, "data": resp.json(), "paid": attempt > 0}
if resp.status_code == 402 and attempt < max_retries:
tx_hash = self._pay(resp)
url = f"{url}{'&' if '?' in url else '?'}tx={tx_hash}"
continue
return {"ok": False, "error": f"HTTP {resp.status_code}", "body": resp.text[:500]}
return {"ok": False, "error": "max retries exceeded"}
def _pay(self, response) -> str:
"""Send USDC payment from the 402 response headers."""
to = response.headers["x402-payment-address"]
amount = int(response.headers["x402-payment-amount"])
chain_id = int(response.headers.get("x402-chain-id", "8453"))
tx = self.usdc.functions.transfer(to, amount).build_transaction({
"from": self.account.address,
"nonce": self.w3.eth.get_transaction_count(self.account.address),
"gas": 100000,
"maxFeePerGas": self.w3.eth.gas_price,
"maxPriorityFeePerGas": self.w3.to_wei(0.001, "gwei"),
"chainId": chain_id,
})
signed = self.account.sign_transaction(tx)
tx_hash = self.w3.eth.send_raw_transaction(signed.raw_transaction)
self.w3.eth.wait_for_transaction_receipt(tx_hash)
return tx_hash.hex()
# --- Usage ---
agent = X402Agent(os.environ["AGENT_WALLET_KEY"])
# Discover available services
import requests as req
services = req.get("https://minia2a.uk/api/stats").json()
print(f"Connected to minia2a — {services['services']} services available")
# Call a service
result = agent.call("https://minia2a.uk/x402/time")
if result["ok"]:
print(f"Current time: {result['data']}")
else:
print(f"Error: {result['error']}")
minia2a.uk has 173 services across categories. Here are the most popular:
| Endpoint | What It Does | Price |
|---|---|---|
/x402/time | Accurate UTC timestamp | ~$0.01 |
/x402/gas | Real-time gas prices across chains | ~$0.01 |
/x402/web-scrape | Scrape any webpage, return clean text | ~$0.05 |
/x402/captcha-solve | Solve CAPTCHAs automatically | ~$0.02 |
/x402/token-security | Audit any ERC-20 token for risks | ~$0.03 |
/x402/wallet-intel | Analyze any wallet's activity | ~$0.03 |
/x402/sentiment | Sentiment analysis on any text | ~$0.01 |
/x402/email-verify | Validate email addresses | ~$0.01 |
The traditional API economy runs on monthly subscriptions and API keys — a model designed for humans. But AI agents don't have email addresses. They can't sign up for Stripe. They can't click "I am not a robot."
x402 is the payment layer for the machine economy. When your agent can pay for API calls directly, you unlock:
173 services, 34 agents, one protocol. The machine economy starts here.
Register Your Agent →