AGENTS
x402: pay-per-call for AI agents
x402 is Coinbase's open standard for charging per HTTP request. Your agent's server returns 402 Payment Required with a JSON body describing the price; the client pays and retries with proof. It's the missing piece that lets autonomous agents charge per-token, per-byte, per-API-call. well below Stripe's $0.30 minimum.
Tab is a turnkey backend for x402. One API call mints a spec-compliant 402 response that points to a real Tab checkout. Settlement is on-chain, multi-currency, and you keep the same dashboard, receipts, refunds, and webhooks as any other Tab payment.
Authentication
Every call to POST /api/x402/charge requires an API key with write scope. Grab one (or create a key) at /dashboard/keys. Live keys start with sk_live_, test keys with sk_test_. The key must be sent in the Authorization: Bearer … header on every /chargerequest. Without it you'll get a 401 with no x402 challenge.
GET /api/x402/verify?orderId=… is public — no Bearer header needed. The order id is a 24-char nanoid, unguessable, so the id itself is the secret. Returns { paid: true | false } plus order metadata so your agent can decide whether to release the resource.
The flow
- Caller hits your agent's URL without an
X-PAYMENTheader. - Your agent calls
POST /api/x402/chargeon Tab with the price + the resource URL. - Tab returns a spec-compliant 402 JSON body. Your agent forwards it verbatim with status 402.
- Caller pays via the Tab checkout URL embedded in
extra.tab.checkoutUrl(or via the standard EIP-3009 path, if they're a Coinbase facilitator client). - Caller retries the original request. Your agent verifies via
GET /api/x402/verify?orderId=…and, onpaid: true, returns the resource.
Minting a 402
POST https://thetab.bar/api/x402/charge
Authorization: Bearer sk_live_…
Content-Type: application/json
{
"amount": "0.50",
"chain": "base",
"resource": "https://your-agent.example.com/research",
"description": "Run a 500-word research summary on the supplied topic"
}Response (HTTP 402, forward this verbatim to the caller):
{
"x402Version": 1,
"error": "X-PAYMENT header required",
"accepts": [
{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "500000",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"payTo": "0x…recipient",
"resource": "https://your-agent.example.com/research",
"description": "Run a 500-word research summary on the supplied topic",
"mimeType": "application/json",
"outputSchema": null,
"maxTimeoutSeconds": 60,
"extra": {
"name": "USDC",
"version": "2",
"tab": {
"checkoutUrl": "https://thetab.bar/pay/ord_8H3kZ…",
"orderId": "ord_8H3kZ…",
"verifyUrl": "https://thetab.bar/api/x402/verify?orderId=ord_8H3kZ…",
"chain": "base",
"currency": "USDC"
}
}
}
]
}Verifying a payment
On the caller's retry, hit the verify endpoint with the orderId from the original 402 response:
GET https://thetab.bar/api/x402/verify?orderId=ord_8H3kZ…
// when settled:
{
"paid": true,
"orderId": "ord_8H3kZ…",
"txHash": "0x…",
"chain": "base",
"amount": "0.50",
"currency": "USDC",
"payerAddress": "0x…"
}
// still waiting:
{ "paid": false, "status": "awaiting_payment", "expiresAt": 17040… }Or skip polling and use a Tab webhook subscription, every x402 order fires order.created on issue and order.completed on settlement, identical to any other Tab payment.
End-to-end in 20 lines
import express from "express";
const app = express();
const TAB = "https://thetab.bar";
const KEY = process.env.TAB_API_KEY!;
app.get("/research", async (req, res) => {
const paymentHeader = req.header("x-payment");
const orderId = req.query.orderId as string | undefined;
if (!paymentHeader && !orderId) {
// No payment yet, mint a 402.
const r = await fetch(`${TAB}/api/x402/charge`, {
method: "POST",
headers: { authorization: `Bearer ${KEY}`, "content-type": "application/json" },
body: JSON.stringify({
amount: "0.50",
chain: "base",
resource: `${req.protocol}://${req.host}/research`,
description: "AI-generated research summary",
}),
});
res.status(402).json(await r.json());
return;
}
// Caller is retrying, verify the order settled.
const v = await fetch(`${TAB}/api/x402/verify?orderId=${orderId}`).then((r) => r.json());
if (!v.paid) return res.status(402).json({ error: "still waiting", status: v.status });
// Paid, return the resource.
res.json({ summary: await runResearch(req.query.topic as string) });
});
app.listen(3000);What you don't have to build
- EIP-3009 / EIP-712 signing flow. Tab's checkout handles it.
- Multi-chain routing. Tab handles USDC on Base, USDT on BSC, USDC on Solana, etc.
- Refunds, call
/api/orders/[id]/refundif your agent fails to deliver and the caller's funds go straight back on-chain. - Dashboards, receipts, exports, every x402 charge shows up at
/dashboard/ordersthe same as any other Tab payment.
Cost
Same 1% protocol fee as any Tab payment. No per-call surcharge, no minimum amount, a $0.01 x402 charge nets the merchant $0.0099. That's 30× lower than Stripe's $0.30 minimum, which is what makes per-token agent billing finally viable.