# How to give an AI agent a budget

_By Apoorv Khanna, July 6, 2026_

The question comes in four costumes. How do I give an agent a budget. How do I stop it from overspending. How do I put guardrails on it. How do I see what it actually spent. Underneath the costumes it is one question, and it has one answer: three numbers and a list. A monthly limit on the key the agent uses. A maximum cost the agent states on every call. A ceiling on what the account as a whole may owe. And a list of categories the key is allowed to spend in. Everything below is an explanation of why those four, in that shape, and what happens the moment one of them says no.

## Why a budget for an agent cannot be a budget for a person

Human budgets are monthly because salaries are monthly, and because a person can only bear so many spending decisions before the mental transaction cost of each one outweighs the money involved. Nick Szabo wrote this down in 1999 and nothing since has contradicted him. We set a number for the month, we stop thinking, and we check the statement later. The control is retrospective, and it works because a human makes perhaps thirty purchase decisions in a month and remembers most of them.

An agent makes thirty purchase decisions before lunch. A research loop that fans out across five providers, retries twice on a timeout, and then enriches the results is easily a hundred priced calls, each of them small, none of them remembered. A monthly number alone is useless against this, in the same way a monthly number is useless against a tap left running. By the time you check the statement the month is gone and so is the money. So the shape of an agent budget has to change. The control has to sit in front of every call, not behind the month, and it has to be enforced by something the agent cannot talk its way past.

That is the design principle behind every control on a Vaaya account. Each one is checked before a call reaches a provider. None of them is checked afterwards. **A limit that is only discovered on the statement is not a limit; it is a report.**

## Set a monthly budget per agent

Start by giving each agent its own key. This sounds like housekeeping and it is the single most important step, because everything else attaches to the key. One key per agent means one budget per agent, one history per agent, and one thing to revoke when an agent misbehaves without touching the others.

On the key, set two things. The categories it may spend in, chosen from Data, Search, Scraping, Media, Compute, LLM router, and Outbound. And the most it may spend in a calendar month. A key with no category restriction can spend in all of them, which is fine for a general assistant and wrong for almost everything else.

A policy for a research agent, written out the way it appears on the account:

| Key | research-agent |
| --- | --- |
| Categories | Search, Data |
| Monthly limit | $25.00 |
| Per-call ceiling | Set by the agent on each call |
| Not permitted | Media, Compute, LLM router, Outbound |

With this in place the agent can run searches and enrich contacts up to twenty-five dollars in the month. It cannot generate a video, start a sandbox, or send an email, no matter how persuasive the prompt that asked it to. When the twenty-five dollars are spent, the next paid call on that key is refused until the month rolls over, and the refusal tells the agent exactly why:

```text
this API key's monthly spend limit of 2500¢ is reached (2500¢ spent this month)
```

## Stop an agent overspending on a single call

The monthly limit stops the slow leak. It does nothing against the single expensive mistake, the one call that costs five dollars because the agent asked for a thousand rows when it needed ten. For that there is a second control, and it is the one the agent applies to itself.

Every call an agent makes through Vaaya carries a maximum cost, in cents, stated by the agent. The tool is called `use`, and the argument is `max_cost_cents`:

```json
{
  "service": "exa",
  "action": "search",
  "params": { "query": "agentic payments protocols 2026", "numResults": 10 },
  "max_cost_cents": 5,
  "intent": "find primary sources for a protocol comparison"
}
```

Before the call runs, the quoted price is compared to that ceiling. If the price is at or under it, the call runs and the receipt shows what was charged. If the price is over it, the call does not run. The response is a refusal, not a bill:

```json
{
  "error": "over_max",
  "message": "price is 8¢ but max_cost_cents was 5",
  "price_cents": 8
}
```

Nothing was charged. The provider was never contacted. The refusal is recorded against the key with its reason, so you can see later that the agent tried, and the agent receives the reason in the response so it can decide whether to raise its ceiling, pick a cheaper provider, or carry on with the work it can afford. In practice a well-built agent gets the price from `consult` first, sets the ceiling a little above it so a retry does not fail on a rounding change, and never sees this message. A badly built agent sees it constantly and costs you nothing.

This is the control that makes the difference between a budget and a hope. The agent cannot spend more on a call than it said it would, and it has to say so every time.

## Put guardrails on what an agent can buy

Guardrails are the controls that shape what the agent may do at all, before price ever enters it.

1. **Categories on the key.** Already covered above, and worth repeating because it is the guardrail most people skip. An agent that only needs search should only have search. Restricting the category is what turns a prompt injection that says "now generate a video of the CEO" into a refused call rather than an invoice.

2. **The account ceiling.** Separate from any key. The account as a whole has a limit on what it can owe, set per account, and it does not care how many keys exist or what their monthly limits add up to. Ten keys with a fifty-dollar limit each do not become a five-hundred-dollar exposure if the account ceiling is a hundred.

3. **Approval for outbound work.** Emails and messages an agent drafts wait for a person to approve them before they are sent. This is the one place where a human sits in the loop by default, because an email cannot be refunded. Automated sending needs an explicit rule, and every rule carries a daily cap.

4. **Revocation.** A key that misbehaves is revoked in one action and the agent behind it stops spending immediately. Because each agent has its own key, revoking one changes nothing for the others.

## Monitor what an agent actually spent

Every call, its quoted price, what was charged, the receipt, and every refusal with its reason are attributed to the key that made them and shown in the agent history. There is no separate report to pull and no sampling. If an agent attempted something and was refused, that attempt is in the history next to the calls that succeeded, which is usually the more interesting half of the record. It is where you find out that the research agent tried to start a sandbox on Tuesday.

## What is not a budget here

Two things people ask for, and the honest answer to each.

There is no daily limit on a key. Limits on keys are monthly. If you need a tighter bound than that, the per-call ceiling and the account ceiling are the tools, and they apply at every single call, which is tighter than daily in every way that matters.

There is no approval prompt on paid API calls. A person is not asked to confirm each five-cent search, because a person asked to confirm five hundred five-cent searches will approve the five-hundred-and-first without reading it, and then the control is theatre. The ceiling is the control. The agent states the most it will pay, the system refuses anything above it, and the human sets the monthly and account bounds inside which that happens. Approval is reserved for the one class of action that cannot be undone, which is sending something to a person outside the account.

That is the whole design. Four numbers, all checked before the call, none of them negotiable by the agent, all of them visible after. The full list of controls is on the [spending controls](/spending-controls) page, and the install is one line.

```bash
npx @vaaya/mcp install
```

## Questions

**How do I give an AI agent a budget?**

Give the agent its own API key, restrict the key to the categories it needs, and set a monthly spending limit on it. The agent then states a maximum cost on every call it makes, and the account as a whole carries a ceiling on what it can owe.

**How do I prevent an AI agent from overspending?**

Every call carries a maximum cost the agent sets. If the quoted price is higher, the call does not run, nothing is charged, and the refusal is recorded with its reason. The key's monthly limit stops the slow leak; the per-call ceiling stops the single expensive mistake.

**Can I set a daily budget for an AI agent on Vaaya?**

No. Limits on keys are monthly. The per-call ceiling and the account ceiling apply at every call. Daily caps exist only on rules that allow automated outbound sending.

**How can I monitor what my AI agent is spending?**

Every call, its price, its receipt, and every refusal is attributed to the key the agent used and shown in the agent history. Nothing an agent spends or attempts to spend is invisible.
