Аутентификация

Ключ из кабинета, два принимаемых заголовка и что на самом деле означают 401 и 402.

Аутентификация одна на весь шлюз: ключ в заголовке, больше ничего. Ни подписей запроса, ни OAuth, ни отдельных секретов на модальность.

Где берётся ключ

Ключ создаётся в кабинете, на странице «Ключи» (app.teamtoken.store/keys): показывается целиком при создании, посмотреть можно там же позже. Начинается с sk-.

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

# Держи ключ в окружении, а не в коде / keep the key in your environment, not in code:
export TEAMTOKEN_KEY="sk-…"

Два заголовка, и оба настоящие

Ключ принимается в двух видах: Authorization: Bearer sk-… (предпочтительный, его понимают все SDK) и x-api-key: sk-… (для клиентов, которые не умеют Authorization). Ручки от выбора не различаются; если присланы оба, побеждает Authorization.

У POST-запросов обязателен Content-Type: application/json; остальные правила — рядом с быстрым стартом на /docs.

curl https://api.teamtoken.store/v1/models \
  -H "Authorization: Bearer $TEAMTOKEN_KEY"
curl https://api.teamtoken.store/v1/models \
  -H "x-api-key: $TEAMTOKEN_KEY"

Что открыто без ключа

Каталог и статус публичны: /cabinet/api/public/models, /media-models и /model-status отвечают анонимно — их можно звать хоть из скрипта сборки, не держа рядом ключ.

Ключ тратит настоящие деньги

Ключ — это доступ к балансу, поэтому во фронтенде и в публичном репозитории его быть не должно: код в браузере отдаёт ключ вместе с собой, а ключ в истории коммитов действует и после удаления строки.

Утёк — удали его в кабинете (app.teamtoken.store/keys) и выдай новый. Отдаёшь наружу — задай лимит расхода до передачи, а не после инцидента.

401 — ключа нет или он не наш

На ручках, которым ключ нужен, 401 означает: ключа нет в заголовке или он не наш. Проверь Authorization: Bearer или x-api-key.

Сюда же попадает сломанный заголовок: «Bearer» без пробела, «Token» вместо «Bearer», ключ в query — для шлюза это неотличимо от запроса без ключа.

402 — не хватает на худшую цену этого запроса

Ответ 402 значит: остатка не хватает на худшую цену этого запроса. Худшая, а не средняя: оценка входных токенов плюс потолок вывода, каждое по своей цене и с запасом; потолок берётся из запроса (max_tokens), иначе из каталога модели.

Отсюда следствие: на тонком остатке запрос с потолком в тысячи токенов получит 402, а с потолком в двести — пройдёт. В теле отказа названы остаток и возможная цена запроса.

402 — про деньги, а не про ключ: ключ рабочий, кончился остаток, пополнение снимает отказ. У медиа тот же 402 — по цене картинки или секунды видео. Исключение одно: байт-в-байт повтор в пределах короткого TTL отдаётся из идемпотентного кэша даже при пустом кошельке — но кэш есть у чата, Responses и эмбеддингов, а у формы Anthropic (/v1/messages) его нет, и повтор там платный.

Ключ, баланс и стоимость каждого запроса

Деньги привязаны к аккаунту, а не к ключу: сколько бы ключей ни было, они тратят один остаток. Остаток — GET /v1/balance тем же ключом, с уже учтёнными резервами под идущие генерации; стоимость ответа — /docs/getting-started, шаг 4.