Skip to main content
PAYMENT API

A payment API designed for AI agent code.

Five endpoints. Five webhook events. Signed payloads. Official SDKs. Built so your agent can request, receive, and verify USDC payments in three 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 request. We want you to copy a snippet, paste your API key, and run it.

THE FIVE ENDPOINTS

That is the entire surface area.

Every additional endpoint we considered, we cut. Add more only when usage proves the need.

POST/v1/agentsCreate an agent wallet profile
GET/v1/agents/{id}Fetch agent details
POST/v1/payment-requestsCreate a hosted payment request
GET/v1/payment-requests/{id}Check payment status
GET/v1/transactionsList transactions
THE FIVE WEBHOOK EVENTS

All signed with HMAC-SHA256.

Signature in the X-Blockchain0x-Signature header. Replay window of 5 minutes. Idempotency keys on every POST.

payment.requested

a payment request was created

payment.received

the chain has seen the payment in a block

payment.confirmed

the payment is final per chain finality rules

payment.failed

the payment expired or was rejected

agent.verified

a verification badge was earned

THREE-LINE EXAMPLE

Hand the URL to whoever owes you money.

PYTHON
from blockchain0x import Client

client = Client(api_key="sk_live_...")
request = client.payment_requests.create(
    agent_id="agt_abc123",
    amount_usdc=5.00,
    reason="Research report on Q4 2025 LLM market",
    callback_url="https://my-agent.com/webhooks/payment",
)
print(request.hosted_url)
OFFICIAL SDKs

Auto-generated from OpenAPI. Always in sync.

TYPESCRIPT
npm install @blockchain0x/node

Works with Node 18+. Native TypeScript types.

PYTHON
pip install blockchain0x

Python 3.9+. Sync and async clients.

FULL ENDPOINT SCHEMAS

Request and response shapes for every endpoint.

No reading docs to make a first call. The exact JSON in and out, copy-paste ready.

POST/v1/agents

Create an agent wallet profile.

REQUEST
{
  "name": "research-bot",
  "slug": "research-bot",
  "purpose": "Generates Q4 LLM market analysis",
  "wallet_address": "0xAbC...",
  "plan": "free"
}
RESPONSE
{
  "id": "agt_01J9QKE...",
  "name": "research-bot",
  "slug": "research-bot",
  "public_url": "https://wallet.blockchain0x.com/a/research-bot",
  "wallet_address": "0xAbC...",
  "plan": "free",
  "created_at": "2026-05-15T08:30:00Z"
}
GET/v1/agents/{id}

Fetch agent details, plan, public URL, wallet address, status.

REQUEST
(no body)
RESPONSE
{
  "id": "agt_01J9QKE...",
  "name": "research-bot",
  "plan": "pro",
  "status": "active",
  "wallet_address": "0xAbC...",
  "public_url": "https://wallet.blockchain0x.com/a/research-bot",
  "verification": { "email": true, "github": true, "domain": false },
  "daily_cap_usdc": "500.00",
  "per_payment_cap_usdc": "50.00"
}
POST/v1/payment-requests

Create a hosted payment request. Returns hosted_url to hand to the buyer.

REQUEST
{
  "agent_id": "agt_01J9QKE...",
  "amount_usdc": "5.00",
  "reason": "Research report on Q4 2025 LLM market",
  "callback_url": "https://my-agent.com/webhooks/payment",
  "expires_in_seconds": 3600
}
RESPONSE
{
  "id": "pr_01J9R6Y...",
  "hosted_url": "https://wallet.blockchain0x.com/a/research-bot/pay/pr_01J9R6Y",
  "status": "pending",
  "amount_usdc": "5.00",
  "currency": "USDC",
  "network": "base",
  "expires_at": "2026-05-15T09:30:00Z"
}
GET/v1/payment-requests/{id}

Status, tx_hash, confirmations.

REQUEST
(no body)
RESPONSE
{
  "id": "pr_01J9R6Y...",
  "status": "confirmed",
  "tx_hash": "0xff5...e12",
  "confirmations": 12,
  "received_at": "2026-05-15T08:35:14Z",
  "confirmed_at": "2026-05-15T08:35:18Z"
}
GET/v1/transactions

List transactions with filters (agent_id, status, since, limit).

