# OpenRouter: один API ко всем моделям. Гайд 2026

> Как работает OpenRouter: единый API к 400+ моделям, комиссия 5,5% при пополнении, provider routing, fallback, ZDR, BYOK и ловушки с оплатой.
> Author: Roman Belov · Published: 2026-10-26 · Source: https://futurecraft.pro/ru/blog/openrouter-guide/

OpenRouter - облачный шлюз к языковым моделям: один OpenAI-совместимый API и один баланс кредитов открывают сотни моделей разных лабораторий, от Claude и GPT до открытых Qwen, DeepSeek и Gemma. Модель задаётся строкой вида `anthropic/claude-haiku-5.5`, а запрос OpenRouter направляет одному из провайдеров, которые эту модель обслуживают. На цены инференса наценки нет, комиссию берут при пополнении баланса. Сам OpenRouter в [объявлении от 19 августа 2026 года](https://openrouter.ai/blog/announcements/openrouter-is-joining-stripe/) писал о 400+ моделях и 10+ млн разработчиков.

Первый запрос делается сменой `base_url`. Сложности начинаются с денег и маршрутизации. Пополнение на $5 стоит $0,80 комиссии. Цепочка fallback «сначала бесплатная модель, потом платная» по факту оказывается платной. Одна и та же открытая модель у разных провайдеров работает в разной квантизации и с разным набором параметров, а запрос с `tool_choice` может попасть к провайдеру, который этот параметр молча проигнорирует.

Статья о том, как устроены каталог и провайдеры OpenRouter, сколько реально стоит пополнение, как управлять выбором провайдера и fallback, что происходит с данными и кэшем и как подключить Claude Code, OpenCode и Codex CLI. Поведение API проверено 7 ноября 2026 года на ключе с лимитом $5: скрипт на стандартной библиотеке Python, `POST /api/v1/chat/completions`, короткий промпт и `max_tokens: 30`. Все проверки вместе стоили $0,0018. Комиссию пополнения, BYOK, ZDR и Claude Code через OpenRouter в проверке не трогали, они описаны по документации.

## Что такое OpenRouter и когда он нужен

OpenRouter закрывает четыре задачи. Даёт один API-формат ко многим лабораториям: код на OpenAI SDK переключается между Claude, GPT и Qwen сменой строки модели. Держит один баланс и один счёт вместо аккаунтов у каждого вендора. Переключается между провайдерами одной модели и, если попросить, между разными моделями. И показывает расход по ключам, моделям и провайдерам в одном месте.

| | OpenRouter | Прямой API провайдера | LiteLLM Proxy |
|---|---|---|---|
| Где работает | Облако OpenRouter | Облако провайдера | Ваш сервер |
| Ключи | Один ключ OpenRouter (или свои через BYOK) | Ключ на каждого вендора | Ключи провайдеров у вас, виртуальные ключи для команды |
| Оплата | Кредиты, комиссия при пополнении | Счёт у каждого вендора | Счета провайдеров, софт бесплатный |
| Fallback между лабораториями | Да, параметр `models` | Нет | Да, в `config.yaml` |
| Данные | Через OpenRouter и выбранного провайдера | Только провайдер | Через ваш хост и провайдера |
| Что обслуживать | Ничего | Ничего | Сервер, базу, обновления |

Прямой API выгоднее, когда работаете с одним вендором и вам нужны его функции в день выхода, без комиссии и без лишнего хопа: как устроен API Anthropic напрямую, разобрано в [гайде по Claude API](https://futurecraft.pro/ru/blog/claude-api-developer-guide/). Self-hosted шлюз нужен, когда ключи провайдеров не должны покидать ваш контур или нужны бюджеты на каждого сотрудника, об этом [гайд по LiteLLM](https://futurecraft.pro/ru/blog/litellm-guide/). Где шлюз стоит в архитектуре с несколькими провайдерами, описано в статье [о провайдерах LLM в production](https://futurecraft.pro/ru/blog/multi-provider-llm-architecture/).

## Модели и провайдеры: как устроен каталог

Каталог доступен без ключа: `GET https://openrouter.ai/api/v1/models`. На 7 ноября 2026 года в нём 460 записей, включая варианты `:free` и `:batch` и служебные роутеры. Больше всего моделей у openai (98), google (43), qwen (43) и anthropic (30). Число меняется почти каждый день.

Идентификатор модели - `vendor/model`. Кроме конкретных версий есть алиасы с тильдой: `~anthropic/claude-sonnet-latest` всегда указывает на новейшую модель семейства ([latest resolution](https://openrouter.ai/docs/guides/routing/routers/latest-resolution)). Алиас удобен для прототипа, для production версию лучше закрепить, чтобы поведение не поменялось без вашего релиза.

К идентификатору добавляют суффиксы. По [FAQ](https://openrouter.ai/docs/faq) они бывают двух видов:

| Суффикс | Вид | Что делает |
|---|---|---|
| `:free` | Каталожный | Бесплатная версия модели, отдельная запись со своими лимитами |
| `:batch` | Каталожный | Пакетная обработка, у Claude 5.5 вдвое дешевле |
| `:nitro` | Маршрутный | Провайдеры по скорости (throughput) плюс priority-эндпоинты |
| `:floor` | Маршрутный | Провайдеры по цене плюс flex-эндпоинты |
| `:exacto` | Маршрутный | Порядок провайдеров по надёжности tool calling |
| `:online` | Маршрутный, устарел | Веб-поиск в промпте; вместо него серверный инструмент `openrouter:web_search` |

Каталожные варианты есть только у моделей, где они перечислены в `/models`. Маршрутные работают на любой модели.

### Одна модель, разные провайдеры

Большинство моделей обслуживают несколько провайдеров, и у каждого свой эндпоинт. Список виден без ключа: `GET /api/v1/models/<vendor>/<model>/endpoints`. Для открытых моделей разница между провайдерами бывает существенной.

Снимок для `qwen/qwen3-coder` на 7 ноября 2026 года:

| Провайдер | Квантизация | Цена за 1M (вход / выход) | Параметров | `tool_choice` | Контекст |
|---|---|---|---|---|---|
| DeepInfra | fp4 | $0,30 / $1,00 | 15 | none, auto, required, function | 262 144 |
| Venice | fp8 | $0,35 / $1,50 | 11 | только none и auto | 256 000 |

`logit_bias`, `min_p`, `repetition_penalty` и `seed` из этих двух провайдеров есть только у DeepInfra. Если запрос с `tool_choice: "required"` попадёт к Venice, ошибки не будет: по документации без специальных настроек неподдерживаемый параметр просто игнорируется.

У закрытых моделей разброс меньше, но он есть. Haiku 5.5 на ту же дату обслуживали Anthropic, Amazon Bedrock, Google Vertex, Azure и Claude Platform on AWS. Глобальные эндпоинты стоили $0,10 за 1M входных токенов, региональные (`google-vertex/europe`, `amazon-bedrock/eu-west-1` и другие) - $0,11.

## Быстрый старт: первый запрос

Нужны аккаунт и ключ на [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys), ключ имеет вид `sk-or-v1-...`. Базовый адрес API - `https://openrouter.ai/api/v1`. OpenRouter реализует OpenAI-совместимые `/chat/completions`, `/completions` и `/responses` ([FAQ](https://openrouter.ai/docs/faq)); примеры в [Quickstart](https://openrouter.ai/docs/quickstart) теперь написаны на `/responses`, но `/chat/completions` работает так же.

### curl

```bash
curl https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer $OPENROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "HTTP-Referer: https://example.com" \
  -H "X-OpenRouter-Title: My App" \
  -d '{
    "model": "anthropic/claude-haiku-5.5",
    "max_tokens": 30,
    "messages": [{"role": "user", "content": "Reply with exactly: ok"}]
  }'
```

Заголовки `HTTP-Referer` и `X-OpenRouter-Title` необязательны: они нужны для атрибуции приложения в рейтингах openrouter.ai. Старое имя `X-Title` по [документации](https://openrouter.ai/docs/app-attribution) тоже принимается.

### OpenAI SDK

```python
import os
from openai import OpenAI

client = OpenAI(
    base_url="https://openrouter.ai/api/v1",
    api_key=os.environ["OPENROUTER_API_KEY"],
)

resp = client.chat.completions.create(
    model="anthropic/claude-haiku-5.5",
    max_tokens=30,
    messages=[{"role": "user", "content": "Reply with exactly: ok"}],
)
print(resp.choices[0].message.content)
```

В TypeScript то же самое: `baseURL: "https://openrouter.ai/api/v1"` в конструкторе `OpenAI`. Параметры, которых нет в OpenAI SDK (`models`, `provider`), передаются через `extra_body`, пример ниже в разделе про fallback.

### Что приходит в ответе

Кроме обычных полей OpenAI-формата в ответе есть `provider` (кто реально обслужил запрос), `model` (какая модель ответила, важно при fallback) и `usage.cost` (стоимость в долларах). По [документации usage accounting](https://openrouter.ai/docs/guides/guides/usage-accounting) на 7 ноября `usage` с `cost` приходит в каждом ответе, параметр `usage: {include: true}` устарел и ни на что не влияет.

**Проверено:** 7 ноября 2026 года, `anthropic/claude-haiku-5.5`, промпт «Reply with exactly: ok». Ответ «ok» пришёл за 1,05 с, провайдер `Claude Platform on AWS`, 18 входных и 4 выходных токена, `cost` $0,0000038. Это сходится с ценой $0,10 / $0,50 за 1M токенов. Расход в `GET /api/v1/key` сразу после проверок показывал 0 и обновился через несколько минут.

## Цены и комиссия OpenRouter

Цены моделей OpenRouter передаёт от провайдеров без изменений, в [FAQ](https://openrouter.ai/docs/faq) это сказано прямо: наценки на инференс нет. Платформа зарабатывает на комиссии при покупке кредитов.

| Тариф | Комиссия при пополнении | BYOK | Лимиты |
|---|---|---|---|
| Free | Не применяется | Нет | 50 запросов в сутки, только бесплатные модели |
| Standard | 5,5%, минимум $0,80; крипто 5% без минимума | $25 000 в месяц по прайсу без комиссии, сверх - 5% | Pay-as-you-go |
| Business | 8% | Как у Standard | Pay-as-you-go |
| Enterprise | По договору | Индивидуально | По договору |

Проценты 5,5% и 8% взяты со [страницы Pricing](https://openrouter.ai/pricing), минимум $0,80 и 5% для крипто - из [поста о комиссии](https://openrouter.ai/blog/announcements/simplifying-our-platform-fee/) (обновлён 11 июня 2026 года), условия на ноябрь 2026 года. Фактическое списание проверить не удалось: на аккаунте, где шли проверки, уже был баланс, нового пополнения не было.

Из-за минимума в $0,80 эффективная ставка зависит от суммы:

| Пополнение | Комиссия | Эффективно |
|---|---|---|
| $5 | $0,80 | 16% |
| $10 | $0,80 | 8% |
| $25 | $1,38 | 5,5% |
| $100 | $5,50 | 5,5% |
| $1000 | $55,00 | 5,5% |

Ещё несколько условий из [Terms](https://openrouter.ai/terms) (редакция от 31 августа 2026 года). Одна покупка - от $5 до $25 000. Возврат неиспользованных кредитов можно запросить только в течение 24 часов после оплаты, комиссия не возвращается, криптоплатежи не возвращаются никогда. Неиспользованные кредиты OpenRouter вправе списать через 365 дней после покупки. Пополнять на год вперёд невыгодно.

### Цены Claude 5.5 и Fable 5.1 в каталоге

На 7 ноября 2026 года, за 1M токенов:

| Модель | Вход | Выход | Чтение кэша |
|---|---|---|---|
| Fable 5.1 | $10 | $50 | $0,25 |
| Opus 5.5 | $4 | $20 | $0,20 |
| Sonnet 5.5 | $2 | $10 | $0,10 |
| Haiku 5.5 | $0,10 | $0,50 | $0,01 |

У всех четырёх есть `:batch`-варианты вдвое дешевле. Как считать стоимость не за токен, а за успешно решённую задачу, разобрано в статье [об оптимизации LLM-расходов](https://futurecraft.pro/ru/blog/ai-cost-optimization/).

## Provider routing: как выбрать провайдера

Если провайдер не указан, OpenRouter выбирает его сам. Алгоритм по умолчанию учитывает цену и стабильность провайдеров и меняется: на момент проверки 7 ноября [документация](https://openrouter.ai/docs/guides/routing/provider-selection) описывает его как сравнение эффективной цены, скорости, времени до первого токена, частоты 429 и ошибок и качества tool calls. При ошибке провайдера запрос автоматически уходит к следующему. Задать `sort`, `order`, `:nitro`, `:floor` или собственный ключ провайдера значит отключить алгоритм по умолчанию.

Управляет выбором объект `provider` в теле запроса:

| Поле | По умолчанию | Что делает |
|---|---|---|
| `order` | - | Список провайдеров по порядку |
| `allow_fallbacks` | `true` | При `false` только провайдеры из `order`, иначе ошибка |
| `only` / `ignore` | - | Белый и чёрный списки провайдеров |
| `sort` | - | `price`, `throughput` или `latency` |
| `quantizations` | - | Фильтр: `int4`, `int8`, `fp4`, `fp8`, `fp16`, `bf16`, `unknown` и другие |
| `require_parameters` | `false` | Только провайдеры, которые поддерживают все параметры запроса |
| `data_collection` | `"allow"` | `"deny"` исключает провайдеров, которые хранят данные и могут обучаться на них |
| `zdr` | - | Только ZDR-эндпоинты |
| `max_price` | - | Потолок цены за 1M токенов; если никто не подходит, запрос падает |
| `preferred_min_throughput`, `preferred_max_latency` | - | Мягкие пороги скорости, медленных опускают в списке, но не исключают |

Пример: только fp8, не дороже $1 за 1M входных и $2 за 1M выходных токенов.

```json
{
  "model": "qwen/qwen3-coder",
  "messages": [{"role": "user", "content": "Reply with exactly: ok"}],
  "provider": {
    "quantizations": ["fp8"],
    "max_price": {"prompt": 1, "completion": 2}
  }
}
```

**Проверено:** 7 ноября 2026 года, `qwen/qwen3-coder`, тот же короткий промпт.

| Запрос | Провайдер | cost, $ |
|---|---|---|
| `sort: "price"` | DeepInfra | 0,0000059 |
| `sort: "throughput"` | DeepInfra | 0,0000059 |
| `quantizations: ["fp8"]` | Venice | 0,00000755 |

Без фильтра запрос ушёл на DeepInfra, у которого по `/endpoints` квантизация fp4. С фильтром `fp8` его обслужил Venice, и запрос стал на 28% дороже. У открытой модели от квантизации зависит качество ответа, поэтому её лучше задавать явно.

### Ошибка 404 и routing_funnel

Ошибки маршрутизации OpenRouter описывает подробно, это помогает при отладке.

**Проверено:** 7 ноября 2026 года, `anthropic/claude-haiku-5.5`, `provider: {only: ["nonexistent-provider"], allow_fallbacks: false}`. Ответ 404, в `metadata` список провайдеров модели (`google-vertex`, `claude-on-aws`, `azure`, `anthropic`, `amazon-bedrock`), `routing_funnel` по шагам и `failed_routing_step`. Воронка: 10 эндпоинтов, после фильтра региональной наценки 5, после фильтра провайдеров 0. В ошибке виден полный ID модели: `anthropic/claude-haiku-5.5-20261007`.

По воронке сразу видно, на каком фильтре отвалился маршрут: опечатка в slug провайдера, слишком жёсткий `max_price` или настройки приватности аккаунта.

## Model fallbacks и Auto Router

Fallback между провайдерами одной модели включён по умолчанию. Fallback между разными моделями задаётся списком `models` в порядке приоритета ([model fallbacks](https://openrouter.ai/docs/guides/routing/model-fallbacks)). Следующая модель пробуется при любой ошибке первой: превышение контекста, отказ модерации, rate limit, недоступность. Стоимость считается по модели, которая ответила, её имя приходит в поле `model`.

С OpenAI SDK список передают через `extra_body`. Модель из `model` пробуется первой, `models` - запасные по порядку:

```python
resp = client.chat.completions.create(
    model="anthropic/claude-haiku-5.5",
    messages=[{"role": "user", "content": "Reply with exactly: ok"}],
    extra_body={
        "models": ["anthropic/claude-sonnet-5.5"],  # запасные модели по порядку
    },
)
print(resp.model)  # какая модель ответила на самом деле
```

**Проверено:** 7 ноября 2026 года. Запрос с `models: ["nonexistent-vendor/no-such-model", "anthropic/claude-haiku-5.5"]` вернул 400 «is not a valid model ID». Список моделей валидируется до маршрутизации: опечатка в первой модели не уходит в fallback, а роняет весь запрос. Два запроса подряд с `models: ["google/gemma-4-26b-a4b-it:free", "anthropic/claude-haiku-5.5"]` оба вернули 200 от `anthropic/claude-haiku-5.5` по $0,0000038 каждый: бесплатная модель в этот момент была ограничена у провайдера, и запрос молча ушёл на платную.

Документация об этом предупреждает: если в `models` за `:free` стоит платная модель, при fallback списывается цена платной. Чтобы запрос гарантированно остался бесплатным, в списке должны быть только `:free`-модели, либо используют роутер `openrouter/free`, который переключается только между бесплатными. В логах приложения стоит писать `model` из ответа, иначе переход на запасную модель останется незамеченным.

Для Anthropic-формата (`/api/v1/messages`) вместо `models` есть параметр `fallbacks`: не больше 3 записей, у каждой только поле `model`, совмещать с `models` нельзя, нарушение любого правила даёт 400.

### Auto Router

Auto Router (`openrouter/auto`) выбирает модель сам под каждый запрос. Дополнительной платы за роутер нет, списывается цена выбранной модели, `provider.max_price` продолжает действовать. Роутеры OpenRouter обновляет часто: на 7 ноября в каталоге несколько записей с префиксом `openrouter/` (`auto`, `auto-code`, `free` и другие), а [страница Auto Router](https://openrouter.ai/docs/guides/routing/routers/auto-router) описывает уже новое поколение с параметром `cost_tier`. В проверке Auto Router не запускался. Для предсказуемых расходов в production модель лучше задавать явно.

## Бесплатные модели (`:free`)

Модели с суффиксом `:free` стоят $0, это отдельные записи каталога со своими лимитами и провайдерами. На 7 ноября 2026 года в каталоге 12 таких записей плюс роутер `openrouter/free`. Лимиты по [документации](https://openrouter.ai/docs/api-reference/limits):

| Куплено кредитов за всё время | Запросов в минуту | Запросов в сутки |
|---|---|---|
| Меньше 10 | 20 | 50 |
| От 10 | 20 | 1000 |

Текущий дневной счётчик отдаёт `GET /api/v1/key` в поле `free_model_daily_requests`. Порог записан в документации с оговоркой: чтобы покрыть округление и комиссию, высокий дневной лимит включается на один кредит раньше. При отрицательном балансе ошибки возможны и на бесплатных моделях.

**Проверено:** 7 ноября 2026 года, `google/gemma-4-26b-a4b-it:free`. Ответ 429 «temporarily rate-limited upstream», `limit_source: upstream_provider_shared_pool`, провайдер Google AI Studio. В `remedy_hint` совет подключить свой ключ (BYOK) или выбрать другого провайдера. Заголовков `X-RateLimit-*` в ответе не было.

429 на `:free` возникает и тогда, когда личный лимит не исчерпан: пул бесплатной модели у провайдера общий, и личный счётчик здесь ничего не объяснит. Для чего-то кроме экспериментов бесплатные модели ненадёжны. Учтите и приватность: настройка, разрешающая провайдеров, которые обучаются на данных, в аккаунте задаётся отдельно для платных и бесплатных моделей ([provider logging](https://openrouter.ai/docs/guides/privacy/provider-logging)).

## BYOK: свои ключи провайдеров

BYOK (bring your own key) - подключение собственного ключа провайдера, например Anthropic или Bedrock. Запросы по-прежнему идут через API OpenRouter, но инференс оплачивается на вашем аккаунте у провайдера, и rate limits тоже ваши. По [документации BYOK](https://openrouter.ai/docs/use-cases/byok) и Pricing на тарифах Standard и Business первые $25 000 в месяц по прайс-листу проходят без комиссии, сверх этого с кредитов OpenRouter списывается 5% от стоимости такого же запроса. На тарифе Free BYOK нет. В старых сводках встречается правило «1 млн BYOK-запросов в месяц бесплатно», его заменили лимитом по стоимости.

Две детали, которые влияют на счёт:

- **Shared capacity fallback.** По умолчанию, если ваш ключ упёрся в лимит или вернул ошибку, OpenRouter переходит на свои эндпоинты и тратит кредиты. Чтобы этого не было, в настройках ключа выбирают «Never use shared capacity».
- **Приоритет.** Ключи бывают Prioritized (пробуются до эндпоинтов OpenRouter) и Fallback (после них). Без `order` в запросе провайдеры, для которых есть ваш Prioritized-ключ, идут первыми.

BYOK в проверке не тестировался: для него нужен отдельный ключ провайдера.

## Приватность, логирование и ZDR

По [FAQ](https://openrouter.ai/docs/faq) OpenRouter логирует метаданные запроса (время, модель, число токенов), а промпты и ответы не сохраняет, если вы сами не включили логирование. За включённое логирование OpenRouter даёт скидку 1% на использование.

Запрос при этом уходит провайдеру, и у каждого провайдера своя политика. Документация [ZDR](https://openrouter.ai/docs/guides/features/zdr) на 7 ноября делит эндпоинты на три уровня:

| Уровень | Что с данными |
|---|---|
| ZDR (Zero Data Retention) | Промпты и ответы после обработки обычно не хранятся |
| Safety Retention | Провайдер или OpenRouter может хранить данные только для борьбы со злоупотреблениями, без обучения |
| Retention and Training | Хранение по политике провайдера, возможно обучение |

Как ограничить маршрут:

- `provider.zdr: true` в запросе: только ZDR-эндпоинты (и Safety Retention, если аккаунт их разрешает).
- `provider.data_collection: "deny"`: без провайдеров, которые собирают данные.
- Настройки приватности аккаунта или guardrails: режим ZDR only, запрет обучения. Если вы задали `provider`, а под настройки аккаунта не подходит ни один провайдер, запрос завершится ошибкой.

У self-serve аккаунтов по умолчанию разрешён Safety Retention, у Enterprise только ZDR. ZDR распространяется на инференс, но не на плагины и серверные инструменты вроде веб-поиска: у них свои политики третьих сторон. На момент проверки страница ZDR также сообщает о скрининге всех запросов, включая ZDR-трафик, на CSAM; подозрительный контент может сохраняться для проверки. Для чувствительных данных политику конкретного эндпоинта стоит смотреть до отправки, а слой data policy держать на стороне приложения, как в [архитектуре с несколькими провайдерами](https://futurecraft.pro/ru/blog/multi-provider-llm-architecture/).

## Кэширование промптов через OpenRouter

Кэш промптов работает у провайдера, поэтому повторный запрос должен попасть к тому же провайдеру. Для этого OpenRouter использует sticky routing ([prompt caching](https://openrouter.ai/docs/guides/best-practices/prompt-caching)). Он включается, только если чтение кэша у провайдера дешевле обычного входа, и не работает при ручном `provider.order`. Разговор определяется по хэшу первого system- и первого не-system сообщения либо по явному `session_id` в теле или заголовке `x-session-id` (до 256 символов). По документации на 7 ноября сессия живёт 60 минут без запросов.

Правила по провайдерам разные:

| Провайдер | Как включается | Запись в кэш | Чтение |
|---|---|---|---|
| Anthropic | Явно, `cache_control` (на блоке или на верхнем уровне запроса) | 1,25x входа (TTL 5 минут), 2x (TTL 1 час) | 0,1x входа; у Opus 5.5 и Sonnet 5.5 0,05x, у Fable 5.1 0,025x |
| OpenAI | Автоматически от 1024 токенов | Бесплатно у моделей до GPT-5.6, у GPT-5.6 и новее 1,25x (TTL 30 минут) или 2,5x (12 часов) | 0,1x или 0,05x входа у GPT-6 и GPT-6.1, у более старых моделей 0,25x или 0,5x |
| Alibaba Qwen | Явно, `cache_control` | 1,25x, TTL 5 минут | 0,1x входа |

Gemini, DeepSeek и формула окупаемости кэша разобраны в [статье о prompt caching у разных вендоров](https://futurecraft.pro/ru/blog/prompt-caching/).

Минимальная длина кэшируемого промпта у Claude 5.5 и Fable 5.1 - 512 токенов. Пример с кэшем на system-промпте:

```json
{
  "model": "anthropic/claude-haiku-5.5",
  "messages": [
    {"role": "system", "content": [
      {"type": "text", "text": "<длинная инструкция или документ>",
       "cache_control": {"type": "ephemeral"}}
    ]},
    {"role": "user", "content": "Reply with exactly: ok"}
  ]
}
```

### Сколько экономит кэш: проверка на Haiku 5.5

**Проверено:** 7 ноября 2026 года, `anthropic/claude-haiku-5.5`, system-промпт на 12 635 токенов с `cache_control: {type: "ephemeral"}`, два одинаковых запроса с паузой 2 с.

| Запрос | cached_tokens | cost, $ | Время, с |
|---|---|---|---|
| Первый (запись в кэш) | 0 | 0,00158 | 1,51 |
| Второй (чтение) | 12 619 | 0,00013 | 1,41 |

Второй запрос дешевле первого в 12 раз. Первый дороже обычного: 12 635 токенов по $0,10 за 1M дали бы $0,00126, а списано $0,00158, это надбавка 1,25x за запись в кэш. Оба запроса обслужил один провайдер, без этого чтение из кэша не случилось бы.

Кэш окупается со второго попадания, а промпт, который отправляется один раз, с `cache_control` стоит на 25% дороже. Метрики кэша приходят в `usage.prompt_tokens_details.cached_tokens` и `cache_write_tokens`. Как устроено кэширование на стороне Anthropic, описано в [гайде по Claude API](https://futurecraft.pro/ru/blog/claude-api-developer-guide/).

## Tool calling и structured outputs: что различается

По каталогу на 7 ноября `tools` поддерживают 398 записей из 460, `tool_choice` - 393, `structured_outputs` - 387, `response_format` - 401. Это поддержка у модели в целом. У конкретного провайдера набор может быть уже, как у Venice для Qwen3 Coder.

По [документации](https://openrouter.ai/docs/guides/routing/provider-selection) `tools`, формат ответа (`response_format`, structured outputs) и `verbosity` работают как мягкие предпочтения: если у модели есть провайдеры с поддержкой, запрос пойдёт к ним. Остальные параметры при `require_parameters: false` неподдерживающий провайдер просто игнорирует. Чтобы запрос шёл только к провайдерам, которые поддерживают все его параметры, ставят `require_parameters: true`.

```json
{
  "model": "qwen/qwen3-coder",
  "messages": [{"role": "user", "content": "What time is it?"}],
  "tools": [{"type": "function", "function": {
    "name": "get_time", "parameters": {"type": "object", "properties": {}}}}],
  "tool_choice": "required",
  "provider": {"require_parameters": true}
}
```

**Проверено:** 7 ноября 2026 года, `qwen/qwen3-coder`, один инструмент `get_time`, `tool_choice: "required"`, `provider: {require_parameters: true}`. Ответ 200, провайдер DeepInfra, в ответе есть `tool_calls`. Это совпадает с данными `/endpoints`: у Venice `tool_choice: required` не поддерживается, у DeepInfra поддерживается.

Для агентов, которые опираются на tool calls, `require_parameters: true` - разумное значение по умолчанию. Альтернатива - суффикс `:exacto`, который упорядочивает провайдеров по надёжности tool calling; в проверке он не запускался.

## Подключение агентов: Claude Code, OpenCode, Codex CLI

### Claude Code

По [официальной инструкции OpenRouter](https://openrouter.ai/docs/cookbook/coding-agents/claude-code-integration) Claude Code подключается переменными окружения, без локального прокси: OpenRouter принимает Anthropic Messages API.

```bash
export ANTHROPIC_BASE_URL="https://openrouter.ai/api"
export ANTHROPIC_AUTH_TOKEN="$OPENROUTER_API_KEY"
export ANTHROPIC_API_KEY=""            # явно пустая, иначе конфликт
# необязательно: закрепить модели по классам
export ANTHROPIC_DEFAULT_SONNET_MODEL="~anthropic/claude-sonnet-latest"
export ANTHROPIC_DEFAULT_HAIKU_MODEL="~anthropic/claude-haiku-latest"
claude
```

Если раньше вы входили в Claude Code через аккаунт Anthropic, один раз нужен `/logout`, иначе кэшированный вход конфликтует с ключом шлюза. Переменные кладут в профиль оболочки, а не в проектный `.env`: нативный установщик Claude Code его не читает. Подключение проверяют командой `/status`: строка Auth token должна называть `ANTHROPIC_AUTH_TOKEN`.

У схемы два предупреждения. В самой инструкции OpenRouter сказано, что работа гарантируется только с провайдером Anthropic first-party, и его советуют ставить первым в provider routing. А [документация Claude Code](https://code.claude.com/docs/en/llm-gateway) прямо пишет, что Anthropic не одобряет и не проверяет сторонние шлюзы и не поддерживает работу Claude Code с моделями не от Anthropic через любой шлюз. Официальной поддержки Anthropic у связки Claude Code и OpenRouter нет, она работает на ваш риск. В проверке для этой статьи Claude Code через OpenRouter не запускался. Что ещё есть у Claude Code с альтернативными провайдерами, разобрано в статье [Claude Code в России](https://futurecraft.pro/ru/blog/claude-code-russia/).

### OpenCode

В OpenCode OpenRouter - встроенный провайдер ([инструкция](https://openrouter.ai/docs/cookbook/coding-agents/opencode-integration)). В TUI выполняют `/connect`, выбирают OpenRouter и вводят ключ, затем `/models` выбирает модель. Дополнительные модели добавляют в `opencode.json` по их slug в OpenRouter. Конфигурация агента и тест моделей разобраны в [гайде по OpenCode](https://futurecraft.pro/ru/blog/opencode-guide/).

### Codex CLI

Codex CLI подключается блоком провайдера в `~/.codex/config.toml` ([инструкция](https://openrouter.ai/docs/cookbook/coding-agents/codex-cli)):

```toml
model_provider = "openrouter"
model = "<vendor/model из каталога>"

[model_providers.openrouter]
name = "openrouter"
base_url = "https://openrouter.ai/api/v1"

[model_providers.openrouter.auth]
command = "sh"
args = ["-c", "echo $OPENROUTER_API_KEY"]
```

Вариант `env_key = "OPENROUTER_API_KEY"` тоже работает, но тогда Codex не загружает каталог моделей OpenRouter и для моделей не от OpenAI показывает предупреждение о неизвестной модели.

## Лимиты и ошибки

| Код | Когда | Что делать |
|---|---|---|
| 400 | Невалидный ID модели (в том числе в `models`), лишние поля в `fallbacks` | Проверить ID по `/api/v1/models` |
| 402 | Не хватает кредитов или исчерпан in-flight budget | Смотреть `metadata.reason`, снизить `max_tokens`, пополнить |
| 404 | Ни один провайдер не прошёл фильтры (`only`, `max_price`, приватность) | Смотреть `routing_funnel` и `failed_routing_step` |
| 429 | Лимит `:free` или общий пул провайдера | Смотреть `limit_source`, повторить с backoff, добавить fallback |

In-flight budget ([limits](https://openrouter.ai/docs/api-reference/limits)) касается части предоплаченных аккаунтов с небольшим балансом и новых аккаунтов. OpenRouter резервирует оценённую стоимость идущих запросов, и при нехватке отвечает 402 даже при положительном балансе. `reason: "in_flight_budget_exhausted"` - временное состояние, ждут `Retry-After`. `reason: "weight_exceeds_budget"` - один запрос дороже всего бюджета, повтор не поможет, нужно уменьшить `max_tokens` или промпт.

Фиксированного RPM для платных моделей документация не называет: мощность управляется глобально, и дополнительные аккаунты или ключи лимит не увеличивают. 429 от провайдера OpenRouter сначала пытается обойти другими провайдерами той же модели и только потом возвращает клиенту. Расход и остаток лимита по ключу показывает `GET /api/v1/key`: поля `limit_remaining`, `usage_daily`, `usage_weekly`, `usage_monthly`. Лимит расходов можно задать на каждый ключ отдельно, это простой способ ограничить эксперимент или отдельный сервис.

## Ограничения OpenRouter и когда нужен другой инструмент

- **Данные проходят через третью сторону.** Даже с ZDR запрос идёт через серверы OpenRouter и провайдера. Если ключи и трафик должны оставаться в вашем контуре, нужен self-hosted шлюз вроде [LiteLLM](https://futurecraft.pro/ru/blog/litellm-guide/) или локальная модель: варианты собраны в [гайде по локальным LLM](https://futurecraft.pro/ru/blog/local-llm-guide/), запуск разобран в [гайде по Ollama](https://futurecraft.pro/ru/blog/ollama-guide/), выбор между двумя популярными программами - в [сравнении LM Studio и Ollama](https://futurecraft.pro/ru/blog/lm-studio-vs-ollama/).
- **Качество зависит от провайдера.** Квантизация и поддержка параметров различаются у провайдеров одной модели, а провайдер по умолчанию может смениться без вашего участия. Для воспроизводимости фиксируют `quantizations`, `order` или `only` и логируют `provider` из ответа.
- **Каталог меняется.** У моделей появляется `expiration_date`, цены и состав провайдеров меняются. Жёстко прописанный ID без мониторинга однажды начнёт возвращать ошибку.
- **Комиссия на мелких суммах.** Пополнение на $5 обходится в 16% сверху. Вернуть кредиты можно только в первые 24 часа, а неиспользованные могут сгореть через год.
- **Доступность по странам.** Ограничения по странам и организациям задают провайдеры моделей, а [Terms OpenRouter](https://openrouter.ai/terms) (п. 5.7) запрещают их обходить; условия стоит проверить до пополнения.
- **Один вендор и его новые функции.** Если работаете только с Anthropic или OpenAI и вам нужны свежие возможности API в день выхода, прямой API проще и дешевле на размер комиссии.

Как связать шлюз, fallback, evals и мониторинг в одну систему, описано в статье [Production LLM Stack](https://futurecraft.pro/ru/blog/production-llm-stack/).

## С чего начать

1. Создайте ключ на openrouter.ai и сразу задайте на нём лимит расходов.
2. Пополните баланс не меньше чем на $25, если планируете работать регулярно: на этой сумме комиссия выходит на 5,5%, а не 16%. Помните о 24 часах на возврат и сроке 365 дней.
3. Подключите OpenAI SDK сменой `base_url` и логируйте из каждого ответа `model`, `provider` и `usage.cost`.
4. Для открытых моделей посмотрите `/api/v1/models/<id>/endpoints` и зафиксируйте `quantizations` или `order`.
5. Для агентов и tool calls поставьте `provider.require_parameters: true`.
6. Для чувствительных данных включите режим ZDR only в настройках приватности или `provider.zdr: true` в запросах.
7. Длинные system-промпты к Claude отправляйте с `cache_control` и проверяйте `cached_tokens` во втором запросе.
