API · Anthropic Messages

POST /v1/messages

Второй протокол шлюза — тот, на котором говорят Claude Code и SDK Anthropic. Отдельного ключа не требует: у обоих протоколов ключ, баланс и каталог общие.

Когда он нужен#

Если клиент умеет OpenAI — берите Chat Completions, он полнее. Этот метод нужен там, где формат зашит в клиент: Claude Code, официальные SDK Anthropic, плагины, написанные под Claude. Таким клиентам обычно достаточно указать хост https://nirastudio.org — путь /v1/messages они дописывают сами.

Запрос#

bash
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.

Ответ#

json
{
  "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:

text
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:

json
[
  {
    "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 из истории сообщений не пересылаются обратно модели. Рассуждение прошлого хода ей не нужно, а токены за него посчитали бы снова.