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 caller

Cost ceilings

Locked v1 pricing — every call's exact USDC cost is known in advance from the PRICING_USDC table:

OperationUSDC per call
cloven.fresh0.001
cloven.brief0.005
cloven.search0.002
cloven.cite0.001
cloven.snapshot0.01
cloven.subscribe0.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

SymptomLikely causeMitigation
X402Required thrownWallet rejected the sign requestCheck the wallet has USDC + gas (ETH on Base).
tx_too_old returnedTx confirmed > 10 min after quoteRPC was slow; retry — the SDK will re-quote.
insufficient_paymentTx amount under quoted priceShould not happen — file an issue with requestId.
Endless retry loopRPC down, wallet client failingThe 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.