API · Chat Completions

POST /v1/chat/completions

Основной метод шлюза. Совместим с OpenAI на уровне полей: библиотека openai работает с ним без правок, достаточно поменять base_url и ключ.

Минимальный запрос#

bash
curl https://nirastudio.org/v1/chat/completions \
  -H "Authorization: Bearer $NIRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.6",
    "messages": [{ "role": "user", "content": "Привет" }]
  }'

Обязательных полей два: model и messages. Всё остальное имеет разумные значения по умолчанию — их задаёт сама модель, а не шлюз.

Поля запроса#

ПолеТип и смысл
modelСтрока. Идентификатор из каталога
messagesМассив, от 1 до 400 сообщений. Роли: system, user, assistant, tool
streamЛогическое. true — ответ приходит событиями SSE
stream_optionsОбъект. include_usage: true добавляет в конец стрима кусок со счётчиком токенов
temperatureЧисло 0…2. Выше — разнообразнее, ниже — предсказуемее
top_pЧисло 0…1. Обрезание по вероятности; вместе с temperature обычно не используют
max_tokensЦелое 1…200 000. Предел длины ответа. Синоним max_completion_tokens — если пришли оба, действует max_tokens
stopСтрока или массив до 8 строк. Генерация прервётся на любой из них
toolsМассив до 128 инструментов. См. инструменты
tool_choiceКак выбирать инструмент: auto, none, required или конкретное имя
functionsУстаревшая форма tools. Принимается для старых клиентов, вместе с tools не нужна
response_formatОбъект с type: json_object или json_schema — просит модель отвечать разбираемым JSON
reasoningОбъект: enabled и effort. Включает рассуждение у моделей, которые его умеют
Неизвестные поля приводят к 400, а не игнорируются молча: опечатка в имени поля иначе выглядела бы как «настройка не действует».

Сообщения#

content — либо строка, либо массив частей. Массив нужен, когда во входе есть картинка:

json
{
  "role": "user",
  "content": [
    { "type": "text", "text": "Что на схеме?" },
    { "type": "image_url", "image_url": { "url": "data:image/png;base64,iVBORw0…" } }
  ]
}
  • system — общие правила поведения. Ставится первым сообщением.
  • assistant — предыдущие ответы модели; вместе с tool_calls, если она вызывала инструменты.
  • tool — результат вызова, с тем же tool_call_id, что пришёл в tool_calls.

Подробности по картинкам — в отдельном разделе: не каждая модель их принимает.

Ответ целиком#

json
{
  "id": "chatcmpl-…",
  "object": "chat.completion",
  "created": 1770000000,
  "model": "anthropic/claude-sonnet-4.6",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "Привет!" },
      "finish_reason": "stop"
    }
  ],
  "usage": { "prompt_tokens": 8, "completion_tokens": 3, "total_tokens": 11 }
}

finish_reason

ЗначениеПочему генерация закончилась
stopМодель закончила мысль сама или наткнулась на stop-строку
lengthКончился max_tokens. Ответ обрезан на полуслове — стоит повторить с бо́льшим пределом
tool_callsМодель хочет вызвать инструмент. Ответа для пользователя тут нет, см. инструменты

Стрим#

С stream: true ответ приходит цепочкой кусков chat.completion.chunk: сначала кусок с ролью, затем дельты текста, затем кусок с finish_reason. Разбор событий и порядок — в разделе про стриминг.

text
data: {"choices":[{"index":0,"delta":{"role":"assistant"}}], …}
data: {"choices":[{"index":0,"delta":{"content":"При"}}], …}
data: {"choices":[{"index":0,"delta":{"content":"вет"}}], …}
data: {"choices":[{"index":0,"delta":{},"finish_reason":"stop"}], …}
data: [DONE]

Ответ в JSON#

Когда результат нужен машине, а не человеку, попросите разбираемый JSON — так не придётся выковыривать объект из окружающего текста:

json
{
  "model": "anthropic/claude-sonnet-4.6",
  "messages": [{ "role": "user", "content": "Разбери адрес: Тверская 7, Москва" }],
  "response_format": { "type": "json_object" }
}
Поддержка зависит от модели. Если модель не умеет строгую схему, она вернёт JSON «по возможности» — оставьте проверку разбора на своей стороне.

Рассуждение#

json
{
  "model": "anthropic/claude-opus-5",
  "messages": [{ "role": "user", "content": "Найди ошибку в этом доказательстве…" }],
  "reasoning": { "enabled": true, "effort": "high" }
}

effortlow, medium или high. Модели, которые рассуждать не умеют, поле просто игнорируют: 400 не будет.

Рассуждение тарифицируется как выходные токены, даже когда его текст не показан. На простых задачах это заметная переплата без выигрыша в качестве.