Чат

POST/v1/chat/completions

Основная текстовая ручка: диалог в форме OpenAI.

Запрос

modelstringbodyобязательно
логическое имя модели из GET /v1/models; префикс провайдера сворачивается
messagesarraybodyобязательно
диалог в форме OpenAI: массив {role, content}; уходит апстриму без изменений
streambooleanbody
true — ответ приходит SSE-кадрами; отказы шлюза случаются до первого байта
stream_optionsobjectbody
{"include_usage": true} — единственный способ получить стоимость в стриме
max_tokensintegerbody
потолок вывода (max_completion_tokens тоже); на нём считается худшая цена запроса

Ответы

Response

{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "model": "gpt-5.6-sol",
  "choices": [
    { "index": 0, "message": { "role": "assistant", "content": "Hello!" }, "finish_reason": "stop" }
  ],
  "usage": { "prompt_tokens": 9, "completion_tokens": 12, "cost_usd": "0.0000465" }
}

Stream

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"Hel"}}]}

data: {"id":"chatcmpl-…","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":9,"completion_tokens":12,"cost_usd":"0.0000465"}}

data: [DONE]

модерация остановила промпт до модели (type: content_policy_violation и категория)

ключа нет в заголовке или он не наш

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

model_not_found — модель выключена админом — из GET /v1/models она пропадает тоже

апстрим ответил лимитом; повтори с задержкой

апстрим недоступен (type: upstream_error)

таймаут ожидания апстрима: чтение 300 с, в стриме 60 с без байтов

Подробности

Нужен ключ в заголовке Authorization: Bearer или x-api-key.

Шлюз проксирует запрос в OpenAI-совместимый апстрим. Перечислены только поля, на которые он смотрит сам; все остальные поля тела (tools, tool_choice, response_format, temperature, seed, logprobs и прочие) передаются апстриму как есть, и мы их не переписываем и не документируем — их смысл задаёт OpenAI-схема.

Потолок вывода (max_tokens или max_completion_tokens) задаёт худшую цену запроса, на которой стоит проверка баланса: чем он больше, тем вероятнее 402 на тонком остатке — при отказе его можно просто уменьшить. Не назвал ни одного — потолок берётся из каталога модели, и запрос всё равно оценивается не в нуль.

Стоимость этого запроса приходит в самом ответе: заголовок x-teamtoken-cost-usd и поле usage.cost_usd в теле. Значение — строка с десятичной записью («0.0000465»), а не число: число после парсинга показывалось бы по правилам языка клиента (Python выдал бы 4.65e-05), строка доходит до кода ровно такой, как записана. Стоимость может и не прийти — тогда её нет ни в заголовке, ни в поле: в нестриминговом ответе так бывает, когда апстрим её не сообщил, в стриме — когда у модели нет тарифа в каталоге. В стриме заголовки уходят раньше, чем стоимость известна, поэтому она дописывается в финальный usage-кадр — попроси его через "stream_options": {"include_usage": true}. Без include_usage поток проходит через шлюз вообще без разбора кадров, и стоимости в нём не будет.

Байт-в-байт такой же запрос с тем же ключом в пределах короткого TTL (по умолчанию 60 с) не уезжает в модель повторно — шлюз отдаёт тело первого ответа и второй раз денег не берёт. Кэшируется только успешный ответ не больше 256 КБ; всё остальное уедет апстриму заново. У повтора из кэша нет заголовка x-teamtoken-cost-usd (списания не было), а cost_usd в теле — от первого, оплаченного ответа. Отсюда же следствие: уже оплаченный ответ отдаётся и при пустом кошельке — проверка баланса стоит ПОСЛЕ идемпотентности. Порядок проверок до отправки: отключённая модель → модерация → баланс. Ответ без содержимого (ни текста, ни reasoning, ни отказа, ни вызова инструмента) шлюз считает сбоем и, если есть куда переключиться, повторяет запрос прежде, чем отдать его; ответ, оборванный политикой или потолком вывода, пустым не считается, а на стрим правило не распространяется вовсе — 200 у клиента уже начался. Любая ошибка приходит одним конвертом (поле code — не у каждого статуса): { "error": { "message": "...", "type": "...", "code": "PROVIDER_CODE" } }.

Модерация, когда она включена, читает текст запроса и блокирует его только по реальному вердикту: недоступный или отвечающий ошибкой модератор запрос пропускает. Ответ всегда несёт то логическое имя модели, которое ты запросил. Если ответ не уложился в таймаут ожидания шлюза (по умолчанию чтение 300 с, в стриме 60 с без байтов), приходит 504; нестриминговую попытку шлюз при этом помечает, и если апстрим всё же досчитал и списал, реконсайлер возвращает сумму на баланс компенсирующим грантом. Из тел ошибок вычищены имена хостов апстрима, поэтому текст ошибки может отличаться от того, что прислал апстрим.

Своего маршрута у этого пути нет: все POST /v1/* принимает один обработчик шлюза, и список принимаемых путей у него закрытый — на любой другой /v1/* приходит 404.

Примеры кода
curl https://api.teamtoken.store/v1/chat/completions \
  -H "Authorization: Bearer sk-…" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "gpt-5.6-sol",
    "messages": [{ "role": "user", "content": "Hello" }]
  }'
from openai import OpenAI

client = OpenAI(api_key="sk-…", base_url="https://api.teamtoken.store/v1")

stream = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Hello"}],
    stream=True,
    stream_options={"include_usage": True},   # no include_usage, no cost in the stream
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
    if chunk.usage:                           # the final frame
        print("cost_usd:", chunk.usage.model_extra["cost_usd"])
Запрос
https://api.teamtoken.store/v1

Панель отправляет запрос с этого домена; в своём коде используйте адрес выше.

Ключ никуда не сохраняется: он живёт в этой вкладке до перезагрузки страницы.

логическое имя модели из GET /v1/models; префикс провайдера сворачивается

диалог в форме OpenAI: массив {role, content}; уходит апстриму без изменений

true — ответ приходит SSE-кадрами; отказы шлюза случаются до первого байта

{"include_usage": true} — единственный способ получить стоимость в стриме

потолок вывода (max_completion_tokens тоже); на нём считается худшая цена запроса

Запрос уйдёт по-настоящему и будет стоить денег по тарифу модели.

Ответ

Нажмите «Отправить запрос» выше — и здесь появится ответ.