Wuraw
Open App

Blog · Agents

Building an agent with a spend cap

A walkthrough of giving autonomous software its own key, its own budget and its own audit trail — and why the cap has to live with the signer rather than in an admin console.

June Watanabe5 min read

The first agent anybody ships runs on a shared API key with a shared budget, and it works fine until it does not. The failure is rarely dramatic. Usually it is a retry loop that grows its own context, or a scheduled job that fires on an hour boundary instead of a day boundary, or a tool call that returns a large document which then gets re-sent on every subsequent turn. By the time anyone looks, the balance is gone and there is no per-caller breakdown that would tell you which of the six agents did it.

01

Where a limit has to live

Most spend controls in this market are server-side policy: a number in a dashboard, enforced by the vendor when a request arrives. That is useful and it is also the weaker half of the design, for two reasons. It only fires after the request has been sent, so you find out about the overspend from a rejection rather than preventing the attempt. And it is enforced by the counterparty, which means you are trusting the entity being paid to decline your money.

When payment is a signature, the strong version becomes available. The agent holds a key. The key is authorized for an amount. A request that would exceed the authorization is never signed, so it is never sent, so no server has to be trusted to refuse it. The limit is a property of the payer.

02

Give the agent its own key

Start by not sharing. Each agent gets a distinct signer, funded deliberately with what it is allowed to spend for the period. This is the same instinct as a per-service credential, with the useful property that the credential's blast radius is denominated in dollars rather than in permissions.

ts
import { Wuraw } from "@wuraw-protocol/sdk";

const router = new Wuraw({
  baseUrl: "https://api.<your-domain>/v1",
  wallet:  researchAgentSigner,          // this agent's own key
  budget: {
    perRequestMax: "0.08",               // USDG
    perDayMax:     "5.00",
    onExceeded:    "reject",             // "reject" | "downgrade" | "queue"
  },
  routing: {
    policy:   "cost",                    // "cost" | "latency" | "quality"
    fallback: ["wuraw/reasoner-mid", "wuraw/reasoner-small"],
  },
});

The onExceeded field is the design decision worth thinking about. Rejecting is safe and loud. Downgrading — routing to a cheaper model in the same alias family once the budget tightens — keeps the agent alive at reduced quality, which is right for a monitoring agent and wrong for one whose output goes to a customer. Queueing defers to the next budget window, which is right for batch work and a trap for anything interactive.

03

Decide what happens at the ceiling

An agent that hits its cap and throws an unhandled exception has converted a cost problem into an availability problem. Handle the refusal explicitly. The pattern that has worked for us is a three-tier response: continue on the cheap path, then degrade to a cached or heuristic answer, then stop and emit a signal a human will actually see.

ts
try {
  return await router.chat.completions.create({ model, messages });
} catch (err) {
  if (err instanceof BudgetExceeded) {
    metrics.increment("agent.budget_exhausted", { agent: "research" });
    return fallbackFromCache(messages) ?? escalateToHuman(err.remaining);
  }
  throw err;
}

04

The audit trail comes free

This is the part that surprises people. Because every paid call settles onchain, the spend record is not something the router generates for you and could get wrong — it is the settlement itself. Every transfer carries the payer address, the amount, the timestamp and the resource. Filter by the agent's address and you have a complete, independently verifiable ledger of what that agent spent, with no logging pipeline involved. The USDG moved or it did not.

Per-agent spend attribution is not a feature we built. It is a side effect of the agent having its own wallet.

The same property is the privacy cost, and it should be stated in the same breath. That ledger is public. Anyone who learns your agent's address can see its spending rhythm — how often it runs, roughly how expensive its calls are, when it went quiet. Not the prompts, not the completions, not the model in most cases. But the shape of the workload is visible, and if that matters for your use case, rotate signers per period rather than running one address forever.

05

Start smaller than feels necessary

Set the daily cap to roughly twice your expected spend for the first week, not ten times. The point of a low cap early is that it fires, and a cap that fires teaches you something about your agent's actual behaviour that no amount of estimation will. Raise it once you have a week of settled transactions to reason from — and on Wuraw you can read exactly that from the chain, across all 400+ models, without asking anyone for an export.

Written by June Watanabe · published 30 May 2026 · filed under agents. Figures cited here carry their source inline; if one has aged badly, the correction goes on the post.