POST /v1/messages
Второй протокол шлюза — тот, на котором говорят Claude Code и SDK Anthropic. Отдельного ключа не требует: у обоих протоколов ключ, баланс и каталог общие.
Когда он нужен#
Если клиент умеет OpenAI — берите Chat Completions, он полнее. Этот метод нужен там, где формат зашит в клиент: Claude Code, официальные SDK Anthropic, плагины, написанные под Claude. Таким клиентам обычно достаточно указать хост https://nirastudio.org — путь /v1/messages они дописывают сами.
Запрос#
curl https://nirastudio.org/v1/messages \
-H "x-api-key: $NIRA_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "anthropic/claude-sonnet-4.6",
"max_tokens": 1024,
"system": "Отвечай кратко.",
"messages": [{ "role": "user", "content": "Привет" }]
}'| Поле | Тип и смысл |
|---|---|
model | Строка. Тот же идентификатор, что и в OpenAI-протоколе |
messages | Массив. content — строка или массив частей: text, image, tool_use, tool_result |
system | Строка или массив блоков. Отдельным сообщением, как в OpenAI, его тут не передают |
max_tokens | Целое. Предел длины ответа |
stream | Логическое. true — события SSE с именами |
temperature | Число. Как в OpenAI-протоколе |
top_p | Число |
stop_sequences | Массив строк. Аналог stop |
tools | Массив в форме Anthropic: name, description, input_schema |
tool_choice | {"type":"auto"}, {"type":"any"}, {"type":"none"} или {"type":"tool","name":"…"} |
thinking | Объект с type: enabled, adaptive, auto включают рассуждение, disabled и none выключают |
anthropic-version шлюз не проверяет — клиенты присылают его сами, и мешать им незачем. Ключ принимается и как x-api-key, и как Authorization: Bearer.Ответ#
{
"id": "msg_…",
"type": "message",
"role": "assistant",
"model": "anthropic/claude-sonnet-4.6",
"content": [{ "type": "text", "text": "Привет!" }],
"stop_reason": "end_turn",
"usage": { "input_tokens": 8, "output_tokens": 3 }
}stop_reason: end_turn — модель закончила, max_tokens — упёрлась в предел, tool_use — хочет вызвать инструмент, stop_sequence — наткнулась на стоп-строку.
События стрима#
В отличие от OpenAI-протокола, здесь у каждого события есть имя в поле event:
event: message_start
data: {"type":"message_start","message":{"id":"msg_…","role":"assistant", …}}
event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}
event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"При"}}
event: content_block_stop
data: {"type":"content_block_stop","index":0}
event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn"},"usage":{"output_tokens":3}}
event: message_stop
data: {"type":"message_stop"}Счётчик токенов приходит в message_delta — отдельного куска, как include_usage в OpenAI, тут нет. Сбой посреди стрима приходит событием error; код ответа к тому моменту уже 200, см. ошибки.
Инструменты#
Вызов приходит блоком tool_use в content, а результат вы возвращаете блоком tool_result с тем же tool_use_id:
[
{
"role": "assistant",
"content": [
{ "type": "tool_use", "id": "toolu_…", "name": "get_weather",
"input": { "city": "Москва" } }
]
},
{
"role": "user",
"content": [
{ "type": "tool_result", "tool_use_id": "toolu_…", "content": "-3 °C, снег" }
]
}
]Логика цикла та же, что в OpenAI-протоколе, — разобрана в инструментах.
Две особенности#
Большой max_tokens не передаётся дальше
Значения от 8000 и выше шлюз не пересылает провайдеру: агенты часто ставят предел «на всякий случай» в десятки тысяч, и для части моделей это само по себе ошибка. Без этого поля модель отвечает своим обычным пределом — на длину ответа это влияет редко.thinking и redacted_thinking из истории сообщений не пересылаются обратно модели. Рассуждение прошлого хода ей не нужно, а токены за него посчитали бы снова.