Как считается цена текстового запроса от начала до конца

От отправки запроса до списания денег проходит несколько шагов, и почти на каждом можно либо сэкономить, либо потерять контроль над расходом.

5 мин · · Обновлено · оплата

Когда вы вызываете /v1/messages или /v1/chat/completions, до того как в ответе появится хоть один токен, шлюз проходит несколько внутренних шагов. Разберём их по порядку — это объясняет, почему запрос иногда падает с 402 мгновенно и почему X-Zukko-Cost-Micros в ответе не всегда совпадает с прикидкой на глаз.

Шаг 1: подсчёт входных токенов

Всё, что уходит в поле messages — системный промпт, история переписки, содержимое вложенных файлов, описания инструментов для агента — токенизируется под конкретную модель. У каждой модели свой токенайзер, поэтому один и тот же русский текст даёт разное число токенов для claude-opus-5-5 и для gpt-5.6-sol. Если нужно узнать число токенов без реального запроса и без списания денег, есть отдельный бесплатный метод:

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":"привет"}]}'

Это удобно, когда контекст собирается программно из кусков файлов и истории, и хочется прикинуть объём до отправки, а не после списания.

Шаг 2: проверка баланса — раньше похода к модели

Дальше шлюз смотрит на баланс аккаунта и на лимиты конкретного ключа, если они заданы в кабинете на странице ключа. Это происходит до того, как запрос уйдёт к провайдеру модели. Если денег нет, ответ придёт мгновенно:

bash
{"error":{"message":"Недостаточно средств на балансе","code":"insufficient_balance"}}

Важная деталь: раз проверка стоит перед вызовом модели, неудачный запрос с 402 не тратит ни цента. На этом же шаге проверяются лимиты ключа — дневной и месячный расход в долларах и список разрешённых моделей. Если конкретная модель запрещена политикой ключа, вернётся 403 model_not_allowed_for_key, а не попытка списания с последующим отказом.

Шаг 3: запрос уходит в модель — но сначала кэш

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

Шаг 4: выходные токены и итоговая цена

Когда модель ответила, шлюз считает выходные токены и складывает стоимость: входные и выходные токены умножаются на ставки модели. У включённых сейчас моделей Zukko вход и выход стоят одинаково — например, claude-sonnet-5 и gpt-5.6-sol по $0.30 за миллион, glm-5.3-flash по $0.04 (цены — GET /v1/models/info). У изображений расчёт устроен иначе: там цена фиксирована за штуку сгенерированной картинки, а не за токены — это отдельный биллинг у nano-banana-2-* и openai-gpt-image-* (генерация изображений через Zukko сейчас временно недоступна). Итоговая сумма списывается с баланса аккаунта сразу после получения ответа от модели, без отдельного шага подтверждения.

Шаг 5: что приходит в ответе

В заголовках обычного (нестримингового) HTTP-ответа есть два поля, которые стоит логировать на своей стороне, а не пересчитывать вручную:

  • X-Zukko-Cost-Micros — стоимость именно этого запроса в микродолларах (1 000 000 микродолларов = $1);
  • X-Fetch-Balance-Cents — остаток на балансе после списания; несмотря на название, тоже в микродолларах (1 000 000 = $1), так что значение 187654 — это около $0.19, а не $1876.54.

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

Если вызываете API из скрипта или агента, дешевле читать эти заголовки по ходу дела, чем регулярно дёргать отдельный эндпоинт баланса:

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

Полную историю списаний с курсорной пагинацией (next_cursor) отдаёт /v1/usage — удобно, когда нужно свести расход за период, а не смотреть только на текущий остаток. В каждой записи — created_at, model, input_tokens, output_tokens, total_tokens и cost_cents (в дробных центах). История общая на весь аккаунт: все ключи вместе, фильтра по ключу нет.

Идемпотентность защищает от двойного списания

Если соединение оборвалось и непонятно, дошёл ли запрос до сервера, не нужно гадать и повторять вслепую. Передайте заголовок Idempotency-Key с уникальным значением на каждый логический запрос (и тем же самым — при его повторах; заново ключ при ретрае не генерируют): повтор с тем же ключом в течение 24 часов вернёт тот же сохранённый ответ и не спишет деньги повторно. Если же с тем же Idempotency-Key придёт другое тело запроса, шлюз ответит 422 idempotency_conflict — это защита от случайной путаницы, а не лишнее ограничение.

Пример полного цикла

bash
curl -i https://api.zukko.pro/v1/messages \
  -H "Authorization: Bearer fetch_ваш_ключ" \
  -H "Content-Type: application/json" \
  -H "anthropic-version: 2023-06-01" \
  -H "Idempotency-Key: session-42-step-1" \
  -d '{"model":"claude-sonnet-5","max_tokens":200,"messages":[{"role":"user","content":"Объясни разницу между TCP и UDP в двух предложениях"}]}'

Флаг -i покажет заголовки ответа вместе с телом — там и будет цена конкретного запроса и остаток баланса. Если нужен каталог моделей с лимитами и текущими ценами без ключа вообще, это отдельный публичный эндпоинт /v1/models/info, а базовый список моделей без деталей — GET /v1/models.

Вся цепочка — подсчёт входных токенов, проверка баланса и лимитов ключа, проверка кэша, вызов модели, подсчёт выходных токенов, списание, запись в заголовки и в историю /v1/usage — занимает миллисекунды и работает одинаково, независимо от того, идёте вы через Anthropic-совместимый путь /v1/messages или через OpenAI-совместимый /v1/chat/completions и /v1/responses. Для картиночных моделей путь другой — /v1/images/generations (сейчас генерация изображений временно недоступна) — но проверка баланса и лимитов ключа перед запуском генерации происходит по той же логике.

zukko

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

за Claude Code & ChatGPT

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