Документация

POST /v1/messages

Anthropic Messages API — эндпоинт /v1/messages API LLMost, совместимый с Anthropic Messages API и Claude Code.

Anthropic Messages API — эндпоинт для работы с моделями Claude в нативном антропиковском формате запросов и ответов. Совместим с Anthropic Messages API и официальным Anthropic SDK — существующий код, написанный под Anthropic, работает через LLMost без переписывания под формат OpenAI. Этот же эндпоинт используется для подключения Claude Code к LLMost.

Основная информация

Эндпоинт: POST https://llmost.ru/api/v1/messages

Аутентификация — API-ключ LLMost в заголовке Authorization: Bearer llmost_... (см. Аутентификация).

Слаги каталога, а не имена моделей Anthropic

Голые имена моделей Anthropic (например, claude-sonnet-4-5-20250929) эндпоинтом не резолвятся. В model нужно передавать слаг каталога LLMost — как и в остальном API, например anthropic/claude-sonnet-4.5. Для моделей, которые следует держать «плавающими» на последней версии (Claude Code, автоматизации), используйте alias-слаги вида ~anthropic/claude-sonnet-latest, ~anthropic/claude-opus-latest, ~anthropic/claude-haiku-latest — они всегда указывают на актуальную версию соответствующей линейки в каталоге.

Подключение Claude Code

Чтобы направить Claude Code через LLMost, задайте переменные окружения перед запуском:

export ANTHROPIC_BASE_URL="https://llmost.ru/api"
export ANTHROPIC_AUTH_TOKEN="llmost_ВАШ_КЛЮЧ"
export ANTHROPIC_API_KEY=""
export ANTHROPIC_DEFAULT_SONNET_MODEL="~anthropic/claude-sonnet-latest"
export ANTHROPIC_DEFAULT_OPUS_MODEL="~anthropic/claude-opus-latest"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="~anthropic/claude-haiku-latest"

Зачем ANTHROPIC_API_KEY=""

Claude Code при непустом ANTHROPIC_API_KEY обращается напрямую к api.anthropic.com, игнорируя ANTHROPIC_BASE_URL. Ключ LLMost передаётся через ANTHROPIC_AUTH_TOKEN — переменную ANTHROPIC_API_KEY нужно явно занулить, иначе Claude Code продолжит ходить в Anthropic напрямую.

После экспорта переменных запускайте claude как обычно — все запросы пойдут через https://llmost.ru/api/v1/messages и будут списывать баланс LLMost.

Быстрый старт

cURL

curl https://llmost.ru/api/v1/messages \
  -H "Authorization: Bearer llmost_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "anthropic/claude-sonnet-4.5",
    "max_tokens": 1024,
    "messages": [
      {
        "role": "user",
        "content": "В чём смысл жизни?"
      }
    ]
  }'

Python с Anthropic SDK

from anthropic import Anthropic

client = Anthropic(
    base_url="https://llmost.ru/api",
    api_key="llmost_ВАШ_КЛЮЧ",
)

message = client.messages.create(
    model="anthropic/claude-sonnet-4.5",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "В чём смысл жизни?"}
    ],
)

print(message.content[0].text)

TypeScript с Anthropic SDK

import Anthropic from '@anthropic-ai/sdk';

const anthropic = new Anthropic({
  baseURL: 'https://llmost.ru/api',
  apiKey: 'llmost_ВАШ_КЛЮЧ',
});

const message = await anthropic.messages.create({
  model: 'anthropic/claude-sonnet-4.5',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: 'В чём смысл жизни?' },
  ],
});

console.log(message.content[0].text);

Структура ответа

