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.
bash
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:

bash
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:

bash
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")); // microdollars

The 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:

bash
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:

bash
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:

bash
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:

bash
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.

Get API keyDocumentation

api.zukko.pro · fetch_*

Real-time API spend monitoring via headers · Zukko