> Dla agentów AI: instrukcja konfiguracji krok po kroku — [`/docs/agents.md`](https://gate.joingonka.ai/docs/agents.md), indeks dokumentacji — [`/llms.txt`](https://gate.joingonka.ai/llms.txt).

# Dokumentacja API

Wszystko o żądaniach do bramy: protokoły, adresy, klucze i parametry. Poniżej — streaming, wywoływanie narzędzi, rozumowanie, wtyczki i koszt żądania w odpowiedzi.

## Protokoły i adresy

Brama przyjmuje formaty OpenAI i Anthropic. Adres bazowy dla SDK OpenAI — `https://gate.joingonka.ai/v1`, dla SDK Anthropic — `https://gate.joingonka.ai`. Wszystkie protokoły działają na jednym kluczu i jednym saldzie: zapytanie w dowolnym formacie przechodzi tą samą ścieżką.

| Metoda i ścieżka | Format | Do czego | Szczegóły |
| --- | --- | --- | --- |
| `POST /v1/chat/completions` | OpenAI Chat Completions | Czat, agenci, wywoływanie narzędzi | Główna ścieżka: pozostałe formaty brama tłumaczy na ten format. |
| `POST /v1/messages` | Anthropic Messages | Claude Code i SDK Anthropic | Adres bazowy bez `/v1`; modele `claude-*` zastępowane zalecanym; pole `max_tokens` obowiązkowe. |
| `POST /v1/responses` | OpenAI Responses | Codex CLI i nowe SDK OpenAI | Bezstanowo: historię przesyłaj w całości w każdym zapytaniu. |
| `POST /v1/completions` | OpenAI Completions (legacy) | Autouzupełnianie i edycja kodu w edytorach | `suffix` przekazywany modelowi jako podpowiedź; w odpowiedzi `logprobs: null`. |
| `POST /v1/embeddings` | OpenAI Embeddings | Reprezentacje wektorowe tekstu | Odpowiedź `501`: w sieci nie ma modeli embeddingowych. |

### Adresy informacyjne

Odpowiadają bez klucza. Tabela modeli z kontekstem i statusem — w sekcji [Modele](https://gate.joingonka.ai/pl/docs/models).

| Metoda i ścieżka | Opis |
| --- | --- |
| `GET /v1/models` | Lista modeli: kontekst, ceny, obsługiwane parametry — pola w formacie OpenRouter. |
| `GET /v1/models/{model}` | Karta jednego modelu; ukośnik w id — jak jest lub `%2F`. Model ukryty lub nieznany — `404 model_not_found`. |
| `GET /v1/capabilities` | Możliwości bramy: parametry, protokoły, pluginy, pola kosztów i limity (`limits`). |
| `GET /v1/plugins` | Pluginy: id i nazwa. |
| `GET /v1/network-status` | Stan modeli sieci: dostępność, opóźnienia, uptime. |
| `GET /v1/nodes` | Podsumowanie puli węzłów: ile łącznie, aktywnych i w kwarantannie. |
| `GET /v1/web-search/engines` | Czy wyszukiwanie w sieci jest włączone i w jakim stanie są jego silniki. |

### Anthropic Messages

- Adres bazowy — `https://gate.joingonka.ai`: SDK sam doda `/v1/messages`.
- Klucz — w nagłówku `x-api-key` (tak wysyła SDK Anthropic) lub `Authorization: Bearer`.
- Modele `claude-*` brama zastępuje zalecanym (`MiniMaxAI/MiniMax-M2.7`); w polu `model` odpowiedzi pozostaje nazwa przesłana przez klienta.
- `max_tokens` jest obowiązkowy, jak w API Anthropic; więcej niż limit modelu — zostaje obcięte.
- Stream — zdarzenia Anthropic; w przerwach brama wysyła `event: ping`, błąd przychodzi zdarzeniem `event: error`.
- Rozumowanie modelu nie trafia do odpowiedzi: bloków `thinking` nie ma.
- Wbudowane narzędzie `web_search` wykonuje plugin wyszukiwania w sieci bramy — patrz sekcja [Pluginy](https://gate.joingonka.ai/pl/docs/api#plugins).
- Zliczania tokenów (`/v1/messages/count_tokens`) nie ma — odpowiedź `404`.

Claude Code najłatwiej skonfigurować instalatorem — [podłączanie narzędzi](https://gate.joingonka.ai/pl/docs#connect). Ręcznie — zmiennymi środowiskowymi; `ANTHROPIC_MODEL` przypisuje model sieci.

#### 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

- Brama nie przechowuje odpowiedzi: przesyłaj całą historię w `input`. Pola `previous_response_id` i `conversation` — błąd `400` z kodem.
- `store` jest przyjmowany i niczego nie zmienia.
- Narzędzia: `function` i `web_search` — to drugie wykonuje plugin wyszukiwania w sieci. Inne wbudowane narzędzia brama pomija i zapytanie wykonuje się bez nich; żądanie takiego narzędzia przez `tool_choice` — błąd `400`.
- Części `input_image` i `input_file` — błąd `400`: modele sieci pracują z tekstem.
- Adresy stanu (`GET /v1/responses/{id}`, `DELETE /v1/responses/{id}`, `GET /v1/responses/{id}/input_items`, `POST /v1/responses/{id}/cancel`, `POST /v1/responses/compact`) odpowiadają `404` z kodem — brama nie przechowuje odpowiedzi.
- Codex CLI: ustaw własny id dostawcy w `model_provider` (nie openai) — wtedy Codex sam kompresuje historię, bez `/v1/responses/compact`.

### Legacy Completions

- `prompt` — ciąg znaków lub tablica z jednym ciągiem; odpowiedź — w `choices[].text`. Wiele promptów lub tokeny zamiast tekstu — błąd `400`.
- `suffix` przekazywany modelowi jako podpowiedź w prompcie: sieć nie ma prawdziwego wypełniania środka.
- W odpowiedzi `logprobs: null`; `best_of` jest ignorowany; `echo` działa.

## Klucze i autoryzacja

Klucz przekazywany jest w nagłówku `Authorization: Bearer jg-…` lub `x-api-key: jg-…` — na wszystkich adresach. Klucz tworzy się po rejestracji na stronie [gate.joingonka.ai/keys](https://gate.joingonka.ai/keys).

| Prefiks | Klucz | Zapytania do modeli |
| --- | --- | --- |
| `jg-` | Zwykły klucz konta | tak |
| `gc-` | Klucz podrzędny: własne limity, wydatki — z salda właściciela | tak |
| `gm-` | Klucz zarządzający: tylko zarządzanie kluczami podrzędnymi | nie — `403 forbidden` |

- Każdemu kluczowi w panelu można ustawić limit wydatków na dzień, miesiąc i łącznie; przekroczenie — `402 child_key_limit_exceeded`.
- Liczba zapytań na minutę na klucz jest ograniczona — wartości w sekcji [Limity](https://gate.joingonka.ai/pl/docs/errors#limits).
- Bez klucza działa tylko czat demonstracyjny na stronie: zapytanie bez klucza z własnego kodu otrzyma `402` z `is_demo`.
- Kluczami zarządza się tylko w panelu: `/api/keys` z kluczem API jest niedostępny. Saldo i wydatki według klucza — [Konto API](https://gate.joingonka.ai/pl/docs/billing#account-api).

> Klucz to sekret: nie przechowuj go w repozytorium ani w kodzie frontendu — przekazuj przez zmienne środowiskowe.

## Przykłady

To samo zapytanie w czterech SDK. Model — zalecany (`MiniMaxAI/MiniMax-M2.7`), klucz — ze zmiennej środowiskowej `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)
```

### Odpowiedź strumieniowa

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

## Parametry zapytania

Parametry `POST /v1/chat/completions`, które bramka gwarantuje sama — lista `supported_parameters` w odpowiedzi capabilities:

| Parametr | Opis |
| --- | --- |
| `temperature` | Losowość odpowiedzi: im wyższa, tym bardziej zróżnicowana. |
| `top_p` | Wybór tokenów według skumulowanego prawdopodobieństwa. |
| `top_k` | Wybór spośród k najbardziej prawdopodobnych tokenów. |
| `min_p` | Odcięcie mało prawdopodobnych tokenów względem najbardziej prawdopodobnego. |
| `frequency_penalty` | Kara za częste powtórzenia. |
| `presence_penalty` | Kara za tokeny, które już się pojawiły. |
| `repetition_penalty` | Mnożnik przeciw powtórzeniom. |
| `stop` | Ciągi, na których generacja się zatrzymuje. |
| `seed` | Ziarno dla powtarzalności. |
| `max_tokens` | Limit tokenów odpowiedzi; powyżej pułapu modelu — przycinane do pułapu. |
| `max_completion_tokens` | Inna nazwa `max_tokens`: bramka przenosi do niej wartość. |
| `tools` | Funkcje, które model może wywołać, w formacie OpenAI. |
| `tool_choice` | Czy wywołać funkcję: do wyboru modelu, nigdy, obowiązkowo lub konkretną. |
| `response_format` | Odpowiedź strukturalna: `json_object` lub `json_schema`. |

- Bez `temperature` bramka podstawia `0.7`.
- Bez `max_tokens` bramka podstawia domyślną wartość modelu: bez streamingu — krótszą, w streamingu — pułap modelu. Liczby dla poszczególnych modeli — w sekcji [Limity](https://gate.joingonka.ai/pl/docs/errors#limits).

### Przekazywane do sieci bez zmian

`reasoning_effort`, `reasoning`, `enable_thinking`, `chat_template_kwargs`, `thinking_token_budget`, `min_tokens`, `logit_bias`, `n`, `parallel_tool_calls`, `extra_body`. Bramka ich nie sprawdza: wartość spoza listy sieci — błąd `400` z typem `api_error`.

### Nieprzekazywane do sieci

Pozostałe pola bramka przyjmuje i nie przekazuje do sieci — na przykład `user`, `metadata`, `store`, `logprobs`, `top_logprobs`, `thinking`, `stream_options`, `web_search_options`. `usage` w streamingu przychodzi zawsze.

## Streaming

- `stream: true` — odpowiedź zdarzeniami SSE; ostatnie zdarzenie — `data: [DONE]`.
- Przed zakończeniem przychodzi chunk z `usage` — zawsze, nawet bez `stream_options`.
- W pauzach bramka co 15 s wysyła komentarz `: keep-alive` — klienci SSE go pomijają.
- Dopóki strumień nie jest otwarty, odmowa przychodzi zwykłym kodem odpowiedzi; po otwarciu — chunkiem `joingonka-error`.
- W `delta.tool_calls` — jedno wywołanie na chunk: wywołania sklejone przez sieć bramka rozdziela.

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

### Chunki serwisowe bramki

Można je rozpoznać po polu `id`:

| `id` | Kiedy i co w środku |
| --- | --- |
| `joingonka-error` | Awaria po otwarciu strumienia: pole `error`, potem przerwanie bez `[DONE]`. |
| `joingonka-stream-stalled` | Sieć milczała dłużej niż dopuszczalna pauza: strumień zamyka się z `finish_reason: stop`. |
| `joingonka-stream-unfinished` | Sieć przerwała generację: `finish_reason: length` — kontynuuj kolejnym zapytaniem. |
| `joingonka-citations` | Źródła wyszukiwania w sieci w `delta.annotations` — przed zakończeniem. |
| `joingonka-meta` | Koszt i czasy — tylko z nagłówkiem `x-joingonka-meta: 1`. |

### Streaming w innych protokołach

- Anthropic Messages: zdarzenia od `message_start` do `message_stop`, w pauzach `event: ping`, awaria — `event: error`.
- OpenAI Responses: zdarzenia `response.*`, awaria — `response.failed`.
- Legacy Completions: przy awarii — `data: {"error": …}`, potem `[DONE]`.

## Wywoływanie narzędzi

- Format OpenAI: `tools` i `tool_choice`. Stary format `functions` i `function_call` też jest akceptowany — odpowiedź przyjdzie w nim samym.
- W streamingu — jedno wywołanie na chunk: klienci, którzy czytają tylko pierwszy element, nie tracą wywołań.
- Historię, na której sieć zwróciłaby błąd `400`, bramka naprawia: rola `developer` staje się `system`, puste i powtarzające się id wywołań otrzymują unikalne, `arguments` jako obiekt zmienia się w ciąg JSON, brakujący `type` jest uzupełniany, wywołanie bez nazwy jest usuwane razem z wynikiem.
- Wywołanie, które model napisał znacznikami w tekście, bramka przenosi do `tool_calls`; fałszywe wywołania w odpowiedzi na zapytanie bez narzędzi usuwa.
- Generacja urwała się w środku argumentów — przyjdzie `finish_reason: length`, a nie `tool_calls`: zwiększ limit odpowiedzi.

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

### Ograniczenia JSON-Schema

Schematy narzędzi i `response_format` sieć kompiluje do gramatyki; wyrażenia regularne — silnikiem RE2. Bramka doprowadza schemat do formy, którą sieć przyjmie:

- `$ref` są rozwijane na miejscu, sekcje `$defs` i `definitions` są usuwane; odwołanie rekursywne staje się schematem bez ograniczeń.
- `pattern` z konstrukcjami, których nie ma w RE2 (lookahead i lookbehind, backreference, grupy atomowe, kwantyfikatory possessywne), jest usuwany; powtórzenia większe niż 1000 są skracane do 1000.
- `anyOf` i `oneOf` ze stałych są zwijane do `enum`; jeśli nierozwijalnych gałęzi jest więcej niż 16, unia jest usuwana.

> Schemat może stać się łagodniejszy niż pierwotny — sprawdzaj argumenty wywołania po swojej stronie.

## Odpowiedź strukturalna

`response_format`: `{"type": "json_object"}` — odpowiedź poprawnym JSON-em, `{"type": "json_schema", "json_schema": {"name": …, "schema": …}}` — według twojego schematu z ograniczeniami powyżej. Obcięty JSON bez streamingu naprawia plugin `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"]
      }
    }
  }
}
```

## Rozumowanie

- Rozumowanie modelu przychodzi oddzielnie od odpowiedzi: `message.reasoning_content`, w streamingu — `delta.reasoning_content`. Pole `reasoning` bramka przemianowuje na ten format.
- Rozumowanie zużywa `max_tokens`: przy małym limicie odpowiedź urywa się (`finish_reason: length`) jeszcze przed tekstem.
- Jeśli tekstu odpowiedzi nie ma, a rozumowanie jest, bramka przenosi je do `content` — poza odpowiedziami z wywołaniem narzędzia.
- `reasoning_effort` i `reasoning.effort` są przekazywane do sieci. Jeśli model ma tylko dwa tryby, bramka doprowadza wartość do nich: `none` i `minimal` — do `low`, wyższe — do rozumowania domyślnego.
- Jeśli noda odrzuciła wartość, bramka obniża ją (`max` i `xhigh` → `high`, `minimal` → `low`, w przeciwnym razie usuwa pole) i powtarza zapytanie.
- W `/v1/messages` rozumowanie nie jest przekazywane — bloków `thinking` nie ma.

## Pluginy

Pluginy włącza się polem `plugins` — tablicą ciągów lub obiektów z opcjami. Lista — `GET /v1/plugins`.

| Plugin | Opis | Warunki |
| --- | --- | --- |
| `response-healing` | Naprawia obcięty JSON w odpowiedzi modelu. | Tylko bez streamingu i jeśli odpowiedź zaczyna się od `{` lub `[`. |
| `privacy-sanitization` | Maskuje w wiadomościach tekstowych email, IPv4, numery kart, JWT, 64-znakowe klucze hex i klucze postaci `sk-…`, `gw_…`, `gm-…`, `Bearer …`. | Tryb — pole `privacy_mode`: `redact` (domyślnie) lub `tokenize`. |
| `file-parser` | Wyciąga tekst z PDF. | Jeśli tekst wiadomości w całości to PDF w base64: `data:application/pdf;base64,…` lub bez prefiksu. |
| `web` | Wyszukiwanie w sieci: wyniki są domieszane do zapytania, odpowiedź otrzymuje linki do źródeł. | Razem z `privacy-sanitization` — błąd `400`. |

### Wyszukiwanie w sieci

- Opcje: `max_results` — od 1 do 10, domyślnie 5; `engine` — podpowiedź silnika; `search_prompt` — własny tekst przed wynikami; `enabled: false` — wyłączyć wyszukiwanie.
- Źródła — w `message.annotations[].url_citation`; w streamingu — chunkiem `joingonka-citations` przed zakończeniem.
- `mode: "agent"` — model sam decyduje, czy szukać i czego; `max_searches` — od 1 do 5, domyślnie 3.
- Rozliczenia: w trybie zwykłym — tylko tokeny (wyniki wyszukiwania wliczają się do tokenów wejściowych); w trybie agenta — tokeny wszystkich kroków plus 1000 nGNK za każde wykonane wyszukiwanie (`x_joingonka.web_search_surcharge_ngonka`).
- W Anthropic Messages i OpenAI Responses wbudowane narzędzie `web_search` uruchamia ten sam plugin w trybie agenta.

#### 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}]
}
```

## Koszt i pola techniczne

Odpowiedź bez streamingu zawiera koszt zapytania w `usage`:

| Pole | Opis |
| --- | --- |
| `usage.cost_gnk` | Koszt zapytania w GNK |
| `usage.platform_fee_gnk` | Z tego — marża platformy, GNK |
| `usage.total_cost_gnk` | Kwota do obciążenia w GNK |
| `usage.total_cost_usd` | Kwota w dolarach według aktualnego kursu GNK |

- W streamingu `usage` zawiera tylko tokeny; koszt — w chunku `joingonka-meta`.
- Z nagłówkiem `x-joingonka-meta: 1` odpowiedź `POST /v1/chat/completions` otrzymuje blok `x_joingonka`: koszt (`cost_ngonka`), saldo po obciążeniu (`balance_ngonka`, tylko bez streamingu) i czasy (`ttft_ms`). Inne protokoły nie zwracają tego bloku.
- `x-request-id` — identyfikator zapytania: dołącz go do zgłoszenia w support.
- `Retry-After` przychodzi z `429`: tyle sekund trzeba poczekać przed ponowieniem.
- Nagłówki `X-Title` i `HTTP-Referer` (jak w OpenRouter) pomagają bramie rozpoznać Twoją aplikację; ich treść nie jest zapisywana.

## Ograniczenia

- Obrazy: części `image_url` są zastępowane tekstowym placeholderem — model nie widzi obrazka (`vision: false` w możliwościach).
- Z przeglądarki API jest dostępne tylko z domen JoinGonka (weryfikacja `Origin`): wywołuj je ze swojego serwera, nie umieszczaj klucza we froncie.
- Embeddingi: `POST /v1/embeddings` odpowiada `501` — w sieci nie ma modeli embeddingowych.
- Kody błędów, limity i timeouty — w sekcji [Błędy i limity](https://gate.joingonka.ai/pl/docs/errors).
