Для ИИ-агентов: пошаговая инструкция по настройке — /docs/agents.md, индекс документации — /llms.txt.
Справочник API
Всё о запросах к шлюзу: протоколы, адреса, ключи и параметры. Ниже — стриминг, вызов инструментов, рассуждения, плагины и стоимость запроса в ответе.
Протоколы и адреса#
Шлюз принимает форматы OpenAI и Anthropic. Базовый адрес для SDK OpenAI — https://gate.joingonka.ai/v1, для SDK Anthropic — https://gate.joingonka.ai. Все протоколы работают на одном ключе и одном балансе: запрос в любом формате идёт одним и тем же путём.
| Метод и путь | Формат | Для чего | Особенности |
|---|---|---|---|
POST /v1/chat/completions | OpenAI Chat Completions | Чат, агенты, вызов инструментов | Основной путь: остальные форматы шлюз переводит в него. |
POST /v1/messages | Anthropic Messages | Claude Code и SDK Anthropic | Базовый адрес без /v1; модели claude-* заменяются рекомендуемой; поле max_tokens обязательно. |
POST /v1/responses | OpenAI Responses | Codex CLI и новые SDK OpenAI | Без состояния: историю присылайте целиком в каждом запросе. |
POST /v1/completions | OpenAI Completions (legacy) | Автодополнение и правка кода в редакторах | suffix передаётся модели подсказкой; в ответе logprobs: null. |
POST /v1/embeddings | OpenAI Embeddings | Векторные представления текста | Ответ 501: в сети нет эмбеддинговых моделей. |
Справочные адреса#
Отвечают без ключа. Таблица моделей с контекстом и статусом — в разделе Модели.
| Метод и путь | Описание |
|---|---|
GET /v1/models | Список моделей: контекст, цены, поддерживаемые параметры — поля в формате OpenRouter. |
GET /v1/models/{model} | Карточка одной модели; слэш в id — как есть или %2F. Скрытая или неизвестная модель — 404 model_not_found. |
GET /v1/capabilities | Возможности шлюза: параметры, протоколы, плагины, поля стоимости и лимиты (limits). |
GET /v1/plugins | Плагины: id и название. |
GET /v1/network-status | Состояние моделей сети: доступность, задержки, аптайм. |
GET /v1/nodes | Сводка пула нод: сколько всего, активных и в карантине. |
GET /v1/web-search/engines | Включён ли веб-поиск и в каком состоянии его движки. |
Anthropic Messages#
- Базовый адрес —
https://gate.joingonka.ai: SDK сам добавит/v1/messages. - Ключ — в заголовке
x-api-key(так шлёт SDK Anthropic) илиAuthorization: Bearer. - Модели
claude-*шлюз заменяет рекомендуемой (MiniMaxAI/MiniMax-M2.7); в полеmodelответа остаётся имя, которое прислал клиент. max_tokensобязателен, как в API Anthropic; больше потолка модели — срезается.- Стрим — события Anthropic; в паузах шлюз шлёт
event: ping, сбой приходит событиемevent: error. - Рассуждения модели в ответ не попадают: блоков
thinkingнет. - Встроенный инструмент
web_searchисполняет плагин веб-поиска шлюза — см. раздел Плагины. - Подсчёта токенов (
/v1/messages/count_tokens) нет — ответ404.
Claude Code проще настроить установщиком — подключение инструментов. Вручную — переменными окружения; ANTHROPIC_MODEL закрепляет модель сети.
export ANTHROPIC_BASE_URL=https://gate.joingonka.ai
export ANTHROPIC_AUTH_TOKEN=$JOINGONKA_API_KEY
export ANTHROPIC_MODEL=MiniMaxAI/MiniMax-M2.7
claudecurl https://gate.joingonka.ai/v1/messages \
-H "x-api-key: $JOINGONKA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "What is Gonka?"}]
}'OpenAI Responses#
- Шлюз не хранит ответы: присылайте всю историю в
input. Поляprevious_response_idиconversation— ошибка400с кодом. storeпринимается и ничего не меняет.- Инструменты:
functionиweb_search— его исполняет плагин веб-поиска. Другие встроенные инструменты шлюз пропускает, и запрос выполняется без них; требовать такой инструмент черезtool_choice— ошибка400. - Части
input_imageиinput_file— ошибка400: модели сети работают с текстом. - Адреса состояния (
GET /v1/responses/{id},DELETE /v1/responses/{id},GET /v1/responses/{id}/input_items,POST /v1/responses/{id}/cancel,POST /v1/responses/compact) отвечают404с кодом — ответов шлюз не хранит. - Codex CLI: задайте свой id провайдера в
model_provider(не openai) — тогда Codex сжимает историю сам, без/v1/responses/compact.
Legacy Completions#
prompt— строка или массив из одной строки; ответ — вchoices[].text. Несколько промптов или токены вместо текста — ошибка400.suffixпередаётся модели подсказкой в промпте: настоящего заполнения середины у сети нет.- В ответе
logprobs: null;best_ofигнорируется;echoработает.
Ключи и авторизация#
Ключ передаётся в заголовке Authorization: Bearer jg-… или x-api-key: jg-… — на всех адресах. Ключ создаётся после регистрации на странице gate.joingonka.ai/keys.
| Префикс | Ключ | Запросы к моделям |
|---|---|---|
jg- | Обычный ключ аккаунта | да |
gc- | Дочерний ключ: свои лимиты, расход — с баланса владельца | да |
gm- | Управляющий ключ: только управление дочерними | нет — 403 forbidden |
- Каждому ключу в кабинете можно задать лимит расходов на день, месяц и всего; превышение —
402 child_key_limit_exceeded. - Число запросов в минуту на ключ ограничено — значения в разделе Лимиты.
- Без ключа работает только демо-чат на сайте: запрос без ключа из своего кода получит
402сis_demo. - Ключами управляют только в кабинете:
/api/keysс API-ключом недоступен. Баланс и расход по ключу — API аккаунта.
Ключ — секрет: не храните его в репозитории и в коде фронтенда, передавайте через переменные окружения.
Примеры#
Один и тот же запрос в четырёх SDK. Модель — рекомендуемая (MiniMaxAI/MiniMax-M2.7), ключ — из переменной окружения JOINGONKA_API_KEY.
import os
from openai import OpenAI
client = OpenAI(
base_url="https://gate.joingonka.ai/v1",
api_key=os.environ["JOINGONKA_API_KEY"],
)
response = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2.7",
messages=[{"role": "user", "content": "What is Gonka?"}],
)
print(response.choices[0].message.content)import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://gate.joingonka.ai/v1",
apiKey: process.env.JOINGONKA_API_KEY,
});
const response = await client.chat.completions.create({
model: "MiniMaxAI/MiniMax-M2.7",
messages: [{ role: "user", content: "What is Gonka?" }],
});
console.log(response.choices[0].message.content);curl https://gate.joingonka.ai/v1/chat/completions \
-H "Authorization: Bearer $JOINGONKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is Gonka?"}]
}'import os
import anthropic
client = anthropic.Anthropic(
base_url="https://gate.joingonka.ai",
api_key=os.environ["JOINGONKA_API_KEY"],
)
message = client.messages.create(
model="MiniMaxAI/MiniMax-M2.7",
max_tokens=1024,
messages=[{"role": "user", "content": "What is Gonka?"}],
)
print(message.content[0].text)Потоковый ответ#
import os
from openai import OpenAI
client = OpenAI(base_url="https://gate.joingonka.ai/v1", api_key=os.environ["JOINGONKA_API_KEY"])
stream = client.chat.completions.create(
model="MiniMaxAI/MiniMax-M2.7",
messages=[{"role": "user", "content": "What is Gonka?"}],
stream=True,
)
for chunk in stream:
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://gate.joingonka.ai/v1", apiKey: process.env.JOINGONKA_API_KEY });
const stream = await client.chat.completions.create({
model: "MiniMaxAI/MiniMax-M2.7",
messages: [{ role: "user", content: "What is Gonka?" }],
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}curl -N https://gate.joingonka.ai/v1/chat/completions \
-H "Authorization: Bearer $JOINGONKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is Gonka?"}],
"stream": true
}'import os
import anthropic
client = anthropic.Anthropic(base_url="https://gate.joingonka.ai", api_key=os.environ["JOINGONKA_API_KEY"])
with client.messages.stream(
model="MiniMaxAI/MiniMax-M2.7",
max_tokens=1024,
messages=[{"role": "user", "content": "What is Gonka?"}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)Параметры запроса#
Параметры POST /v1/chat/completions, которые шлюз гарантирует сам, — список supported_parameters в ответе возможностей:
| Параметр | Описание |
|---|---|
temperature | Случайность ответа: чем выше, тем разнообразнее. |
top_p | Отбор токенов по суммарной вероятности. |
top_k | Отбор из k самых вероятных токенов. |
min_p | Отсечка маловероятных токенов относительно самого вероятного. |
frequency_penalty | Штраф за частые повторы. |
presence_penalty | Штраф за уже встречавшиеся токены. |
repetition_penalty | Множитель против повторов. |
stop | Строки, на которых генерация останавливается. |
seed | Зерно для воспроизводимости. |
max_tokens | Лимит токенов ответа; больше потолка модели — срезается до потолка. |
max_completion_tokens | Другое имя max_tokens: шлюз переносит значение в него. |
tools | Функции, которые модель может вызвать, в формате OpenAI. |
tool_choice | Вызывать ли функцию: на выбор модели, никогда, обязательно или конкретную. |
response_format | Структурированный ответ: json_object или json_schema. |
- Без
temperatureшлюз подставляет0.7. - Без
max_tokensшлюз подставляет умолчание модели: без стрима — короче, в стриме — потолок модели. Числа по моделям — в разделе Лимиты.
Передаются в сеть как есть#
reasoning_effort, reasoning, enable_thinking, chat_template_kwargs, thinking_token_budget, min_tokens, logit_bias, n, parallel_tool_calls, extra_body. Шлюз их не проверяет: значение вне списка сети — ошибка 400 с типом api_error.
Не передаются в сеть#
Остальные поля шлюз принимает и не передаёт в сеть — например, user, metadata, store, logprobs, top_logprobs, thinking, stream_options, web_search_options. usage в стриме приходит всегда.
Стриминг#
stream: true— ответ событиями SSE; последнее событие —data: [DONE].- Перед завершением приходит чанк с
usage— всегда, даже безstream_options. - В паузах шлюз каждые 15 с шлёт комментарий
: keep-alive— SSE-клиенты его пропускают. - Пока поток не открыт, отказ приходит обычным кодом ответа; после открытия — чанком
joingonka-error. - В
delta.tool_calls— один вызов на чанк: склеенные сетью вызовы шлюз разрезает.
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[{"index":0,"delta":{"content":"Hi"},"finish_reason":null}]}
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}
data: {"object":"chat.completion.chunk","model":"MiniMaxAI/MiniMax-M2.7","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":2,"total_tokens":14}}
data: [DONE]Служебные чанки шлюза#
Их можно узнать по полю id:
id | Когда и что внутри |
|---|---|
joingonka-error | Сбой после открытия потока: поле error, затем обрыв без [DONE]. |
joingonka-stream-stalled | Сеть молчала дольше допустимой паузы: поток закрывается с finish_reason: stop. |
joingonka-stream-unfinished | Сеть оборвала генерацию: finish_reason: length — продолжите следующим запросом. |
joingonka-citations | Источники веб-поиска в delta.annotations — перед завершением. |
joingonka-meta | Стоимость и тайминги — только с заголовком x-joingonka-meta: 1. |
Стрим в других протоколах#
- Anthropic Messages: события от
message_startдоmessage_stop, в паузахevent: ping, сбой —event: error. - OpenAI Responses: события
response.*, сбой —response.failed. - Legacy Completions: при сбое —
data: {"error": …}, затем[DONE].
Вызов инструментов#
- Формат OpenAI:
toolsиtool_choice. Старый форматfunctionsиfunction_callтоже принимается — ответ придёт в нём же. - В стриме — один вызов на чанк: клиенты, которые читают только первый элемент, не теряют вызовы.
- Историю, на которой сеть ответила бы ошибкой
400, шлюз чинит: рольdeveloperстановитсяsystem, пустые и повторяющиеся id вызовов получают уникальные,argumentsобъектом превращается в строку JSON, пропущенныйtypeдополняется, вызов без имени убирается вместе с результатом. - Вызов, который модель написала разметкой в тексте, шлюз переносит в
tool_calls; ложные вызовы в ответе на запрос без инструментов убирает. - Генерация оборвалась посреди аргументов — придёт
finish_reason: length, а неtool_calls: увеличьте лимит ответа.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is the weather in Paris?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Current weather for a city",
"parameters": {
"type": "object",
"properties": {"city": {"type": "string"}},
"required": ["city"]
}
}
}]
}Ограничения JSON-Schema#
Схемы инструментов и response_format сеть компилирует в грамматику; регулярные выражения — движком RE2. Шлюз приводит схему к форме, которую сеть примет:
$refраскрываются на месте, разделы$defsиdefinitionsудаляются; рекурсивная ссылка становится схемой без ограничений.patternс конструкциями, которых нет в RE2 (просмотр вперёд и назад, обратные ссылки, атомарные группы, сверхжадные квантификаторы), снимается; повторы больше 1000 сокращаются до 1000.anyOfиoneOfиз констант сворачиваются вenum; если несворачиваемых веток больше 16, объединение снимается.
Схема может стать мягче исходной — проверяйте аргументы вызова на своей стороне.
Структурированный ответ#
response_format: {"type": "json_object"} — ответ валидным JSON, {"type": "json_schema", "json_schema": {"name": …, "schema": …}} — по вашей схеме с ограничениями выше. Обрезанный JSON без стрима чинит плагин response-healing.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "Name three planets."}],
"response_format": {
"type": "json_schema",
"json_schema": {
"name": "planets",
"schema": {
"type": "object",
"properties": {"planets": {"type": "array", "items": {"type": "string"}}},
"required": ["planets"]
}
}
}
}Рассуждения#
- Рассуждения модели приходят отдельно от ответа:
message.reasoning_content, в стриме —delta.reasoning_content. Полеreasoningшлюз переименовывает в этот формат. - Рассуждения тратят
max_tokens: при маленьком лимите ответ обрывается (finish_reason: length) ещё до текста. - Если текста ответа нет, а рассуждения есть, шлюз переносит их в
content— кроме ответов с вызовом инструмента. reasoning_effortиreasoning.effortпередаются в сеть. Если у модели только два режима, шлюз приводит значение к ним:noneиminimal— кlow, более высокие — к рассуждению по умолчанию.- Если нода отвергла значение, шлюз понижает его (
maxиxhigh→high,minimal→low, иначе снимает поле) и повторяет запрос. - В
/v1/messagesрассуждения не передаются — блоковthinkingнет.
Плагины#
Плагины включаются полем plugins — массивом строк или объектов с опциями. Список — GET /v1/plugins.
| Плагин | Описание | Условия |
|---|---|---|
response-healing | Чинит обрезанный JSON в ответе модели. | Только без стрима и если ответ начинается с { или [. |
privacy-sanitization | Маскирует в текстовых сообщениях email, IPv4, номера карт, JWT, 64-символьные hex-ключи и ключи вида sk-…, gw_…, gm-…, Bearer …. | Режим — поле privacy_mode: redact (по умолчанию) или tokenize. |
file-parser | Извлекает текст из PDF. | Если текст сообщения целиком — PDF в base64: data:application/pdf;base64,… или без префикса. |
web | Веб-поиск: результаты подмешиваются в запрос, ответ получает ссылки на источники. | Вместе с privacy-sanitization — ошибка 400. |
Веб-поиск#
- Опции:
max_results— от 1 до 10, по умолчанию 5;engine— подсказка движка;search_prompt— свой текст перед результатами;enabled: false— выключить поиск. - Источники — в
message.annotations[].url_citation; в стриме — чанкомjoingonka-citationsперед завершением. mode: "agent"— модель сама решает, искать ли и что;max_searches— от 1 до 5, по умолчанию 3.- Оплата: в обычном режиме — только токены (результаты поиска входят во входные токены); в режиме агента — токены всех шагов плюс 1000 nGNK за каждый выполненный поиск (
x_joingonka.web_search_surcharge_ngonka). - В Anthropic Messages и OpenAI Responses встроенный инструмент
web_searchисполняет этот же плагин в режиме агента.
{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
"plugins": [{"id": "web", "max_results": 5}]
}{
"model": "MiniMaxAI/MiniMax-M2.7",
"messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
"plugins": [{"id": "web", "mode": "agent", "max_searches": 3}]
}Стоимость и служебные поля#
Ответ без стрима несёт стоимость запроса в usage:
| Поле | Описание |
|---|---|
usage.cost_gnk | Стоимость запроса в GNK |
usage.platform_fee_gnk | Из неё — наценка платформы, GNK |
usage.total_cost_gnk | Итог к списанию в GNK |
usage.total_cost_usd | Итог в долларах по текущему курсу GNK |
- В стриме
usageсодержит только токены; стоимость — в чанкеjoingonka-meta. - С заголовком
x-joingonka-meta: 1ответPOST /v1/chat/completionsполучает блокx_joingonka: стоимость (cost_ngonka), баланс после списания (balance_ngonka, только без стрима) и тайминги (ttft_ms). Другие протоколы этот блок не отдают. x-request-id— идентификатор запроса: приложите его к обращению в поддержку.Retry-Afterприходит с429: столько секунд подождать перед повтором.- Заголовки
X-TitleиHTTP-Referer(как у OpenRouter) помогают шлюзу узнать ваше приложение; их текст не сохраняется.
Ограничения#
- Изображения: части
image_urlзаменяются текстовой заглушкой — модель картинку не видит (vision: falseв возможностях). - Из браузера API доступен только с доменов JoinGonka (проверка
Origin): вызывайте его со своего сервера, ключ во фронтенд не кладите. - Эмбеддинги:
POST /v1/embeddingsотвечает501— в сети нет эмбеддинговых моделей. - Коды ошибок, лимиты и таймауты — в разделе Ошибки и лимиты.