> Для ШІ-агентів: покрокова інструкція з налаштування — [`/docs/agents.md`](https://gate.joingonka.ai/docs/agents.md), індекс документації — [`/llms.txt`](https://gate.joingonka.ai/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`: у мережі немає ембеддингових моделей. |

### Довідкові адреси

Відповідають без ключа. Таблиця моделей із контекстом і статусом — у розділі [Моделі](https://gate.joingonka.ai/uk/docs/models).

| Метод і шлях | Опис |
| --- | --- |
| `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` виконує плагін веб-пошуку шлюзу — див. розділ [Плагіни](https://gate.joingonka.ai/uk/docs/api#plugins).
- Підрахунку токенів (`/v1/messages/count_tokens`) немає — відповідь `404`.

Claude Code простіше налаштувати інсталятором — [підключення інструментів](https://gate.joingonka.ai/uk/docs#connect). Вручну — змінними середовища; `ANTHROPIC_MODEL` закріплює модель мережі.

#### Claude Code

```bash
export ANTHROPIC_BASE_URL=https://gate.joingonka.ai
export ANTHROPIC_AUTH_TOKEN=$JOINGONKA_API_KEY
export ANTHROPIC_MODEL=MiniMaxAI/MiniMax-M2.7
claude
```

#### cURL

```bash
curl 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](https://gate.joingonka.ai/keys).

| Префікс | Ключ | Запити до моделей |
| --- | --- | --- |
| `jg-` | Звичайний ключ акаунта | так |
| `gc-` | Дочірній ключ: свої ліміти, витрати — з балансу власника | так |
| `gm-` | Керівний ключ: лише керування дочірніми | ні — `403 forbidden` |

- Кожному ключу в кабінеті можна задати ліміт витрат на день, місяць і загалом; перевищення — `402 child_key_limit_exceeded`.
- Кількість запитів за хвилину на ключ обмежена — значення в розділі [Ліміти](https://gate.joingonka.ai/uk/docs/errors#limits).
- Без ключа працює лише демо-чат на сайті: запит без ключа зі свого коду отримає `402` з `is_demo`.
- Ключами керують лише в кабінеті: `/api/keys` з API-ключем недоступний. Баланс і витрати за ключем — [API акаунта](https://gate.joingonka.ai/uk/docs/billing#account-api).

> Ключ — це секрет: не зберігайте його в репозиторії та в коді фронтенду, передавайте через змінні середовища.

## Приклади

Один і той самий запит у чотирьох SDK. Модель — рекомендована (`MiniMaxAI/MiniMax-M2.7`), ключ — зі змінної середовища `JOINGONKA_API_KEY`.

### Python

```python
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)
```

### TypeScript

```typescript
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

```bash
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?"}]
  }'
```

### Anthropic SDK

```python
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)
```

### Потокова відповідь

#### Python

```python
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)
```

#### TypeScript

```typescript
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

```bash
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
  }'
```

#### Anthropic SDK

```python
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` шлюз підставляє усталене значення моделі: без стріму — коротше, у стрімі — стеля моделі. Числа за моделями — у розділі [Ліміти](https://gate.joingonka.ai/uk/docs/errors#limits).

### Передаються в мережу як є

`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` — один виклик на чанк: склеєні мережею виклики шлюз розрізає.

```text
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`: збільште ліміт відповіді.

```json
{
  "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`.

```json
{
  "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` виконує той самий плагін у режимі агента.

#### plugins: web

```json
{
  "model": "MiniMaxAI/MiniMax-M2.7",
  "messages": [{"role": "user", "content": "What is new in the Gonka network?"}],
  "plugins": [{"id": "web", "max_results": 5}]
}
```

#### mode: agent

```json
{
  "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` — у мережі немає ембедингових моделей.
- Коди помилок, ліміти й таймаути — у розділі [Помилки та ліміти](https://gate.joingonka.ai/uk/docs/errors).
