Документация API go2llm

Баланс и расходы

Баланс, списания, квоты ключей и история запросов доступны в кабинете. Сумма конкретного списания также возвращается прямо в ответе модели: usage.cost_usd содержит стоимость запроса в USD. Поле добавляется и в обычные JSON-ответы, и в финальный usage-блок потоковой выдачи.

Что проверяется до запроса

  • ключ существует и активен;
  • срок действия ключа не истёк;
  • модель разрешена ключу;
  • квота ключа и доступный баланс покрывают максимальную оценку запроса.

Шлюз резервирует оценочную стоимость до обращения к поставщику, затем списывает фактическую стоимость и освобождает остаток резерва.

Для генерации изображений usage.images содержит количество результатов, а usage.cost_usd — итоговое списание. Повтор успешного image-запроса с тем же Idempotency-Key возвращает то же usage без повторного списания.

Если вы получили insufficient_balance, пополните баланс. Если получили quota exceeded, увеличьте квоту ключа или уменьшите max_tokens.

Как агенту прочитать свой бюджет через GET /v1/me

Автономному агенту бесполезно узнавать о пустом балансе из 402 на середине длинного прогона. GET /v1/me отдаёт остаток и квоту по тому же ключу, которым агент ходит в модель.

curl https://go2llm.tech/v1/me \
  -H "Authorization: Bearer YOUR_API_KEY"
{
  "object": "api_key",
  "key": {
    "name": "prod",
    "masked": "gk_sk_abcd…wxyz",
    "quota_usd": 50,
    "spent_usd": 12.34,
    "rpm_limit": 20,
    "allowed_models": ["*"],
    "expires_at": null
  },
  "balance": {
    "spendable_usd": 87.66,
    "reserved_usd": 0.12,
    "currency": "USD"
  },
  "limits": { "account_max_concurrency": 2 }
}

Маршрут принимает те же заголовки, что остальные: Authorization: Bearer YOUR_API_KEY или x-api-key: YOUR_API_KEY. Отдельный лимит — 60 RPM на ключ, ответ приходит с cache-control: no-store, так что кэшировать его на своей стороне надо осознанно.

ПолеЗначение
key.maskedмаскированный вид ключа, полный секрет не отдаётся
key.quota_usdквота ключа в USD; 0 означает «отдельной квоты нет»
key.spent_usdизрасходовано по этому ключу
key.rpm_limitлимит запросов в минуту на ключ, по умолчанию 20
key.allowed_modelsсписок разрешённых моделей; ["*"] — все опубликованные
key.expires_atсрок действия ключа строкой ISO-8601 ("2027-01-02T03:04:05.000Z") или null
balance.spendable_usdдоступно к трате прямо сейчас
balance.reserved_usdудержано под выполняющиеся запросы
limits.account_max_concurrencyпараллельных запросов на аккаунт, по умолчанию 2

expires_at — именно ISO-8601, а не unix-время: этот ответ читает сторонний агент, а не наш фронтенд. Лимит параллельности одинаков и для ключа с аккаунтом, и для ключа без него.

spendable_usd и reserved_usd — разные вещи

spendable_usd — то, что вы можете потратить прямо сейчас. Именно эту цифру сравнивайте с оценкой стоимости предстоящей работы.

reserved_usd — деньги, уже удержанные под запросы, которые прямо сейчас выполняются. Резерв ставится по максимальной оценке до вызова поставщика и освобождается после фактического списания. Поэтому нормально видеть ненулевой reserved_usd при параллельных запросах, и поэтому же баланс «вроде есть», а 402 всё равно приходит: под текущие запросы удержано больше, чем видно по остатку. Складывать spendable_usd и reserved_usd, чтобы получить «настоящий баланс», не нужно — тратить можно только первое.

Проверка перед длинным прогоном

import os
import sys

import httpx

BASE_URL = "https://go2llm.tech"
HEADERS = {"Authorization": f"Bearer {os.environ['GO2LLM_API_KEY']}"}

# Грубая оценка сверху: сколько запросов и по какой максимальной цене.
ESTIMATED_COST_USD = 4.0

me = httpx.get(f"{BASE_URL}/v1/me", headers=HEADERS, timeout=30).json()

balance = me["balance"]
if balance is None:
    # Ключ не привязан к аккаунту: расход ограничен только квотой ключа.
    remaining = me["key"]["quota_usd"] - me["key"]["spent_usd"]
else:
    remaining = balance["spendable_usd"]

if remaining < ESTIMATED_COST_USD:
    print(f"Останавливаюсь: доступно ${remaining:.2f}, нужно ${ESTIMATED_COST_USD:.2f}")
    sys.exit(1)

print(f"Бюджет есть: ${remaining:.2f}")

Квоту ключа стоит проверять вместе с балансом: ключ с квотой упрётся в неё раньше, чем кончится общий баланс аккаунта. Ключ с квотой 0 отдельного лимита не имеет — его расход ограничен только балансом. Ключ без привязанного аккаунта отдаёт "balance": null.

Чего в ответе нет

Маршрут читает ровно то, что нужно для планирования расходов, и ничего сверх:

Не отдаётсяПочему
email, имя и id аккаунтаутечка ключа не должна превращаться в опознание владельца
другие ключи аккаунтаиначе один утёкший ключ открывает все остальные
реферальные данные, платежи, промо-грантыдля работы не нужны, а ущерб от утечки расширяют
полный секрет ключатолько маскированный вид в key.masked

Разбивка баланса на cash, промо и замороженные гранты тоже не публикуется: это внутренняя механика, она будет меняться, и строить на ней логику агента не стоит. Наружу идут только spendable_usd и reserved_usd.

Эскалации доступа здесь нет: держатель ключа и так может тратить баланс, а читать остаток — строго меньше того, что он уже умеет.

Разбор кодов 402 и 429 — на странице Ошибки API, полный список маршрутов — в Маршрутах API, тарифы — на странице цен и биллинга. Ключ и первый запрос — на go2llm.tech.