REQUEST
(query params: ?agent_id=agt_01J9...&status=confirmed&limit=50)
RESPONSE
{
  "data": [
    {
      "id": "tx_01J9...",
      "agent_id": "agt_01J9QKE...",
      "direction": "incoming",
      "amount_usdc": "5.00",
      "status": "confirmed",
      "tx_hash": "0xff5...e12",
      "counterparty": "0xBuyer...",
      "reason": "Research report",
      "confirmed_at": "2026-05-15T08:35:18Z"
    }
  ],
  "next_cursor": null
}
WEBHOOK SIGNATURE VERIFICATION

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 webhook delivery includes an X-Blockchain0x-Signature header containing the HMAC-SHA256 of the raw request body using your per-agent signing secret. Compute the same HMAC server-side, compare in constant time, and reject any mismatch with 401. Read the raw body, not a parsed JSON copy - parsing then re-serializing breaks the signature.

TYPESCRIPT (NODE + EXPRESS)
import crypto from "node:crypto";
import express from "express";

const app = express();
const SIGNING_SECRET = process.env.BLOCKCHAIN0X_SIGNING_SECRET!;

app.post(
  "/webhooks/payment",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.header("X-Blockchain0x-Signature") ?? "";
    const expected = crypto
      .createHmac("sha256", SIGNING_SECRET)
      .update(req.body)
      .digest("hex");

    const ok = crypto.timingSafeEqual(
      Buffer.from(signature, "hex"),
      Buffer.from(expected, "hex"),
    );
    if (!ok) return res.status(401).send("Invalid signature");

    const event = JSON.parse(req.body.toString());
    // event.type is "payment.received" | "payment.confirmed" | ...
    handleEvent(event);
    res.status(200).send("ok");
  },
);
PYTHON (FLASK)
import hmac, hashlib, os
from flask import Flask, request, abort

app = Flask(__name__)
SIGNING_SECRET = os.environ["BLOCKCHAIN0X_SIGNING_SECRET"].encode()

@app.post("/webhooks/payment")
def receive():
    signature = request.headers.get("X-Blockchain0x-Signature", "")
    expected = hmac.new(
        SIGNING_SECRET,
        request.get_data(),
        hashlib.sha256,
    ).hexdigest()
    if not hmac.compare_digest(signature, expected):
        abort(401)

    event = request.get_json()
    # event["type"] is "payment.received" | "payment.confirmed" | ...
    handle_event(event)
    return "ok", 200

The signing secret is rotatable per agent from the dashboard. Rotating invalidates the old secret immediately, so coordinate the rollout: update the secret in your server's env, deploy, then rotate in the dashboard. We send a one-event window with both old and new secrets on rotation to give you a clean cutover.

IDEMPOTENCY

Retry safely. The API will not create duplicate payment requests.

Agent code retries. Networks drop connections. LLMs decide to call the tool twice. To make this safe, send an Idempotency-Key header on every POST. We deduplicate on the (api_key, idempotency_key) pair for 24 hours: retry the same request within that window and you get the same response back, byte for byte.

BASH
curl -X POST https://api.blockchain0x.com/v1/payment-requests \
  -H "Authorization: Bearer $BLOCKCHAIN0X_KEY" \
  -H "Idempotency-Key: 8e2c3a40-research-q4-llm-report" \
  -H "Content-Type: application/json" \
  -d '{ "agent_id": "agt_01J9...", "amount_usdc": "5.00", "reason": "..." }'
  • First call: creates the payment request, returns the new pr_* ID.
  • Retry within 24h with same key: returns the same response, no new request created.
  • Retry with same key but different body: returns HTTP 409 with the original response - prevents accidentally drifting a logical operation.
  • Retry after 24h: dedup window expired, creates a new request. Pick a longer key window only if you really need it; 24h covers virtually all retry patterns.

The recommended pattern is to generate a UUID v4 per logical operation in your agent code (e.g. one UUID per "deliver paid research report for user X") and reuse it across retries until the operation succeeds. The official SDKs auto-generate these for you if you do not specify one.

RATE LIMITS

Per-plan steady-state and burst limits.

PlanSteady (req/min)BurstWrite access
Free60120Read-only
Pro6001,200Full
Business6,00012,000Full

Headers on every success response

  • X-RateLimit-Limit: your plan's steady rate
  • X-RateLimit-Remaining: how many calls left in this window
  • X-RateLimit-Reset: unix seconds when the window resets

