Real-time spend monitoring from response headers
You don't need to wait for a daily report to know what a request cost — the price and the remaining balance arrive in the headers of every non-streaming response. Here's how to use that.
4 min · · Updated · API · экономия
Usually you find out about API spend after the fact: you open a dashboard, see a total for the day, and dig through which of ten endpoints ran it up. Here it works differently — the cost of a specific request and the remaining balance come back right in the response headers, no separate report needed.
Two headers that cover half of monitoring
Every response carries:
X-Zukko-Cost-Micros— the cost of that exact request in microdollars (1,000,000 = $1).X-Fetch-Balance-Cents— the remaining balance after the charge, in cents.
curl -si https://api.zukko.pro/v1/chat/completions \
-H "Authorization: Bearer fetch_your_key" \
-H "Content-Type: application/json" \
-d '{"model":"claude-sonnet-5","messages":[{"role":"user","content":"test"}]}' \
| grep -i "x-zukko-cost\|x-fetch-balance"Nothing needs to be computed separately from token counts and a price list — the cost is already calculated on the gateway's side for that specific model.
Log the headers instead of waiting for an export
A small Python wrapper that writes the cost of every call to your own metrics system instead of checking the dashboard once a day:
import requests
def call_model(payload, api_key):
resp = requests.post(
"https://api.zukko.pro/v1/chat/completions",
headers={"Authorization": f"Bearer {api_key}"},
json=payload,
)
cost_micros = int(resp.headers.get("X-Zukko-Cost-Micros", 0))
# despite the name, this header is in microdollars (1_000_000 = $1)
balance_micros = int(resp.headers.get("X-Fetch-Balance-Cents", 0))
metrics.gauge("zukko.balance_micros", balance_micros)
metrics.increment("zukko.cost_micros", cost_micros)
if balance_micros < 5_000_000: # under $5 — raise an alert
alert("zukko.pro balance below $5")
return resp.json()The same thing in JS:
const resp = await fetch("https://api.zukko.pro/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
const costMicros = Number(resp.headers.get("x-zukko-cost-micros"));
const balanceMicros = Number(resp.headers.get("x-fetch-balance-cents")); // microdollarsThe difference from an after-the-fact report: the alert fires at the moment the request crosses a threshold, not the next day while you're going through logs.
Attributing cost to a specific request, not to a blended average
If a service makes calls to different models within one user action — say, classifying the request with a light model first, then processing it with the flagship — the header on each individual HTTP response gives the exact cost of each step. Summing X-Zukko-Cost-Micros across every call in one user session gives you the actual unit economics of a feature, instead of a rough "average across all models" guess.
Cache hits are free repeats, and they show up in the headers too
If a request is sent with the X-Zukko-Cache: true header (temperature: 0 also enables it, but only on models that accept it — Claude models may reject a temperature other than 1), identical requests from the same user get cached (for chat, for up to 7 days). A repeated identical request comes back instantly and isn't charged, and the response marks it with an X-Zukko-Cache: hit header. The cache only fires on a fully identical request body, and these hits aren't written to /v1/usage. It's worth logging that too — the share of cache hits directly shows how much traffic you could stop paying for by turning caching on where it currently isn't:
curl -si https://api.zukko.pro/v1/chat/completions \
-H "Authorization: Bearer fetch_your_key" \
-H "X-Zukko-Cache: true" \
-H "Content-Type: application/json" \
-d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"test"}]}' \
| grep -i "x-zukko-cache"/v1/usage is for reconciliation, not real time
Headers give you an instant snapshot, while the charge history with cursor pagination is for reconciling a period. It covers the whole account (all keys together, no per-key filter); each entry has created_at, model, input_tokens, output_tokens, total_tokens and cost_cents (fractional cents), plus next_cursor for the next page:
curl https://api.zukko.pro/v1/usage \
-H "Authorization: Bearer fetch_your_key"A sensible setup: headers get written to metrics on every call and trigger alerts immediately, while /v1/usage reconciles the summed headers against the official history once a day — keep in mind that streaming requests don't show up in headers and exist only in /v1/usage; if the numbers diverge beyond those, header logging is silently failing somewhere, and it's worth finding that before the invoice diverges too.
Account balance is separate from a single key's limit
X-Fetch-Balance-Cents shows the balance of the whole account, not a specific key's cap — if a key has a daily or monthly spend limit configured, that's tracked separately and shows up as a 429 with key_daily_limit_reached or key_monthly_limit_reached once it's exhausted. For monitoring a capped key, sum X-Zukko-Cost-Micros per day on your own side and compare it against the configured limit, so you see the threshold approaching ahead of time instead of only at the moment of rejection.
A quick check that everything is wired up
The overall balance, without a breakdown by request, is always available directly:
curl https://api.zukko.pro/v1/balance \
-H "Authorization: Bearer fetch_your_key"If the number from /v1/balance doesn't match what's accumulated in your header logs, the wrapper around your HTTP client is failing to read headers or losing them on retries — check that part of the code, not the billing itself.
Estimating cost before sending, not after
Headers are great for showing what an already-sent request cost, but sometimes you need the price ahead of time — before a batch of a thousand prompts, say, which is cheaper to stop before sending than to monitor mid-flight. There's a separate free endpoint for that, which counts tokens without executing the request:
curl https://api.zukko.pro/v1/messages/count_tokens \
-H "Authorization: Bearer fetch_your_key" \
-H "Content-Type: application/json" \
-H "anthropic-version: 2023-06-01" \
-d '{"model":"claude-opus-5-5","messages":[{"role":"user","content":"..."}]}'Knowing the token count and the model's current price from /v1/models/info, you can estimate the cost of the whole batch before it ever ships, and compare it against the limit set on the key — instead of finding out the real number after the fact from headers or /v1/usage.
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.
Related articles
- opencode agents: setting up roles, models and toolsA custom agent in opencode is a role, a model and a set of permissions. A working config where a cheap model handles routine work and a stronger one edits code.
- Plan mode in Claude Code: plan first, then edit the codeIn plan mode Claude Code reads your code and proposes a plan but edits nothing until you agree. How to enable it, use it and what it costs.
- Buying AI tokens: how a dollar balance works and what $5 gets youTokens at a gateway are not a package but a dollar balance. We look at what is charged to it and calculate how many requests $5 covers.
- Paying for AI without a fee: is it possible and how to calculate the overpaymentThere is almost always a fee when you top up. We show what it consists of, calculate it for SBP and card, and give a formula for how many rubles you need for N dollars.