How to cap API key spend so an agent doesn't drain your balance

An agent stuck in a loop can burn through a balance overnight. A separate key, limits, a model list and proper error handling put a ceiling on spend.

6 min · · API keys · агенты

An agent stuck in a loop or handed too big a task can burn through your entire balance overnight. You can cap API key spend in several layers: a separate key per agent, a daily and monthly ceiling, an allowed-models list, and code that reacts correctly to limit errors. Let's go through each layer and where to see actual spend.

A separate key for each agent

Limits in Zukko are set per key, not per account. So the first step is a separate key for each agent or pipeline, with a clear name: agent-review, nightly-labeling, support-bot.

What you get:

  • each agent has its own ceiling, and an agent that hits its limit doesn't stop the others — other keys keep working;
  • if a key leaks or an agent misbehaves, you can revoke it without touching other integrations;
  • the settings show at a glance which agent can access which models.

The full key is shown once, at creation — store it in the agent's environment variables or secrets. Keys are created under API keys.

Daily and monthly limits

Each key can have a spending ceiling in dollars per day and per month. How it works, per the key limits documentation:

  • The check happens before the request reaches the model, so a rejected request costs nothing.
  • Daily spend resets at 00:00 UTC, monthly spend at the start of the month (UTC).
  • An empty limit or 0 means no limit.
  • Web search requests count toward the limits too.

The limits are soft

This is an important detail. Before a request, the gateway compares what has already been charged with the ceiling, and the cost of the request itself isn't known in advance. So the last request let through can exceed the ceiling, and several parallel requests started before the limit was reached will all go through. With five parallel agents on one key, the overrun can be noticeable — leave a margin or split them across keys.

How to pick the number

Estimate the cost of one agent run and multiply by runs per day. Example: an agent on claude-sonnet-5 uses 3M input tokens per run (2.7M cache reads, 0.15M cache writes, 0.15M fresh input) and 0.1M output tokens. At per-1M prices (input 0.2, output 1.013, cache read 0.025, cache write 0.25):

0.15 × 0.2 + 2.7 × 0.025 + 0.15 × 0.25 + 0.1 × 1.013 = 0.03 + 0.0675 + 0.0375 + 0.1013 ≈ $0.24 per run.

Five runs a day — 5 × 0.2363 ≈ $1.18. A reasonable daily limit is $2: a normal day fits, and a looping agent stops after about eight runs (2 / 0.2363 ≈ 8.5). Set the monthly limit below daily × 30 — it catches slow spend growth that the daily limit doesn't notice.

Caching matters in this estimate: for Claude, the cache discount comes with the Anthropic format (/v1/messages); in the OpenAI format all Claude input is billed at the input price, and the same run would cost 3 × 0.2 + 0.1 × 1.013 ≈ $0.70. Take your real numbers from the usage history after the first day. Prices in the estimate are as of October 6, 2026; current models and prices: GET https://api.zukko.pro/v1/models or the Models page in the dashboard.

allowed_models: only the models you need

The second ceiling is the list of models allowed for the key (allowed_models). If a classification agent only needs deepseek-v4.1-flash and glm-5.3-flash, allow just those. Then a config mistake that makes the agent call claude-fable-5-1 ($3.48 / $17.4 per 1M versus $0.013 / $0.038 for DeepSeek V4.1 Flash) ends in a 403 error, not a bill.

For a coding agent the list might be claude-sonnet-5 and claude-opus-5-5. More on setup is in the article on allowed_models.

Which errors an agent will get and what to do

StatusCodeWhat happenedRetry?
402insufficient_balancebalance below $0.01only after a top-up
403model_not_allowed_for_keymodel not in the key's listno, fix the config
429key_daily_limit_reachedkey's daily limit used upafter 00:00 UTC or raise the limit
429key_monthly_limit_reachedkey's monthly limit used upnext month (UTC) or raise the limit
429provider codelimit on the model provider's sideyes, with a pause

Zukko has no rate limit of its own: a 429 from the gateway means only the key limits you set yourself. Any other 429 came from the model provider. So parse the error by the error.code field, not just the status.

This matters especially for agents: many clients retry any 429 by default. The official OpenAI Python SDK, for example, retries 429 and 5xx errors automatically. Retries against an exhausted limit are free but pointless: the agent will spin until midnight UTC instead of stopping and reporting the problem.

Handling it in code

A Python example: the SDK's automatic retries are off, decisions are made by error code, and each request's cost is read from the X-Zukko-Cost-Micros header (in microdollars, present on regular, non-streaming responses).

bash
import os
import time

import openai
from openai import OpenAI

client = OpenAI(
    base_url="https://api.zukko.pro/v1",
    api_key=os.environ["ZUKKO_AGENT_KEY"],
    max_retries=0,
)

STOP_CODES = {
    "insufficient_balance",

agent_is_done and next_messages are your agent's own logic: checking whether the task is finished and building the next messages (the model's reply, tool results). The task budget and MAX_STEPS are a third layer on top of key limits: they cap a single task, not the whole day. The full list of codes and retry rules is in the errors section of the documentation and in the article on error handling and a fallback model.

Where to see spend

  • Dashboard, Usage section. Per-request spending history: time, model, tokens, cost. The first place to look after an agent's first day.
  • GET /v1/balance. The current account balance in cents. The balance is shared across all keys. An expensive request started with a small remainder can push the balance negative — then subsequent requests get 402 until you top up. Details in the balance docs.
  • GET /v1/usage. Spending history via API, with pagination. Note: it includes all account charges, not just this key's.
bash
curl -G https://api.zukko.pro/v1/usage \
  -H "Authorization: Bearer $ZUKKO_AGENT_KEY" \
  --data-urlencode "limit=50"

Both requests are free. If you need spend for a specific agent, sum X-Zukko-Cost-Micros in its code, as in the example above.

FAQ

Am I charged for a request rejected by a limit?

No. Limits and the model list are checked before the request reaches the model, so a rejected request costs nothing.

Why did the agent spend slightly more than the limit?

The limits are soft: the last request let through can cross the ceiling, and parallel requests started before the limit was reached all go through. Leave a margin or spread parallel agents across keys.

When does the daily limit reset?

At 00:00 UTC, which is 03:00 Moscow time. The monthly one resets at the start of the calendar month, UTC.

What happens to other keys when one hits its limit?

They keep working: the limit applies to the key, not the balance. But the balance is shared by all keys, and if it runs out, all of them get 402.

zukko

Pay 25×
less

for Claude Code & ChatGPT

One fetch_* key and base URL api.zukko.pro — for Cursor, Claude Code, Codex, and any SDK.

Get API keyDocumentation

api.zukko.pro · fetch_*

Cap API key spend: limits for AI agents · Zukko