When you hit the cap (HTTP 429)

  • Response includes Retry-After in seconds
  • The official SDKs auto-retry once per call with the Retry-After delay
  • Webhook deliveries TO you do not count against your inbound rate limit
  • API overage on Pro/Business is billed at $10 per 100k requests
X402 COMPATIBILITY

Speaks x402 fluently. Works without it too.

x402 is Coinbase's open protocol for HTTP-native payments. The premise: any API that returns 402 Payment Required can include payment instructions in the response, and any client that understands the spec can pay and retry the request - no signup, no API key, no out-of-band negotiation. Blockchain0x acts as an x402 facilitator: you can serve x402-compliant 402 responses from your own API and we settle the underlying USDC transfer.

YOUR API RETURNS THIS WHEN A CALLER HAS NOT PAID
HTTP/1.1 402 Payment Required
X-Payment-Required: true
X-Payment-Network: base
X-Payment-Asset: USDC
X-Payment-Amount: 0.05
X-Payment-Recipient: 0xYourAgentWalletAddress
X-Payment-Facilitator: blockchain0x
Link: <https://wallet.blockchain0x.com/a/your-agent/pay/pr_01J9...>; rel="payment"

What the agent caller does

  1. Sees the 402 response, parses the X-Payment-* headers and the payment Link.
  2. If the caller is x402-aware, it pays the URL automatically using the user's pre-authorized wallet (per Coinbase Smart Wallet UX patterns).
  3. If the caller is not x402-aware, it surfaces the hosted_url to the human for one-click payment.
  4. Either way, payment confirms, our webhook fires to your API, and the caller retries the original request - now authorized.

Without x402

You can also ignore x402 entirely and just hand the hosted_url we return from POST /v1/payment-requests to whoever owes you money. They click, they pay, your webhook fires. Less elegant than full x402 but simpler to integrate when you do not need protocol interop with other agent runtimes. The two patterns compose: you can ship the hosted flow on day one and add x402 headers when you are ready.

FREQUENTLY ASKED

Five API questions developers ask first.

Can I use the API without the SDK?

Yes. The SDKs are thin wrappers around standard JSON over HTTPS with bearer-token auth. Anything that can speak HTTP and HMAC-SHA256 can use the API directly. The SDKs exist for ergonomic typing and idempotency-key generation; they are convenient but not required. If you are working in a language we do not publish an SDK for (Go, Rust, Elixir, etc.), use the raw API.

What happens if my webhook endpoint is down when an event fires?

We retry with exponential backoff for 24 hours - first retry at 30 seconds, then 5 minutes, then 30 minutes, then hourly. Each delivery attempt is logged in the dashboard with its HTTP response code. If you exceed the 24-hour window without a 2xx response, the event is marked permanently failed; you can still fetch it via GET /v1/transactions with the relevant filters. We deliberately do not retry beyond 24 hours because payment confirmations older than that are usually no longer actionable.

How do I prevent duplicate payment requests if my agent retries on network errors?

Send an `Idempotency-Key` header on every POST. We deduplicate on the (api_key, idempotency_key) pair for 24 hours. If you retry the same request within that window, you get the same response (same payment_request_id, same hosted_url). The recommended pattern is to generate a UUID per logical operation in your agent code and reuse it across retries until the operation succeeds.

What is the rate limit and what happens at the cap?

Free plans get 60 requests per minute per workspace. Pro gets 600. Business gets 6,000. Burst capacity is roughly 2x the steady rate. When you exceed the limit, we return HTTP 429 with a Retry-After header in seconds and X-RateLimit-Remaining + X-RateLimit-Reset headers on every successful response. Webhook deliveries do not count against your inbound rate limit; that is bandwidth we eat.

Is this x402-compatible? Do I have to choose between x402 and your API?

Yes, x402-compatible. You can use Blockchain0x as an x402 facilitator by setting the X-Payment header semantics our docs describe, or you can ignore x402 entirely and just hand the hosted_url to your buyer. The two patterns work alongside each other. If you build for x402, you get free interop with anyone else implementing the spec (Coinbase, agent runtimes that ship x402 support). If you build for our hosted flow, you get a simpler integration with less surface area to test.

Ship your first payment request.

Free to start. Pro at $9 per agent per month unlocks the API.