> Per gli agenti AI: guida passo passo alla configurazione — [`/docs/agents.md`](https://gate.joingonka.ai/docs/agents.md), indice della documentazione — [`/llms.txt`](https://gate.joingonka.ai/llms.txt).

# Riferimento API

Tutto sulle richieste al gateway: protocolli, indirizzi, chiavi e parametri. Di seguito — streaming, chiamata di strumenti, ragionamento, plugin e costo della richiesta nella risposta.

## Protocolli e indirizzi

Il gateway accetta i formati OpenAI e Anthropic. Il Base URL per gli SDK OpenAI è `https://gate.joingonka.ai/v1`, per gli SDK Anthropic è `https://gate.joingonka.ai`. Tutti i protocolli funzionano con la stessa chiave e lo stesso saldo: una richiesta in qualsiasi formato segue lo stesso percorso.

| Metodo e percorso | Formato | A cosa serve | Note |
| --- | --- | --- | --- |
| `POST /v1/chat/completions` | OpenAI Chat Completions | Chat, agenti, chiamata di strumenti | Percorso principale: il gateway converte gli altri formati in questo. |
| `POST /v1/messages` | Anthropic Messages | Claude Code e SDK Anthropic | Base URL senza `/v1`; i modelli `claude-*` vengono sostituiti con quello consigliato; il campo `max_tokens` è obbligatorio. |
| `POST /v1/responses` | OpenAI Responses | Codex CLI e i nuovi SDK OpenAI | Senza stato: invia la cronologia completa in ogni richiesta. |
| `POST /v1/completions` | OpenAI Completions (legacy) | Autocompletamento e correzione del codice negli editor | `suffix` viene passato al modello come suggerimento; nella risposta `logprobs: null`. |
| `POST /v1/embeddings` | OpenAI Embeddings | Rappresentazioni vettoriali del testo | Risposta `501`: nella rete non ci sono modelli di embedding. |

### Indirizzi di riferimento

Rispondono senza chiave. La tabella dei modelli con contesto e stato è nella sezione [Modelli](https://gate.joingonka.ai/it/docs/models).

| Metodo e percorso | Descrizione |
| --- | --- |
| `GET /v1/models` | Elenco dei modelli: contesto, prezzi, parametri supportati — campi nel formato OpenRouter. |
| `GET /v1/models/{model}` | Scheda di un singolo modello; lo slash nell'id va inserito così com'è oppure come `%2F`. Modello nascosto o sconosciuto — `404 model_not_found`. |
| `GET /v1/capabilities` | Funzionalità del gateway: parametri, protocolli, plugin, campi di costo e limiti (`limits`). |
| `GET /v1/plugins` | Plugin: id e nome. |
| `GET /v1/network-status` | Stato dei modelli della rete: disponibilità, latenze, uptime. |
| `GET /v1/nodes` | Riepilogo del pool di nodi: quanti in totale, attivi e in quarantena. |
| `GET /v1/web-search/engines` | Se la ricerca web è attiva e in che stato sono i suoi motori. |

### Anthropic Messages

- Base URL — `https://gate.joingonka.ai`: l'SDK aggiunge `/v1/messages` da solo.
- Chiave — nell'header `x-api-key` (così la invia l'SDK Anthropic) oppure `Authorization: Bearer`.
- I modelli `claude-*` vengono sostituiti dal gateway con quello consigliato (`MiniMaxAI/MiniMax-M2.7`); nel campo `model` della risposta resta il nome inviato dal client.
- `max_tokens` è obbligatorio, come nell'API Anthropic; se supera il tetto del modello viene tagliato.
- Stream — eventi Anthropic; nelle pause il gateway invia `event: ping`, un errore arriva come evento `event: error`.
- Il ragionamento del modello non compare nella risposta: non ci sono blocchi `thinking`.
- Lo strumento integrato `web_search` viene eseguito dal plugin di ricerca web del gateway — vedi la sezione [Plugin](https://gate.joingonka.ai/it/docs/api#plugins).
- Non c'è il conteggio dei token (`/v1/messages/count_tokens`) — risposta `404`.

Configurare Claude Code è più semplice con l'installer — [connessione degli strumenti](https://gate.joingonka.ai/it/docs#connect). Manualmente, tramite variabili d'ambiente; `ANTHROPIC_MODEL` fissa il modello della rete.

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

- Il gateway non conserva le risposte: invia tutta la cronologia in `input`. I campi `previous_response_id` e `conversation` — errore `400` con codice.
- `store` viene accettato senza alcun effetto.
- Strumenti: `function` e `web_search` — quest'ultimo viene eseguito dal plugin di ricerca web. Gli altri strumenti integrati vengono ignorati dal gateway e la richiesta va a buon fine senza di essi; richiedere uno di questi strumenti tramite `tool_choice` — errore `400`.
- Le parti `input_image` e `input_file` — errore `400`: i modelli della rete lavorano con il testo.
- Gli indirizzi di stato (`GET /v1/responses/{id}`, `DELETE /v1/responses/{id}`, `GET /v1/responses/{id}/input_items`, `POST /v1/responses/{id}/cancel`, `POST /v1/responses/compact`) rispondono `404` con codice — il gateway non conserva le risposte.
- Codex CLI: imposta il tuo id di provider in `model_provider` (non openai) — così Codex comprime la cronologia da solo, senza `/v1/responses/compact`.

### Legacy Completions

- `prompt` — stringa o array con una sola stringa; la risposta è in `choices[].text`. Più prompt o token al posto del testo — errore `400`.
- `suffix` viene passato al modello come suggerimento nel prompt: la rete non supporta davvero il riempimento centrale.
- Nella risposta `logprobs: null`; `best_of` viene ignorato; `echo` funziona.

## Chiavi e autorizzazione

La chiave si passa nell'header `Authorization: Bearer jg-…` oppure `x-api-key: jg-…` — su tutti gli indirizzi. La chiave si crea dopo la registrazione nella pagina [gate.joingonka.ai/keys](https://gate.joingonka.ai/keys).

| Prefisso | Chiave | Richieste ai modelli |
| --- | --- | --- |
| `jg-` | Chiave normale dell'account | sì |
| `gc-` | Chiave figlia: limiti propri, spesa dal saldo del proprietario | sì |
| `gm-` | Chiave di gestione: gestisce solo le chiavi figlie | no — `403 forbidden` |

- A ogni chiave nell'area personale si può assegnare un limite di spesa giornaliero, mensile e totale; se lo superi — `402 child_key_limit_exceeded`.
- Il numero di richieste al minuto per chiave è limitato — i valori sono nella sezione [Limiti](https://gate.joingonka.ai/it/docs/errors#limits).
- Senza chiave funziona solo la chat demo sul sito: una richiesta dal tuo codice senza chiave riceverà `402` con `is_demo`.
- Le chiavi si gestiscono solo nell'area personale: `/api/keys` con API key non è accessibile. Saldo e spesa per chiave — [API dell'account](https://gate.joingonka.ai/it/docs/billing#account-api).

> La chiave è un segreto: non conservarla nel repository né nel codice frontend, trasmettila tramite variabili d'ambiente.

## Esempi

La stessa richiesta in quattro SDK. Il modello è quello consigliato (`MiniMaxAI/MiniMax-M2.7`), la chiave proviene dalla variabile d'ambiente `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)
```

### Risposta in streaming

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

## Parametri della richiesta

I parametri di `POST /v1/chat/completions` che il gateway garantisce da sé — la lista `supported_parameters` nella risposta capabilities:

| Parametro | Descrizione |
| --- | --- |
| `temperature` | Casualità della risposta: più è alto, più è varia. |
| `top_p` | Selezione dei token per probabilità cumulata. |
| `top_k` | Selezione tra i k token più probabili. |
| `min_p` | Taglio dei token improbabili rispetto a quello più probabile. |
| `frequency_penalty` | Penalità per le ripetizioni frequenti. |
| `presence_penalty` | Penalità per i token già comparsi. |
| `repetition_penalty` | Moltiplicatore contro le ripetizioni. |
| `stop` | Stringhe su cui la generazione si ferma. |
| `seed` | Seme per la riproducibilità. |
| `max_tokens` | Limite di token della risposta; oltre il tetto del modello — viene tagliata al tetto. |
| `max_completion_tokens` | Un altro nome di `max_tokens`: il gateway vi trasferisce il valore. |
| `tools` | Funzioni che il modello può chiamare, nel formato OpenAI. |
| `tool_choice` | Se chiamare una funzione: a scelta del modello, mai, obbligatoriamente o una specifica. |
| `response_format` | Risposta strutturata: `json_object` o `json_schema`. |

- Senza `temperature` il gateway inserisce `0.7`.
- Senza `max_tokens` il gateway inserisce il default del modello: senza stream — più corto, in streaming — il tetto del modello. I numeri per modello sono nella sezione [Limiti](https://gate.joingonka.ai/it/docs/errors#limits).

### Trasmessi alla rete così come sono

`reasoning_effort`, `reasoning`, `enable_thinking`, `chat_template_kwargs`, `thinking_token_budget`, `min_tokens`, `logit_bias`, `n`, `parallel_tool_calls`, `extra_body`. Il gateway non li verifica: un valore fuori dalla lista della rete — errore `400` con tipo `api_error`.

### Non trasmessi alla rete

Gli altri campi il gateway li accetta e non li trasmette alla rete — per esempio `user`, `metadata`, `store`, `logprobs`, `top_logprobs`, `thinking`, `stream_options`, `web_search_options`. `usage` in streaming arriva sempre.

## Streaming

- `stream: true` — risposta come eventi SSE; l'ultimo evento — `data: [DONE]`.
- Prima della conclusione arriva un chunk con `usage` — sempre, anche senza `stream_options`.
- Nelle pause il gateway invia ogni 15 s un commento `: keep-alive` — i client SSE lo saltano.
- Finché lo stream non è aperto, il rifiuto arriva come normale codice di risposta; dopo l'apertura — come chunk `joingonka-error`.
- In `delta.tool_calls` — una chiamata per chunk: le chiamate unite dalla rete il gateway le separa.

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

### Chunk di servizio del gateway

Si riconoscono dal campo `id`:

| `id` | Quando e cosa contiene |
| --- | --- |
| `joingonka-error` | Errore dopo l'apertura dello stream: campo `error`, poi interruzione senza `[DONE]`. |
| `joingonka-stream-stalled` | La rete è rimasta in silenzio oltre la pausa consentita: lo stream si chiude con `finish_reason: stop`. |
| `joingonka-stream-unfinished` | La rete ha interrotto la generazione: `finish_reason: length` — continua con la richiesta successiva. |
| `joingonka-citations` | Le fonti della ricerca web in `delta.annotations` — prima della conclusione. |
| `joingonka-meta` | Costo e tempistiche — solo con l'header `x-joingonka-meta: 1`. |

### Stream in altri protocolli

- Anthropic Messages: eventi da `message_start` a `message_stop`, nelle pause `event: ping`, errore — `event: error`.
- OpenAI Responses: eventi `response.*`, errore — `response.failed`.
- Legacy Completions: in caso di errore — `data: {"error": …}`, poi `[DONE]`.

## Chiamata degli strumenti

- Formato OpenAI: `tools` e `tool_choice`. Anche il vecchio formato `functions` e `function_call` è accettato — la risposta arriverà nello stesso.
- In streaming — una chiamata per chunk: i client che leggono solo il primo elemento non perdono le chiamate.
- La cronologia su cui la rete risponderebbe con errore `400` il gateway la corregge: il ruolo `developer` diventa `system`, gli id di chiamata vuoti e duplicati ricevono id univoci, `arguments` come oggetto diventa una stringa JSON, il `type` mancante viene aggiunto, la chiamata senza nome viene rimossa insieme al risultato.
- La chiamata che il modello ha scritto come markup nel testo il gateway la sposta in `tool_calls`; le chiamate false nella risposta a una richiesta senza strumenti le rimuove.
- La generazione si è interrotta a metà degli argomenti — arriverà `finish_reason: length`, non `tool_calls`: aumenta il limite della risposta.

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

### Limitazioni di JSON-Schema

Gli schemi degli strumenti e `response_format` la rete li compila in una grammatica; le espressioni regolari — con il motore RE2. Il gateway porta lo schema alla forma che la rete accetta:

- I `$ref` vengono espansi sul posto, le sezioni `$defs` e `definitions` vengono rimosse; un riferimento ricorsivo diventa uno schema senza vincoli.
- I `pattern` con costrutti assenti in RE2 (lookahead e lookbehind, backreference, gruppi atomici, quantificatori possessivi) vengono rimossi; le ripetizioni superiori a 1000 vengono ridotte a 1000.
- `anyOf` e `oneOf` di costanti vengono compattati in `enum`; se i rami non compattabili sono più di 16, l'unione viene rimossa.

> Lo schema può diventare più permissivo dell'originale — verifica gli argomenti della chiamata dalla tua parte.

## Risposta strutturata

`response_format`: `{"type": "json_object"}` — risposta come JSON valido, `{"type": "json_schema", "json_schema": {"name": …, "schema": …}}` — secondo il tuo schema con le limitazioni sopra. Il JSON troncato senza stream viene corretto dal 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"]
      }
    }
  }
}
```

## Ragionamento

- Il ragionamento del modello arriva separato dalla risposta: `message.reasoning_content`, in streaming — `delta.reasoning_content`. Il campo `reasoning` il gateway lo rinomina in questo formato.
- Il ragionamento consuma `max_tokens`: con un limite piccolo la risposta si interrompe (`finish_reason: length`) ancora prima del testo.
- Se il testo della risposta manca ma il ragionamento c'è, il gateway lo sposta in `content` — tranne le risposte con chiamata di strumento.
- `reasoning_effort` e `reasoning.effort` vengono trasmessi alla rete. Se il modello ha solo due modalità, il gateway adegua il valore: `none` e `minimal` — a `low`, quelli più alti — al ragionamento predefinito.
- Se il nodo rifiuta il valore, il gateway lo abbassa (`max` e `xhigh` → `high`, `minimal` → `low`, altrimenti rimuove il campo) e ripete la richiesta.
- In `/v1/messages` il ragionamento non viene trasmesso — non ci sono blocchi `thinking`.

## Plugin

I plugin si attivano con il campo `plugins` — come array di stringhe o di oggetti con opzioni. La lista — `GET /v1/plugins`.

| Plugin | Descrizione | Condizioni |
| --- | --- | --- |
| `response-healing` | Corregge il JSON troncato nella risposta del modello. | Solo senza stream e se la risposta inizia con `{` o `[`. |
| `privacy-sanitization` | Maschera nei messaggi di testo email, IPv4, numeri di carta, JWT, chiavi hex di 64 caratteri e chiavi del tipo `sk-…`, `gw_…`, `gm-…`, `Bearer …`. | La modalità è il campo `privacy_mode`: `redact` (predefinita) o `tokenize`. |
| `file-parser` | Estrae il testo da un PDF. | Se il testo del messaggio è interamente un PDF in base64: `data:application/pdf;base64,…` o senza prefisso. |
| `web` | Ricerca web: i risultati vengono mescolati nella richiesta, la risposta riceve i link alle fonti. | Insieme a `privacy-sanitization` — errore `400`. |

### Ricerca web

- Opzioni: `max_results` — da 1 a 10, predefinito 5; `engine` — suggerimento del motore; `search_prompt` — testo personalizzato prima dei risultati; `enabled: false` — disattiva la ricerca.
- Le fonti — in `message.annotations[].url_citation`; in streaming — come chunk `joingonka-citations` prima della conclusione.
- `mode: "agent"` — il modello decide da sé se cercare e cosa; `max_searches` — da 1 a 5, predefinito 3.
- Pagamento: in modalità normale — solo token (i risultati di ricerca rientrano nei token di input); in modalità agente — i token di tutti i passaggi più 1000 nGNK per ogni ricerca eseguita (`x_joingonka.web_search_surcharge_ngonka`).
- In Anthropic Messages e OpenAI Responses lo strumento integrato `web_search` esegue lo stesso plugin in modalità agente.

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

## Costo e campi di servizio

La risposta non in streaming riporta il costo della richiesta in `usage`:

| Campo | Descrizione |
| --- | --- |
| `usage.cost_gnk` | Costo della richiesta in GNK |
| `usage.platform_fee_gnk` | Di cui — maggiorazione della piattaforma, GNK |
| `usage.total_cost_gnk` | Totale da addebitare in GNK |
| `usage.total_cost_usd` | Totale in dollari al cambio GNK corrente |

- Nello streaming `usage` contiene solo token; il costo è nel chunk `joingonka-meta`.
- Con l'header `x-joingonka-meta: 1` la risposta `POST /v1/chat/completions` riceve il blocco `x_joingonka`: costo (`cost_ngonka`), saldo dopo l'addebito (`balance_ngonka`, solo senza streaming) e tempi (`ttft_ms`). Gli altri protocolli non restituiscono questo blocco.
- `x-request-id` — identificatore della richiesta: allegalo alla richiesta di assistenza.
- `Retry-After` arriva con `429`: quanti secondi attendere prima di riprovare.
- Gli header `X-Title` e `HTTP-Referer` (come su OpenRouter) aiutano il gateway a riconoscere la tua applicazione; il loro testo non viene salvato.

## Limiti

- Immagini: le parti `image_url` vengono sostituite da un segnaposto testuale — il modello non vede l'immagine (`vision: false` nelle capacità).
- Dal browser l'API è accessibile solo dai domini JoinGonka (controllo `Origin`): chiamala dal tuo server, non mettere la chiave nel frontend.
- Embedding: `POST /v1/embeddings` risponde `501` — nella rete non ci sono modelli di embedding.
- Codici di errore, limiti e timeout — nella sezione [Errori e limiti](https://gate.joingonka.ai/it/docs/errors).
