SDK x402 wallet mode
Pass a viem WalletClient to the SDK factory and Cloven handles the entire x402 payment dance for you — quote, sign, wait for confirmation, retry the call with proof, return the response. No human in the loop. No API key issued.
This is the canonical autonomous-agent path. Your agent owns a wallet, the wallet holds USDC on Base, every call costs fractions of a cent, and there is no monthly subscription to provision in advance.
Setup
import { cloven } from "@cloven/sdk";
import { createWalletClient, http } from "viem";
import { base } from "viem/chains";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.AGENT_PK as `0x${string}`);
const wallet = createWalletClient({
account,
chain: base,
transport: http(process.env.BASE_RPC_URL),
});
const client = cloven({ wallet });That's it. Every call now auto-pays:
const ctx = await client.pack("crypto").fresh();
// internally:
// 1. GET /v1/fresh → 402 with PaymentRequirements
// 2. wallet.writeContract(USDC.transfer, recipient, amount)
// 3. wait for 1 confirmation on Base (~2s)
// 4. GET /v1/fresh + x-payment header
// 5. return MindResponse to callerCost ceilings
Locked v1 pricing — every call's exact USDC cost is known in advance from the PRICING_USDC table:
| Operation | USDC per call |
|---|---|
cloven.fresh | 0.001 |
cloven.brief | 0.005 |
cloven.search | 0.002 |
cloven.cite | 0.001 |
cloven.snapshot | 0.01 |
cloven.subscribe | 0.005 / hour |
To enforce a per-call budget, wrap the client:
const MAX_PER_CALL_USDC = 0.01;
async function safeCall<T>(fn: () => Promise<T>): Promise<T> {
// The SDK fires a 'x402:quote' event before signing — abort if too pricey
return new Promise((resolve, reject) => {
const onQuote = (q: { amount: string }) => {
if (parseFloat(q.amount) > MAX_PER_CALL_USDC) {
client.off("x402:quote", onQuote);
reject(new Error(`quote ${q.amount} exceeds ceiling ${MAX_PER_CALL_USDC}`));
}
};
client.on("x402:quote", onQuote);
fn().then(resolve, reject).finally(() => client.off("x402:quote", onQuote));
});
}
const ctx = await safeCall(() => client.pack("crypto").fresh());Events
The SDK emits typed events you can subscribe to for observability:
client.on("x402:quote", ({ tool, amount, recipient, expiresAt }) => {
log.info("about to pay", { tool, amount });
});
client.on("x402:paid", ({ txHash, blockNumber }) => {
log.info("tx confirmed", { txHash, blockNumber });
});
client.on("x402:settled", ({ tool, mindResponse }) => {
log.info("response received", { tool, brief: mindResponse.brief.slice(0, 60) });
});Useful for billing reconciliation — your spend ledger is the sum of x402:paid events.
Discount hints (Phase 3)
When the $CLOVEN token launches in Phase 3, your wallet may qualify for a stake-tier discount on each call. The SDK automatically passes X-402-Payer-Hint: <wallet> so the 402 quote arrives pre-discounted. No code change required — the discount mechanism activates server-side once the token is live.
Until Phase 3 ships, lib/billing/discounts.ts returns 0% for every wallet. The hint is sent regardless; it's just ignored.
Failure modes
| Symptom | Likely cause | Mitigation |
|---|---|---|
X402Required thrown | Wallet rejected the sign request | Check the wallet has USDC + gas (ETH on Base). |
tx_too_old returned | Tx confirmed > 10 min after quote | RPC was slow; retry — the SDK will re-quote. |
insufficient_payment | Tx amount under quoted price | Should not happen — file an issue with requestId. |
| Endless retry loop | RPC down, wallet client failing | The SDK caps retries at 3. After that, X402Required is thrown. |
Prepaid escrow (Phase 1.5)
For high-throughput agents that don't want the per-call sign overhead, Phase 1.5 ships an optional prepaid escrow mode: deposit USDC to a Cloven-managed contract once, and each call debits from the balance without a per-call transaction. Same SDK constructor, same call surface — the SDK transparently uses the escrow when the wallet has a deposit on file.
Combined modes
You cannot combine apiKey and wallet in one client — pass one. If you operate both a human-owned subscription and an autonomous agent, instantiate two clients:
const human = cloven({ apiKey: process.env.CLOVEN_KEY });
const agent = cloven({ wallet });They are independent — separate quotas, separate billing paths, separate dashboards.