Para agentes de IA: guía paso a paso de configuración — /docs/agents.md, índice de documentación — /llms.txt.
Referencia de la API
Todo sobre las solicitudes a la pasarela: protocolos, direcciones, claves y parámetros. A continuación: streaming, llamada a herramientas, razonamiento, plugins y el coste de la solicitud en la respuesta.
Protocolos y direcciones#
El gateway acepta los formatos de OpenAI y Anthropic. La URL base para el SDK de OpenAI es https://gate.joingonka.ai/v1 y para el SDK de Anthropic, https://gate.joingonka.ai. Todos los protocolos funcionan con una misma clave y un mismo saldo: una solicitud en cualquier formato recorre el mismo camino.
| Método y ruta | Formato | Para qué sirve | Particularidades |
|---|---|---|---|
POST /v1/chat/completions | OpenAI Chat Completions | Chat, agentes, llamada a herramientas | Es la ruta principal: el gateway convierte los demás formatos a este. |
POST /v1/messages | Anthropic Messages | Claude Code y el SDK de Anthropic | URL base sin /v1; los modelos claude-* se sustituyen por el recomendado; el campo max_tokens es obligatorio. |
POST /v1/responses | OpenAI Responses | Codex CLI y los nuevos SDK de OpenAI | Sin estado: envía el historial completo en cada solicitud. |
POST /v1/completions | OpenAI Completions (legacy) | Autocompletado y edición de código en editores | suffix se pasa al modelo como sugerencia; en la respuesta, logprobs: null. |
POST /v1/embeddings | OpenAI Embeddings | Representaciones vectoriales de texto | Respuesta 501: la red no tiene modelos de embeddings. |
Direcciones de referencia#
Responden sin clave. La tabla de modelos con contexto y estado está en la sección Modelos.
| Método y ruta | Descripción |
|---|---|
GET /v1/models | Lista de modelos: contexto, precios, parámetros admitidos; campos en formato OpenRouter. |
GET /v1/models/{model} | Ficha de un modelo; la barra en el id, tal cual o como %2F. Modelo oculto o desconocido: 404 model_not_found. |
GET /v1/capabilities | Capacidades del gateway: parámetros, protocolos, plugins, campos de coste y límites (limits). |
GET /v1/plugins | Plugins: id y nombre. |
GET /v1/network-status | Estado de los modelos de la red: disponibilidad, latencias, uptime. |
GET /v1/nodes | Resumen del pool de nodos: cuántos hay en total, activos y en cuarentena. |
GET /v1/web-search/engines | Si la búsqueda web está activada y en qué estado están sus motores. |
Anthropic Messages#
- URL base:
https://gate.joingonka.ai. El SDK añadirá/v1/messagespor su cuenta. - La clave va en el encabezado
x-api-key(así la envía el SDK de Anthropic) oAuthorization: Bearer. - El gateway sustituye los modelos
claude-*por el recomendado (MiniMaxAI/MiniMax-M2.7); en el campomodelde la respuesta se mantiene el nombre que envió el cliente. max_tokenses obligatorio, como en la API de Anthropic; si supera el techo del modelo, se recorta.- El stream son eventos de Anthropic; en las pausas el gateway envía
event: pingy un fallo llega como eventoevent: error. - El razonamiento del modelo no aparece en la respuesta: no hay bloques
thinking. - La herramienta integrada
web_searchla ejecuta el plugin de búsqueda web del gateway; consulta la sección Plugins. - No hay conteo de tokens (
/v1/messages/count_tokens): respuesta404.
Claude Code se configura más fácilmente con el instalador: conexión de herramientas. De forma manual, con variables de entorno; ANTHROPIC_MODEL fija el modelo de la red.
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#
- El gateway no almacena respuestas: envía todo el historial en
input. Los camposprevious_response_idyconversationdan un error400con código. storese acepta y no cambia nada.- Herramientas:
functionyweb_search, que ejecuta el plugin de búsqueda web. El gateway omite las demás herramientas integradas y la solicitud se ejecuta sin ellas; exigir una de esas herramientas mediantetool_choiceda un error400. - Las partes
input_imageyinput_filedan un error400: los modelos de la red trabajan con texto. - Las direcciones de estado (
GET /v1/responses/{id},DELETE /v1/responses/{id},GET /v1/responses/{id}/input_items,POST /v1/responses/{id}/cancel,POST /v1/responses/compact) responden404con código: el gateway no almacena respuestas. - Codex CLI: define tu propio id de proveedor en
model_provider(que no sea openai); así Codex comprime el historial por su cuenta, sin/v1/responses/compact.
Legacy Completions#
promptes una cadena o un array de una sola cadena; la respuesta va enchoices[].text. Varios prompts o tokens en lugar de texto dan un error400.suffixse pasa al modelo como sugerencia en el prompt: la red no realiza un verdadero relleno de la parte central.- En la respuesta,
logprobs: null;best_ofse ignora;echofunciona.
Claves y autorización#
La clave se envía en el encabezado Authorization: Bearer jg-… o x-api-key: jg-…, en todas las direcciones. La clave se crea tras registrarse en la página gate.joingonka.ai/keys.
| Prefijo | Clave | Solicitudes a los modelos |
|---|---|---|
jg- | Clave normal de la cuenta | sí |
gc- | Clave hija: límites propios, el gasto se descuenta del saldo del propietario | sí |
gm- | Clave de gestión: solo gestiona las claves hijas | no: 403 forbidden |
- En el panel puedes fijar a cada clave un límite de gasto diario, mensual y total; si se supera,
402 child_key_limit_exceeded. - El número de solicitudes por minuto por clave está limitado; los valores están en la sección Límites.
- Sin clave solo funciona el chat de demostración del sitio: una solicitud sin clave desde tu propio código recibirá
402conis_demo. - Las claves solo se gestionan en el panel:
/api/keysno está disponible con una clave API. El saldo y el gasto por clave están en API de la cuenta.
La clave es un secreto: no la guardes en el repositorio ni en el código del frontend, pásala mediante variables de entorno.
Ejemplos#
La misma petición en cuatro SDK. El modelo es el recomendado (MiniMaxAI/MiniMax-M2.7), la clave va en la variable de entorno 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)Respuesta en streaming#
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)Parámetros de la petición#
Parámetros de POST /v1/chat/completions que el gateway garantiza por su cuenta: la lista supported_parameters en la respuesta de capacidades:
| Parámetro | Descripción |
|---|---|
temperature | Aleatoriedad de la respuesta: cuanto más alto, más variada. |
top_p | Selección de tokens por probabilidad acumulada. |
top_k | Selección entre los k tokens más probables. |
min_p | Descarte de tokens poco probables respecto al más probable. |
frequency_penalty | Penalización por repeticiones frecuentes. |
presence_penalty | Penalización por tokens ya aparecidos. |
repetition_penalty | Multiplicador contra las repeticiones. |
stop | Cadenas en las que se detiene la generación. |
seed | Semilla para la reproducibilidad. |
max_tokens | Límite de tokens de la respuesta; por encima del techo del modelo se recorta hasta el techo. |
max_completion_tokens | Otro nombre de max_tokens: el gateway traslada el valor a él. |
tools | Funciones que el modelo puede invocar, en formato OpenAI. |
tool_choice | Si invocar una función: a elección del modelo, nunca, obligatorio o una concreta. |
response_format | Respuesta estructurada: json_object o json_schema. |
- Sin
temperature, el gateway aplica0.7. - Sin
max_tokens, el gateway aplica el valor por defecto del modelo: sin streaming, más corto; en streaming, el techo del modelo. Los números por modelo están en la sección Límites.
Se transmiten a la red tal cual#
reasoning_effort, reasoning, enable_thinking, chat_template_kwargs, thinking_token_budget, min_tokens, logit_bias, n, parallel_tool_calls, extra_body. El gateway no los valida: un valor fuera de la lista de la red produce un error 400 con tipo api_error.
No se transmiten a la red#
El resto de campos el gateway los acepta pero no los transmite a la red, por ejemplo user, metadata, store, logprobs, top_logprobs, thinking, stream_options, web_search_options. usage en streaming llega siempre.
Streaming#
stream: true: respuesta por eventos SSE; el último evento esdata: [DONE].- Antes del cierre llega un chunk con
usage, siempre, incluso sinstream_options. - En las pausas el gateway envía cada 15 s un comentario
: keep-alive; los clientes SSE lo ignoran. - Mientras el stream no está abierto, el rechazo llega con un código de respuesta normal; una vez abierto, llega como chunk
joingonka-error. - En
delta.tool_callshay una sola llamada por chunk: las llamadas que la red une las separa el gateway.
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]Chunks internos del gateway#
Se reconocen por el campo id:
id | Cuándo y qué incluye |
|---|---|
joingonka-error | Fallo tras abrir el stream: campo error y luego corte sin [DONE]. |
joingonka-stream-stalled | La red estuvo en silencio más de la pausa permitida: el stream se cierra con finish_reason: stop. |
joingonka-stream-unfinished | La red interrumpió la generación: finish_reason: length; continúa con la siguiente petición. |
joingonka-citations | Fuentes de la búsqueda web en delta.annotations, antes del cierre. |
joingonka-meta | Coste y tiempos solo con la cabecera x-joingonka-meta: 1. |
Streaming en otros protocolos#
- Anthropic Messages: eventos desde
message_starthastamessage_stop, conevent: pingen las pausas yevent: erroren caso de fallo. - OpenAI Responses: eventos
response.*, falloresponse.failed. - Legacy Completions: en caso de fallo,
data: {"error": …}y luego[DONE].
Llamada a herramientas#
- Formato OpenAI:
toolsytool_choice. El formato antiguofunctionsyfunction_calltambién se acepta, y la respuesta llega en ese mismo formato. - En streaming, una llamada por chunk: los clientes que solo leen el primer elemento no pierden llamadas.
- El historial con el que la red devolvería un error
400el gateway lo corrige: el roldeveloperpasa asystem, los id de llamada vacíos y repetidos reciben valores únicos,argumentscomo objeto se convierte en cadena JSON, eltypeausente se completa, y una llamada sin nombre se elimina junto con su resultado. - La llamada que el modelo escribió como marcado en el texto el gateway la traslada a
tool_calls; las llamadas falsas en una respuesta a una petición sin herramientas las elimina. - La generación se interrumpió en medio de los argumentos: llegará
finish_reason: lengthy notool_calls; aumenta el límite de respuesta.
{
"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"]
}
}
}]
}Restricciones de JSON-Schema#
Los esquemas de las herramientas y response_format la red los compila a una gramática; las expresiones regulares usan el motor RE2. El gateway adapta el esquema a la forma que la red acepta:
- Los
$refse expanden en su lugar, las secciones$defsydefinitionsse eliminan; una referencia recursiva se convierte en un esquema sin restricciones. - El
patterncon construcciones que no existen en RE2 (lookahead y lookbehind, retrorreferencias, grupos atómicos, cuantificadores posesivos) se retira; las repeticiones mayores que 1000 se reducen a 1000. anyOfyoneOfde constantes se colapsan enenum; si hay más de 16 ramas no colapsables, la unión se retira.
El esquema puede volverse más permisivo que el original: valida los argumentos de la llamada en tu lado.
Respuesta estructurada#
response_format: {"type": "json_object"} para una respuesta JSON válida, {"type": "json_schema", "json_schema": {"name": …, "schema": …}} según tu esquema con las restricciones anteriores. El JSON truncado sin streaming lo corrige el plugin 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"]
}
}
}
}Razonamiento#
- El razonamiento del modelo llega aparte de la respuesta:
message.reasoning_content, y en streamingdelta.reasoning_content. El camporeasoningel gateway lo renombra a este formato. - El razonamiento consume
max_tokens: con un límite pequeño la respuesta se corta (finish_reason: length) antes incluso del texto. - Si no hay texto de respuesta pero sí razonamiento, el gateway lo traslada a
content, salvo en respuestas con llamada a herramienta. reasoning_effortyreasoning.effortse transmiten a la red. Si el modelo solo tiene dos modos, el gateway adapta el valor a ellos:noneyminimalalow, los más altos al razonamiento por defecto.- Si el nodo rechaza el valor, el gateway lo rebaja (
maxyxhigh→high,minimal→low, o de lo contrario elimina el campo) y repite la petición. - En
/v1/messagesno se transmite el razonamiento: no hay bloquesthinking.
Plugins#
Los plugins se activan con el campo plugins: un array de cadenas o de objetos con opciones. La lista está en GET /v1/plugins.
| Plugin | Descripción | Condiciones |
|---|---|---|
response-healing | Corrige el JSON truncado en la respuesta del modelo. | Solo sin streaming y si la respuesta empieza por { o [. |
privacy-sanitization | Enmascara en los mensajes de texto emails, IPv4, números de tarjeta, JWT, claves hex de 64 caracteres y claves con forma sk-…, gw_…, gm-…, Bearer …. | El modo es el campo privacy_mode: redact (por defecto) o tokenize. |
file-parser | Extrae el texto de un PDF. | Si el texto del mensaje es íntegramente un PDF en base64: data:application/pdf;base64,… o sin prefijo. |
web | Búsqueda web: los resultados se incorporan a la petición y la respuesta recibe enlaces a las fuentes. | Junto con privacy-sanitization, error 400. |
Búsqueda web#
- Opciones:
max_results, de 1 a 10, por defecto 5;engine, sugerencia de motor;search_prompt, texto propio antes de los resultados;enabled: false, desactivar la búsqueda. - Las fuentes están en
message.annotations[].url_citation; en streaming, en el chunkjoingonka-citationsantes del cierre. mode: "agent": el modelo decide por sí mismo si buscar y qué buscar;max_searches, de 1 a 5, por defecto 3.- Pago: en modo normal, solo tokens (los resultados de búsqueda se incluyen en los tokens de entrada); en modo agente, los tokens de todos los pasos más 1000 nGNK por cada búsqueda realizada (
x_joingonka.web_search_surcharge_ngonka). - En Anthropic Messages y OpenAI Responses, la herramienta integrada
web_searchejecuta este mismo plugin en modo agente.
{
"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}]
}Costo y campos de servicio#
La respuesta sin streaming incluye el costo de la solicitud en usage:
| Campo | Descripción |
|---|---|
usage.cost_gnk | Costo de la solicitud en GNK |
usage.platform_fee_gnk | De lo cual, margen de la plataforma, GNK |
usage.total_cost_gnk | Total a debitar en GNK |
usage.total_cost_usd | Total en dólares según el tipo de cambio actual de GNK |
- En streaming,
usagecontiene solo tokens; el costo está en el chunkjoingonka-meta. - Con la cabecera
x-joingonka-meta: 1, la respuestaPOST /v1/chat/completionsrecibe el bloquex_joingonka: costo (cost_ngonka), saldo tras el débito (balance_ngonka, solo sin streaming) y tiempos (ttft_ms). Otros protocolos no devuelven este bloque. x-request-id: identificador de la solicitud; inclúyelo en tu contacto con soporte.Retry-Afterllega con429: los segundos que hay que esperar antes de reintentar.- Las cabeceras
X-TitleyHTTP-Referer(como en OpenRouter) ayudan a la pasarela a identificar tu aplicación; su texto no se almacena.
Limitaciones#
- Imágenes: las partes
image_urlse sustituyen por un marcador de texto; el modelo no ve la imagen (vision: falseen las capacidades). - Desde el navegador, la API solo es accesible desde dominios de JoinGonka (verificación
Origin): llámala desde tu propio servidor y no pongas la clave en el frontend. - Embeddings:
POST /v1/embeddingsresponde501; no hay modelos de embeddings en la red. - Códigos de error, límites y timeouts en la sección Errores y límites.