USDC payments
The exact wire format for the x402 dance against Cloven. Use this if you're rolling your own HTTP client; the SDK in wallet mode handles all of this transparently.
The 402 response
When a request arrives without Authorization: Bearer … and without a valid X-Payment header, Cloven returns:
HTTP/1.1 402 Payment Required
Content-Type: application/json
X-402-Version: 1
{
"x402_version": 1,
"accepts": [
{
"scheme": "exact",
"network": "base",
"asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
"amount": "1000",
"recipient": "0xClovenTreasury...",
"valid_until": "2026-05-24T12:05:00Z",
"nonce": "01HXY8AB7M3Q4R5S6T7U8V9W0X",
"metadata": {
"tool": "cloven.fresh",
"pack": "crypto",
"base_price_usd": "0.001",
"tier_discount_applied": false
}
}
]
}Fields:
asset— USDC contract on Base (canonical address shown above).amount— USDC with 6 decimals, as a string."1000"= 0.001 USDC.recipient— Cloven treasury wallet. Hard-pinned viaX402_RECIPIENT_ADDRESSenv var server-side; the client should trust the response and pay only this address.valid_until— ISO8601. Quote expires after this; new request → new quote.nonce— server-generated ULID. Pass this into your transfer's calldata (or via an EIP-2612 memo) so the tx is unique per quote.metadata.tier_discount_applied— true if you passedX-402-Payer-Hintand a stake discount applied (Phase 3+).
The accepts array currently contains exactly one option. The shape allows for multi-asset / multi-chain quotes in the future; clients should treat it as ordered (server's preferred option first).
Sign and broadcast
Sign a USDC transfer on Base for the quoted amount to the quoted recipient. With viem:
import { encodeFunctionData, parseUnits } from "viem";
const calldata = encodeFunctionData({
abi: usdcAbi,
functionName: "transfer",
args: [recipient, BigInt(amount)], // amount is already in 6-decimal units
});
const txHash = await wallet.sendTransaction({
to: asset, // USDC contract
data: calldata,
value: 0n,
});
await waitForTransactionReceipt({ hash: txHash, confirmations: 1 });You only need 1 confirmation on Base — block time is ~2 seconds, finality is fast enough that 1-conf is the recommended setting.
The X-Payment header
After the tx confirms, retry the original request with X-Payment set to a base64-encoded JSON payload:
GET /v1/fresh?pack=crypto HTTP/1.1
Host: api.cloven.cloud
X-Payment: eyJzY2hlbWUiOiJleGFjdCIsIm5ldHdvcmsiOiJiYXNlIiwidHhIYXNoIjoiMHhhYmMuLi4iLCJwYXllciI6IjB4V2FsbGV0In0=The decoded payload:
{
"scheme": "exact",
"network": "base",
"txHash": "0xabc...",
"payer": "0xWallet..."
}Fields:
scheme— match the quote ("exact"for v1).network— match the quote ("base"for v1).txHash— the confirmed USDC transfer tx.payer— the wallet that signed the tx. Used for stake-tier discount lookup (Phase 3) and for trace attribution.
The header must be base64 of the JSON. Naked JSON in the header is rejected.
Server verifies
Cloven verification order (any failure → 402 with a typed error code):
- Header parse. Base64 decode → JSON parse → required fields present. Failure:
400 invalid_payment. - Idempotency check.
redis.exists("x402:tx:" + txHash). If set, accept the cached settlement (idempotent replay). If a fresh request — proceed. - On-chain lookup.
eth_getTransactionReceipt(txHash)viaX402_RPC_URL. Failure (RPC down, hash invalid):402 tx_not_found. - Status check. Receipt's
statusfield is0x1. Otherwise:402 tx_reverted. - Event check. Receipt logs include a
Transfer(from = payer, to = recipient, value)event from the USDC contract, wherevalue ≥ quoted amount. Otherwise:402 insufficient_payment(orwrong_recipient). - Age check.
block.timestampwithin last 10 minutes. Otherwise:402 tx_too_old. - Cache idempotency. Set
x402:tx:<txHash>in Redis with 24h TTL. - Serve. 200 OK with the MindResponse and
X-402-Settled: <txHash>+X-402-Amount-Paid: <amount>headers.
Successful response headers
HTTP/1.1 200 OK
Content-Type: application/json
X-402-Settled: 0xabc...
X-402-Amount-Paid: 1000
X-Mind-Freshness: 2m14s
X-Request-Id: req_01HXY8AB...
{ "state": {...}, "brief": "...", "citations": [...], "freshness": {...} }Idempotency rules
- The 24-hour cache lets you retry the API call freely with the same
X-Paymentheader — useful if the response was lost in transit. - Re-using a tx hash from a different call (same hash, different endpoint / pack / args) is fine. The payment is "I paid for one API call within 24h."
- After 24h, the cache purges. The tx becomes "too old" on the next attempt — pay fresh.
Underpayment
If the on-chain Transfer.value is less than the quoted amount, the tx is not partially credited. Cloven returns:
{
"error": {
"code": "insufficient_payment",
"message": "tx 0xabc paid 500, quote was 1000; re-quote and pay full amount",
"requestId": "req_..."
}
}The underpayment USDC stays in the Cloven treasury — there is no refund mechanism. Don't underpay.
Wrong recipient / wrong network
If the tx was signed to a different recipient (typo, frontrun, replay attack), Cloven cannot credit it. Same for tx on the wrong network (Ethereum mainnet instead of Base). The payment is lost to the wrong destination, and Cloven returns 402 wrong_recipient / 402 network_mismatch. The client wrote the tx — it's the client's responsibility to sign to the address from the live quote.
Rate limit
Even paid requests pass through the Redis sliding-window rate limit (anti-DDoS). Default 100 req/min per wallet. Diamond stake tier raises this to 1000 req/min (Phase 3).