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: фактически списанная сумма в рублях, уже с учётом наценки LLMostcost_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 | Причина |
|---|---|---|
| 400 | invalid_request_error | Невалидный запрос — отсутствуют обязательные поля, модель не найдена |
| 401 | authentication_error | Недействительный или отсутствующий API-ключ |
| 402 | invalid_request_error | Недостаточно средств на балансе — сообщение на русском, тип по протоколу Anthropic соответствует «неверному запросу» |
| 403 | permission_error | Запрос отклонён модерацией провайдера или доступ к модели запрещён |
| 404 | not_found_error | Эндпоинт или ресурс не найден |
| 429 | rate_limit_error | Превышен лимит запросов |
| 503 | overloaded_error | Нет доступных провайдеров для модели |
| 5xx | api_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 из предыдущих ответов.
Следующие шаги
- Ознакомьтесь с Аутентификацией для безопасной работы с ключами
- Изучите Обработку ошибок — общий формат для остального API LLMost
- Для запросов в формате OpenAI Responses API — POST /v1/responses
- Для классического формата чата — POST /chat/completions