{
  "id": "msg_01XFDUDYJgAACzvnptvVoYEL",
  "type": "message",
  "role": "assistant",
  "model": "anthropic/claude-sonnet-4.5",
  "content": [
    {
      "type": "text",
      "text": "Смысл жизни — философский вопрос..."
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 15,
    "output_tokens": 120,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0,
    "cost": 0.00042,
    "cost_details": {}
  }
}

В не-потоковом ответе поле model — тот же слаг, что был передан в запросе (слаг каталога LLMost, не внутреннее имя апстрима). В потоковом режиме события проходят насквозь, поэтому model внутри message_start может содержать имя модели у провайдера (например, claude-sonnet-4-5-20250929) — не сверяйте его с отправленным слагом.

usage

Поля usage — в родном формате Anthropic, плюс два расширения LLMost:

  • input_tokens — входные токены, не покрытые кэшем
  • output_tokens — токены ответа
  • cache_creation_input_tokens — токены, записанные в prompt-кэш при этом запросе
  • cache_read_input_tokens — токены, прочитанные из prompt-кэша
  • cost — расширение LLMost: фактически списанная сумма в рублях, уже с учётом наценки LLMost
  • cost_details — расширение LLMost: детализация списания

Где искать cost

В не-потоковом ответе usage.cost приходит прямо в теле, как в примере выше — читайте его напрямую, отдельный запрос не нужен.

При stream: true cost-поля приходят в событии message_delta (в его usage, вместе с итоговым output_tokens) — также с уже применённой наценкой LLMost. Если поток оборвался до message_delta, точная стоимость видна в истории генераций в личном кабинете: списание LLMost выполняет по данным апстрима уже после закрытия потока.

Потоковая передача

Как и в остальном API, потоковая передача включается параметром stream: true — ответ приходит как Server-Sent Events в нативном формате событий Anthropic (message_start, content_block_delta, message_delta, message_stop и т.д.).

curl https://llmost.ru/api/v1/messages \
  -H "Authorization: Bearer llmost_ВАШ_КЛЮЧ" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "~anthropic/claude-sonnet-latest",
    "max_tokens": 1024,
    "stream": true,
    "messages": [
      {
        "role": "user",
        "content": "Напиши короткое стихотворение"
      }
    ]
  }'
const stream = await anthropic.messages.stream({
  model: '~anthropic/claude-sonnet-latest',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: 'Напиши короткое стихотворение' },
  ],
});

for await (const event of stream) {
  if (event.type === 'content_block_delta' && event.delta.type === 'text_delta') {
    process.stdout.write(event.delta.text);
  }
}

Общие принципы SSE (буферизация, отмена через AbortController) — см. Потоковую передачу; формат самих событий здесь — антропиковский, не OpenAI-подобный.

Обработка ошибок

Ошибки возвращаются в родном антропиковском конверте, а не в формате {"error": {...}}, который использует остальной API LLMost:

{
  "type": "error",
  "error": {
    "type": "invalid_request_error",
    "message": "Model 'anthropic/nonexistent' not found"
  }
}

Коды ошибок и error.type

HTTP-кодerror.typeПричина
400invalid_request_errorНевалидный запрос — отсутствуют обязательные поля, модель не найдена
401authentication_errorНедействительный или отсутствующий API-ключ
402invalid_request_errorНедостаточно средств на балансе — сообщение на русском, тип по протоколу Anthropic соответствует «неверному запросу»
403permission_errorЗапрос отклонён модерацией провайдера или доступ к модели запрещён
404not_found_errorЭндпоинт или ресурс не найден
429rate_limit_errorПревышен лимит запросов
503overloaded_errorНет доступных провайдеров для модели
5xxapi_errorПрочие ошибки шлюза LLMost или апстрима

429 бывает двух видов

Строка rate_limit_error в таблице описывает лимит апстрима: такой ответ проходит через маппинг ошибок и приезжает в антропиковском конверте. Но 429 может вернуть и собственный лимитер LLMost — до того, как запрос вообще дойдёт до модели. Он отвечает своим общим для всего API форматом, без антропиковского конверта:

{
  "error": "Слишком много попыток проверки. Попробуйте позже.",
  "code": "RATE_LIMITED",
  "retryAfter": 42
}

Здесь error — строка, а не объект, error.type отсутствует, зато есть code: "RATE_LIMITED", поле retryAfter (в секундах) и заголовок Retry-After. Клиентам, которые разбирают тело 429, стоит быть готовыми к обоим формам: определяйте превышение лимита по HTTP-статусу 429, а паузу берите из Retry-After.

402 в антропиковском конверте

Обратите внимание: несмотря на то, что HTTP-статус 402 семантически ближе к отдельной категории, в антропиковском протоколе для него нет отдельного error.type — LLMost возвращает invalid_request_error с понятным русским сообщением о нехватке средств. Определяйте нехватку баланса по HTTP-статусу 402, а не по error.type.

Ограничения совместимости

count_tokens не поддерживается

Эндпоинт POST /v1/messages/count_tokens из Anthropic Messages API не реализован. Так как у LLMost нет отдельного роута под этот путь, запрос падает на стандартный 404-обработчик Hono — в ответ приходит обычный текст 404 Not Found, а не JSON в антропиковском конверте ошибок ({"type":"error",...}) и не с Content-Type: application/json. Если ваш клиент парсит тело ошибки как JSON, будьте готовы обработать этот случай отдельно (например, по Content-Type или на try/catch вокруг JSON.parse). Если вам нужна оценка количества токенов до отправки запроса, используйте токенизатор на своей стороне или ориентируйтесь на usage из предыдущих ответов.

Следующие шаги

POST /v1/messages | Документация | LLMost