Мониторинг расхода в реальном времени по заголовкам ответа

Не нужно ждать отчёта за сутки, чтобы узнать, сколько стоил запрос — цена и остаток баланса приходят в заголовках каждого обычного (не потокового) ответа. Как это использовать.

4 мин · · Обновлено · API · экономия

Обычно расход на API узнаёшь постфактум: смотришь дашборд, видишь сумму за сутки, разбираешься, какой из десяти эндпоинтов её накрутил. Здесь можно иначе — цена конкретного запроса и остаток баланса приходят прямо в заголовках ответа, без похода в отдельный отчёт.

Два заголовка, которые решают половину задачи мониторинга

Каждый обычный (не потоковый) ответ несёт:

  • X-Zukko-Cost-Micros — стоимость именно этого запроса в микродолларах (1,000,000 = $1).
  • X-Fetch-Balance-Cents — остаток баланса после списания. Несмотря на название, значение тоже в микродолларах (1,000,000 = $1); точный баланс в центах — GET /v1/balance, поле balance_cents.

У потоковых ответов (stream: true) этих заголовков нет — для них расход смотри в кабинете, /v1/usage или /v1/balance.

bash
curl -si https://api.zukko.pro/v1/chat/completions \
  -H "Authorization: Bearer fetch_твой_ключ" \
  -H "Content-Type: application/json" \
  -d '{"model":"claude-sonnet-5","messages":[{"role":"user","content":"тест"}]}' \
  | grep -i "x-zukko-cost\|x-fetch-balance"

Ничего не нужно вычислять из токенов и прайс-листа отдельно — цена уже посчитана на стороне шлюза с учётом конкретной модели.

Логировать заголовки, а не ждать выгрузки

Простая обёртка на Python, которая пишет стоимость каждого вызова в свою систему метрик вместо похода в кабинет раз в день:

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))
    # несмотря на название, заголовок в микродолларах (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:  # меньше $5 — сигнал тревоги
        alert("Баланс zukko.pro ниже $5")
    return resp.json()

На 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")); // микродоллары

Разница с постфактум-отчётом: алерт срабатывает в момент запроса, который пробил порог, а не на следующий день при разборе логов.

Привязка стоимости к конкретному запросу, а не к среднему по больнице

Если сервис делает вызовы к разным моделям в рамках одного пользовательского действия — например, сначала классифицирует запрос лёгкой моделью, потом обрабатывает флагманом — заголовок с каждого отдельного HTTP-ответа даёт точную стоимость каждого шага. Складывая X-Zukko-Cost-Micros по всем вызовам одной пользовательской сессии, получаешь реальную unit-экономику фичи, а не грубую оценку "в среднем по всем моделям".

Кэш — это бесплатные повторы, и это тоже видно в заголовках

Если запрос идёт с заголовком X-Zukko-Cache: true (temperature: 0 тоже включает кэш, но только у моделей, которые его принимают, — модели Claude могут отклонить temperature, отличный от 1), одинаковые запросы одного и того же пользователя кэшируются (для чата — на срок до 7 суток). Повторный идентичный запрос возвращается мгновенно и не тарифицируется, а в ответе это отмечено заголовком X-Zukko-Cache: hit. Кэш срабатывает только при полном совпадении тела запроса, и такие попадания не пишутся в /v1/usage. Стоит логировать и его — доля кэш-хитов прямо показывает, сколько трафика можно было не оплачивать, если включить кэш там, где сейчас его нет:

bash
curl -si https://api.zukko.pro/v1/chat/completions \
  -H "Authorization: Bearer fetch_твой_ключ" \
  -H "X-Zukko-Cache: true" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-5.6-sol","messages":[{"role":"user","content":"тест"}]}' \
  | grep -i "x-zukko-cache"

/v1/usage — для сверки, не для реального времени

Заголовки дают моментальный срез, а история списаний с курсорной пагинацией нужна для сверки за период. Она общая на весь аккаунт (все ключи вместе, фильтра по ключу нет); в каждой записи — created_at, model, input_tokens, output_tokens, total_tokens и cost_cents (дробные центы), для следующей страницы — next_cursor:

bash
curl https://api.zukko.pro/v1/usage \
  -H "Authorization: Bearer fetch_твой_ключ"

Разумная схема: заголовки пишутся в метрики на каждый вызов и триггерят алерты сразу, а /v1/usage раз в день сверяет сумму заголовков с официальной историей — учитывай, что потоковые запросы в заголовках не видны и есть только в /v1/usage; если без них числа расходятся, значит где-то логирование заголовков само отваливается, и это стоит найти раньше, чем разойдётся счёт.

Баланс аккаунта отдельно от баланса конкретного ключа

X-Fetch-Balance-Cents показывает баланс всего аккаунта, а не лимит конкретного ключа — если на ключе настроен дневной или месячный лимит расхода, он тарифицируется отдельно и виден через 429 с кодом key_daily_limit_reached или key_monthly_limit_reached, когда исчерпан. Для мониторинга по ключу с лимитом стоит отдельно считать сумму X-Zukko-Cost-Micros за день на своей стороне и сравнивать с выставленным лимитом, чтобы видеть приближение к порогу заранее, а не только в момент отказа.

Быстрая проверка, что всё подключено

Общий баланс без разбора по запросам всегда можно дёрнуть напрямую:

bash
curl https://api.zukko.pro/v1/balance \
  -H "Authorization: Bearer fetch_твой_ключ"

Если цифра из /v1/balance расходится с тем, что накопилось в логах по заголовкам — значит, в обёртке вокруг HTTP-клиента заголовки не читаются или теряются при ретраях, и стоит проверить именно этот участок кода, а не сам биллинг.

Оценка стоимости до отправки, а не после

Заголовки хорошо показывают, сколько стоил уже отправленный запрос, но иногда нужно узнать цену заранее — например, перед батчем из тысячи промптов, который дешевле остановить до отправки, чем мониторить в процессе. Для этого есть отдельный бесплатный эндпоинт, который считает токены без выполнения запроса:

bash
curl https://api.zukko.pro/v1/messages/count_tokens \
  -H "Authorization: Bearer fetch_твой_ключ" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -d '{"model":"claude-opus-5-5","messages":[{"role":"user","content":"..."}]}'

Зная число токенов и текущую цену модели из /v1/models/info, можно прикинуть стоимость всего батча до того, как он ушёл, и сравнить с лимитом, выставленным на ключе — вместо того чтобы узнавать реальную сумму постфактум из заголовков или /v1/usage.

zukko

Платите в 25×
меньше

за Claude Code & ChatGPT

Один ключ fetch_* и base URL api.zukko.pro — в Cursor, Claude Code, Codex и любом SDK.