No signup. No API keys. No rate-limit dashboards. Pay $0.002–$1 per call in USDC on Base mainnet via the x402 protocol. Works out of the box with Claude Desktop, Cursor, Coinbase Agent Kit, or any HTTP client that can sign an EIP-3009 authorization.
0x24A9…aF40. Verifiable. Auditable. No invoicing.Using @x402/core + @x402/evm + viem:
// npm i viem @x402/core @x402/evm
import { createWalletClient, http, publicActions } from "viem";
import { privateKeyToAccount } from "viem/accounts";
import { base } from "viem/chains";
import { x402Client, x402HTTPClient } from "@x402/core/client";
import { ExactEvmScheme, toClientEvmSigner } from "@x402/evm";
const account = privateKeyToAccount("0xYOUR_AGENT_PRIVATE_KEY");
const wc = createWalletClient({ account, chain: base, transport: http() }).extend(publicActions);
const core = new x402Client();
core.register("eip155:8453", new ExactEvmScheme(toClientEvmSigner(account, wc)));
const http402 = new x402HTTPClient(core);
const url = "https://x402.adametherzlab.com/api/compliance-check";
const body = { query: "Is benzene storage at 50 ppm OSHA-compliant for a 50-worker site?" };
// 1) Request gets back 402 challenge
const r1 = await fetch(url, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(body) });
const pr = http402.getPaymentRequiredResponse(n => r1.headers.get(n), await r1.json());
// 2) Sign EIP-3009 authorization (no on-chain tx from your side; gas paid by facilitator)
const payload = await http402.createPaymentPayload(pr);
const paymentHeaders = http402.encodePaymentSignatureHeader(payload);
// 3) Retry with payment header gets 200 + the answer
const r2 = await fetch(url, { method: "POST", headers: { "content-type": "application/json", ...paymentHeaders }, body: JSON.stringify(body) });
console.log(await r2.json());
Your agent wallet needs ~$0.05 in USDC on Base. Get test USDC from CDP or buy on any Base DEX.
Using eth-account + requests. Full reference: /x402_py_client.py (MIT, ~250 lines, copy-paste). Compact version:
# pip install eth-account requests
import base64, json, os, secrets, time, requests
from eth_account import Account
from eth_account.messages import encode_typed_data
USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
CHAIN_ID = 8453
def pay_and_call(url, private_key, body=None):
payer = Account.from_key(private_key).address
# 1) Request returns a 402 challenge
r1 = requests.post(url, json=body, timeout=90)
if r1.status_code != 402:
return r1.json() if r1.status_code == 200 else r1.raise_for_status()
challenge = json.loads(base64.b64decode(r1.headers["payment-required"]))
accept = challenge["accepts"][0]
# 2) Sign EIP-3009 transferWithAuthorization
now = int(time.time())
nonce = secrets.token_bytes(32)
typed = {
"types": {
"EIP712Domain": [
{"name":"name","type":"string"},
{"name":"version","type":"string"},
{"name":"chainId","type":"uint256"},
{"name":"verifyingContract","type":"address"}],
"TransferWithAuthorization": [
{"name":"from","type":"address"},
{"name":"to","type":"address"},
{"name":"value","type":"uint256"},
{"name":"validAfter","type":"uint256"},
{"name":"validBefore","type":"uint256"},
{"name":"nonce","type":"bytes32"}],
},
"primaryType": "TransferWithAuthorization",
"domain": {"name":"USD Coin","version":"2","chainId":CHAIN_ID,"verifyingContract":USDC},
"message": {"from":payer,"to":accept["payTo"],"value":int(accept["amount"]),
"validAfter": now-30, "validBefore": now+870, "nonce": nonce},
}
sig = Account.sign_message(encode_typed_data(full_message=typed), private_key=private_key)
# 3) Build wire payload {x402Version, payload, extensions, resource, accepted}
wire = {
"x402Version": challenge.get("x402Version", 2),
"payload": {
"authorization": {"from":payer,"to":accept["payTo"],"value":accept["amount"],
"validAfter":str(now-30),"validBefore":str(now+870),
"nonce":"0x"+nonce.hex()},
"signature": "0x" + sig.signature.hex(),
},
"extensions": challenge.get("extensions", {}),
"resource": challenge.get("resource", {}),
"accepted": accept,
}
hdr = base64.b64encode(json.dumps(wire, separators=(",",":")).encode()).decode()
# 4) Retry with payment header
r2 = requests.post(url, json=body, headers={"payment-signature": hdr}, timeout=90)
r2.raise_for_status()
return r2.json()
# Example: call the Industrial Compliance endpoint
result = pay_and_call(
url="https://x402.adametherzlab.com/api/compliance-check",
private_key=os.environ["X402_PRIVATE_KEY"],
body={"query": "Is benzene storage at 50 ppm OSHA-compliant for a 50-worker site?"},
)
print(result)
Confirmed working end-to-end via real $0.01 Base mainnet settlement. Wire shape gotchas: the body must include extensions, resource, and accepted at the top level (not just x402Version + payload); validAfter should be ~now (small back-skew) and not zero. The full /x402_py_client.py includes those details with comments.
AI POST endpoints accept any of: { query: "..." }, { q: "..." }, { input: "..." }, { text: "..." }, { prompt: "..." }, { question: "..." }. If none of those keys are present, the first non-trivial string field is used. So { plant: "yaupon holly" } works just like { query: "yaupon holly" }.
Full schema with pricing and request bodies: /openapi.json (OpenAPI 3.1, with x-price-usd and x-x402 extensions on every operation).
DataForge web-scraping is also available as an MCP server: github.com/AdametherzLab/dataforge-mcp. Wire it into your Claude Desktop config and your assistant can scrape pay-per-call without leaving the chat. A wider MCP wrapper covering all 32 AI endpoints is on the roadmap.
No. Anyone with a Base wallet holding USDC can call any endpoint. Identity is the wallet that signs the payment authorization.
If the handler times out or errors after payment, you get a 500 response. The settlement still happened on-chain. Future work: refund-on-failure via x402 receipt extension. Open issue if this blocks you.
Not yet — each call is one payment authorization. A batch extension is on the x402 spec roadmap upstream.
The 402 challenge body (and the payment-required header) state the exact amount in USDC micros. Your x402 client signs an authorization for exactly that amount. The facilitator (CDP) settles for at most that amount. There is no overdraft path.
Open issues at github.com/AdametherzLab. We respond.