A payment API designed for AI agent code.
A small REST API. Signed webhooks. Official SDKs in five languages. Built so your agent can send and settle USDC and verify payments in a few lines of code.

The Blockchain0x API is deliberately small. We do not want you to read documentation for an hour to make your first payment. We want you to copy a snippet, paste your API key, and run it.
A small surface, built for agent code.
The payment-shaped routes are below. Webhooks, api-keys, and read-only spend-permissions round out the surface; the SDK wraps all of it.
/v1/paymentsSend a USDC payment from an agent wallet/v1/transactions/{id}Fetch a transaction's status and hash/v1/payment-requests/{id}/settleSettle an invoice with on-chain proof/v1/agents/{id}Fetch an agent wallet/v1/agentsCreate an agent walletAll signed with HMAC-SHA256.
Signature in the X-Blockchain0x-Signature header. Replay window of 5 minutes. Idempotency keys on every POST.
payment.receivedUSDC landed in one of your agent wallets
payment.sentan outbound payment from your agent settled on chain
wallet.deployedan agent's smart wallet was deployed
webhook.testa test delivery you triggered from the dashboard
Send USDC from your agent's wallet.
from blockchain0x import Client
client = Client(api_key="sk_test_...") # sk_test_ testnet, sk_live_ mainnet
tx = client.payments.create(body={
"agentId": "agt_123",
"to": "0xRecipient",
"amountWei": "10000", # USDC base units (6 decimals): 0.01 USDC
})
print(tx) # may return 503 until the chain adapter is wired for your networkTyped clients for TypeScript and Python.
npm install @blockchain0x/nodeWorks with Node 18+. Native TypeScript types.
pip install blockchain0xPython 3.9+. Sync and async clients.
The request bodies the SDK wraps.
These are the verified inputs for each route. Responses are shown short here; the full typed shapes live in the SDK and the API reference. Amounts are USDC base units (6 decimals).
/v1/paymentsSend a USDC payment (payments.create). amountWei is USDC base units (6 decimals). May return 503 until the chain adapter is wired.
{
"agentId": "agt_123",
"to": "0xRecipient",
"amountWei": "10000",
"metadata": { "reason": "Research report" }
}{
"txHash": "0xff5...e12"
}/v1/payment-requests/{id}/settleSettle a payment request (invoice) created in the dashboard, with on-chain proof (paymentRequests.settle). There is no create route - settle only.
{
"txHash": "0xff5...e12",
"payerAddress": "0xBuyer...",
"amountUsdcVerified": "0.10"
}{
"txHash": "0xff5...e12"
}/v1/transactions/{id}Fetch a single transaction by id (transactions.get).
(no body){
"id": "tx_01J9...",
"txHash": "0xff5...e12"
}/v1/agents/{id}Fetch an agent wallet (agents.get). Its public page lives at wallet.blockchain0x.com/a/{slug}.
(no body){
"id": "agt_01J9QKE...",
"name": "research-bot",
"public_url": "https://wallet.blockchain0x.com/a/research-bot"
}/v1/agents/{id}/spend-permissionsRead an agent's spend permissions. READ-ONLY via the API - creation and changes are dashboard-only.
(no body){
"allowance_wei": "5000000",
"per_tx_wei": "1000000",
"period_seconds": 86400,
"start_at": "2026-05-15T00:00:00Z",
"revoked_at": null
}Always verify the signature before trusting the payload.
Anyone can POST to your callback URL. The signature is what proves the event actually came from us.
Every delivery carries an X-Blockchain0x-Signature header (t=<unix>,v1=<hex>) - an HMAC-SHA256 over the string `${t}.${rawBody}` with your webhook secret, inside a 5-minute replay window. In Node, webhooks.verify from @blockchain0x/node does it and returns a discriminated union you branch on. In other languages, compute the same HMAC and compare in constant time. Read the RAW body, not a parsed copy - re-serializing breaks the signature.
import express from "express";
import { webhooks } from "@blockchain0x/node";
const app = express();
// Capture the RAW body. The HMAC is over the exact bytes on the wire.
app.use(express.raw({ type: "application/json" }));
app.post("/webhooks/payment", (req, res) => {
const result = webhooks.verify({
headers: req.headers,
rawBody: req.body, // Buffer, raw bytes
secret: process.env.BLOCKCHAIN0X_WEBHOOK_SECRET!,
});
if (!result.ok) return res.status(400).json({ code: result.code });
// result.eventType is "payment.received" | "payment.sent" | ...
handleEvent(result);
res.status(200).send("ok");
});import hmac, hashlib, os, time
from flask import Flask, request, abort
app = Flask(__name__)
SECRET = os.environ["BLOCKCHAIN0X_WEBHOOK_SECRET"].encode()
@app.post("/webhooks/payment")
def receive():
raw = request.get_data() # RAW bytes - do not parse first
sig = request.headers.get("X-Blockchain0x-Signature", "")
ts = request.headers.get("X-Blockchain0x-Timestamp", "")
# Header is "t=<unix>,v1=<hex>"; some proxies send bare hex + the ts header.
parts = dict(p.split("=", 1) for p in sig.split(",") if "=" in p)
t, v1 = parts.get("t", ts), parts.get("v1", sig)
want = hmac.new(SECRET, t.encode() + b"." + raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(want, v1) or abs(time.time() - int(t)) > 300:
abort(401)
handle_event(request.headers.get("X-Blockchain0x-Event-Type"), request.get_json())
return "ok", 200The webhook secret is returned once when you create or rotate the webhook (webhooks.rotateSecret), and BLOCKCHAIN0X_WEBHOOK_SECRET is where your handler reads it. Rotating invalidates the old secret, so coordinate the rollout: set the new secret in your server's env, deploy, then rotate. The shipped events are payment.received, payment.sent, wallet.deployed, and webhook.test - branch on the event type, ignore the rest.
Retry safely. The API will not pay twice.
Agent code retries. Networks drop connections. LLMs decide to call the tool twice. To make this safe, send an Idempotency-Key header on the POST. payments.create in the SDK auto-mints a stable one for you, so a retried call collapses to a single on-chain submission instead of paying twice. Override it with your own key when you want to dedupe the same logical operation across processes.
curl -X POST https://api.blockchain0x.com/v1/payments \
-H "Authorization: Bearer $BLOCKCHAIN0X_API_KEY" \
-H "Idempotency-Key: 8e2c3a40-pay-vendor-once" \
-H "Content-Type: application/json" \
-d '{ "agentId": "agt_123", "to": "0xRecipient", "amountWei": "10000" }'- First call: submits the payment, returns the transaction.
- Retry with the same key: collapses to one on-chain submission instead of paying twice.
- The SDK handles it: payments.create auto-mints a stable Idempotency-Key, so a retried call is safe out of the box.
- Override it: pass your own key when you want to dedupe the same logical operation across processes.
The recommended pattern is to generate a UUID per logical operation in your agent code (e.g. one UUID per "pay vendor X for order Y") and reuse it across retries until the operation succeeds. The official SDKs auto-generate one for payments.create if you do not specify it.
Read your limit off the response, not a table.
Limits scale with your plan. Rather than hard-code numbers that drift, every response tells you where you stand and the SDKs handle backoff for you.
Headers on every success response
X-RateLimit-Limit: your plan's steady rateX-RateLimit-Remaining: how many calls left in this windowX-RateLimit-Reset: unix seconds when the window resets
When you hit the cap (HTTP 429)
- Response includes
Retry-Afterin seconds - The official SDKs retry on 429 and 5xx with exponential backoff, honouring Retry-After
- Most code never handles 429 by hand because the SDK already does
Speaks x402 fluently. Works without it too.
x402 is the open protocol for HTTP-native payments. The premise: any API that returns 402 Payment Required can advertise payment requirements in the response, and any client that understands the spec can pay and retry - no signup, no API key, no out-of-band negotiation. Blockchain0x ships real x402 packages: a pay-side client and receive-side server adapters. The only scheme today is exact-usdc, on Base.
HTTP/1.1 402 Payment Required
Content-Type: application/json
{
"version": 1,
"resource": "https://api.example.com/paid-endpoint",
"accepts": [
{ "scheme": "exact-usdc", "network": "eip155:8453" }
]
}What the agent caller does
- Reads the 402 body: version 1, the resource, and a non-empty accepts[] of payment requirements (scheme exact-usdc, network eip155:8453 for Base).
- Builds a payment and resends the request with an X-Payment: exact-usdc:<base64(json)> header.
- On the pay side, createX402Client({ sdk }) from @blockchain0x/x402 does this for you - it answers 402s automatically.
- Your server verifies the X-Payment header and fulfills the original request.
Both sides, real packages
On the pay side, createX402Client({ sdk }) from @blockchain0x/x402 wraps fetch and answers 402s automatically. On the receive side, createX402Plugin (Fastify) and createX402Middleware (Express) gate your own endpoints. Or skip x402 and use the REST API directly - the two compose, so you can add x402 when you are ready.