← Блог

Access denied by security policy: почему OpenRouter даёт 403

· 7 минут чтения · обновлено

Запрос упал с 403, следом в логах появился 402, а разработчик уже готов менять ключ и поднимать VPN. Я 22.09.2026 прогнал те же проверки руками с сервера в Нюрнберге, Германия, в дата-центре netcup: OpenRouter ответил JSON, а не страницей блокировки.

Если у вас пустой баланс и пополнить его нечем, рабочий маршрут — перенести запросы в altrouter. В коде меняются два поля: base_url и api_key; зарегистрироваться.

Сначала всё равно посмотрите на тело ответа. Один и тот же 403 может означать защитный HTML перед API или отказ самого приложения в JSON. Это разные проблемы, и новый ключ не поможет там, где запрос до API вообще не дошёл.

Проверка OpenRouter без ключа

Начал с запроса без авторизации. Модель здесь не играет роли: задача была проверить, кто именно отвечает на соединение.

curl -s https://openrouter.ai/api/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-5.6","messages":[{"role":"user","content":"hi"}]}'

Ответ:

HTTP 401, application/json:
{"error":{"message":"No cookie auth credentials found","code":401}}

401 — отказ по авторизации, а JSON показывает, что запрос дошёл до API. Если бы соединение оборвал защитный слой, вместо структурированной ошибки пришёл бы HTML.

Теперь подставил выдуманный ключ:

curl -s https://openrouter.ai/api/v1/chat/completions \
  -H "Authorization: Bearer sk-or-v1-0000" \
  -H "Content-Type: application/json" \
  -d '{"model":"openai/gpt-5.6","messages":[{"role":"user","content":"hi"}]}'

Ответ:

HTTP 401, application/json:
{"error":{"message":"User not found.","code":401}}

Снова JSON. Значит, сервер в Нюрнберге на 22.09.2026 не был отбит защитным слоем OpenRouter. Дополнительная проверка каталога вернула HTTP 200, application/json за 0,12 с.

curl https://openrouter.ai/api/v1/models

Это не доказывает, что любой запрос с любого адреса всегда пройдёт. Но для диагностики важнее другое: в конкретной точке и в конкретную дату сервис отвечал, а причина отказа находилась в теле ответа.

Дерево решений для ошибки 403, разделяющее проблему на сетевую блокировку при HTML-ответе и ошибку аккаунта при JSON-ответе.
Формат ответа — главный маркер. HTML указывает на проблемы с сетью, JSON — на настройки аккаунта.

Почему 403 бывает разным

403 Forbidden — только код статуса. Он не говорит, дошёл ли запрос до приложения.

Если тело ответа — JSON в формате ошибки API, проверяйте ключ, доступ к модели и баланс. Если тело — HTML с текстом Sorry, you have been blocked или access denied by security policy, запрос остановил защитный слой до обработки ключа.

Два ответа на один и тот же запрос к OpenRouter: сверху HTML-страница защитного фильтра с текстом Sorry, you have been blocked, снизу JSON-ошибка самого API
Статус одинаковый, причины разные. Сверху запрос до API не дошёл, снизу - дошёл и получил отказ по ключу.

HTML-блок я по этому замеру не воспроизвёл: с сервера в Нюрнберге OpenRouter вернул JSON. Но сама форма ответа известна, а типичные причины — VPN, адрес дата-центра и слишком высокая частота запросов с одного IP.

VPN здесь может быть причиной ошибки, а не лекарством. Выходные адреса массовых VPN получают плохую репутацию из-за парсеров и ботов. Адрес дата-центра тоже могут фильтровать строже, чем домашнее подключение.

Не смешивайте это с 429 Too Many Requests. 429 — JSON-ответ самого API при превышении лимита аккаунта, а HTML-страница означает, что до приложения запрос не дошёл.

402 insufficient credits: самая частая «блокировка»

Отдельный сценарий выглядит ещё убедительнее: API узнаёт ключ, но возвращает 402 insufficient credits. Это значит, что сервис работает, а денег на оплату токенов больше нет.

Летом 2026 года пользователи с российской географией аккаунта получали письма о прекращении поддержки платёжных методов. Предлагалось потратить оставшиеся кредиты или запросить возврат. Отключили платежи, а не доступ, поэтому интеграция могла продолжать работать до списания последнего остатка.

Так появляется отложенный сбой. Утром запросы проходят, к вечеру баланс достигает нуля, а приложение видит уже не временную сетевую проблему, а 402.

Посчитайте остаток и средний дневной расход. Остаток, делённый на расход, показывает примерный запас в днях — ваш технический дедлайн до следующего отказа.

График снижения баланса, который упирается в ноль и вызывает ошибку 402.
Отключение платежей имеет отложенный эффект: интеграция падает с ошибкой 402 только в момент полного исчерпания старых запасов.

Главный вывод простой: OpenRouter в России не заблокирован. Отключён приём платежей для аккаунтов с российской географией, поэтому проблема часто начинается не с маршрута и не с ключа, а с невозможности пополнить баланс.

Сбой может быть у вендора

OpenRouter работает как шлюз к моделям разных вендоров. Если сбоит один из них, ошибка может выглядеть как проблема самого OpenRouter.

Посмотрите текст ответа и попробуйте модель другого вендора. Если запрос к Gemini проходит, а запрос к Claude нет, менять весь шлюз необязательно: причина может находиться на стороне Anthropic.

Это место, где универсальный рецепт ломается. По одному статусу нельзя надёжно определить источник сбоя, поэтому проверяйте тело ответа и сравнивайте модели.

Чек-лист перед сменой интеграции

  1. Найдите тело ответа, а не только строку со статусом.
  2. 402 или insufficient credits — проверьте баланс и расход.
  3. JSON с 401 — проверьте ключ и аккаунт.
  4. HTML с 403 — проверьте VPN, адрес сервера и частоту запросов.
  5. Сравните запросы из двух точек: локальной и серверной.
  6. Если пополнить баланс нельзя, подготовьте второй маршрут через OpenAI-совместимый API.

Новый ключ не исправит HTML-блок. Смена DNS не добавит кредитов. В дебаге это две разные ветки, и смешивать их дорого по времени.

Последний запуск через altrouter

Я отправил тот же короткий вопрос через altrouter. В этом запросе использовал модель gemini-3.1-flash-lite.

curl -s https://api.altrouter.ai/v1/chat/completions \
  -H "Authorization: Bearer $ALTROUTER_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gemini-3.1-flash-lite","max_tokens":60,"messages":[{"role":"user","content":"Ответь одним словом: столица Франции?"}]}'

Ответ:

HTTP 200 за 6,8 с:
{"object":"chat.completion","model":"gemini-3.1-flash-lite","choices":[{"index":0,"message":{"role":"assistant","content":"Париж"},"finish_reason":"stop"}],"usage":{"prompt_tokens":96,"completion_tokens":3,"total_tokens":99}}

usage — блок, где API показывает расход токенов по запросу. Здесь всего 99 токенов: 96 входных и 3 выходных.

Для Python-клиента миграция выглядит так:

from openai import OpenAI

client = OpenAI(
    base_url="https://api.altrouter.ai/v1",   # было: https://openrouter.ai/api/v1
    api_key="ar-...",                          # было: sk-or-v1-...
)

r = client.chat.completions.create(
    model="gemini-3.1-flash-lite",
    messages=[{"role": "user", "content": "Ответь одним словом: столица Франции?"}],
)
print(r.choices[0].message.content)

base_url — адрес, куда SDK отправляет запрос. api_key — ключ авторизации, который передаётся этому адресу.

У altrouter на 22.09.2026 было 79 публичных моделей. Цена gemini-3.1-flash-lite — $0,225 за 1 млн входных токенов и $1,35 за 1 млн выходных против $0,25 и $1,50 у Google, то есть на 10% ниже официальной цены вендора.

Оплата доступна картой РФ, по СБП или криптовалютой. За подтверждённый Telegram на баланс начисляется $1 на пробу, а скидка на большинстве моделей составляет 10–15% от официальной цены вендора. Минус маршрута тоже нужно учитывать: конкретная модель или API может отсутствовать в каталоге.

Что у нас не заработает

Проверка 22.09.2026 показала, что POST https://api.altrouter.ai/v1/messages возвращает 404. Инструменты, которые жёстко используют Anthropic-формат и /v1/messages, не подключатся: рабочий интерфейс — OpenAI-совместимый /v1/chat/completions.

В каталоге было 79 моделей. DeepSeek среди публичных моделей нет, поэтому код, привязанный к конкретному имени модели, сначала нужно сверить с каталогом.

Этот маршрут не отменяет проверку совместимости. Если библиотека умеет менять base_url, использует OpenAI-формат и нужная модель есть в каталоге, достаточно заменить два поля.

Если остаётесь: чем пополнять

Для OpenRouter остаются зарубежная карта, платёжный посредник или криптовалюта. Комиссии и ограничения зависят от способа, а варианты пополнения собраны в статье как пополнить OpenRouter из России.

FAQ

sorry, you have been blocked you are unable to access openrouter.ai

Это HTML-страница защитного слоя, а не JSON-ответ API. Причиной могут быть VPN, адрес дата-центра или высокая частота запросов с одного IP.

openrouter forbidden: access denied by security policy

Так отвечает фильтр перед сервисом. Смотрите на точку выхода и сетевой адрес, а не выпускайте новый ключ вслепую.

access denied by security policy openrouter

HTML означает, что запрос остановили до приложения. JSON означает, что запрос дошёл до API и причину нужно искать в ключе, модели или балансе.

Заблокирован ли OpenRouter в России

Сам сервис не заблокирован, отключены платежи для аккаунтов с российской географией. Интеграция продолжает работать, пока на балансе остаются кредиты.

Что означает ошибка 403 у OpenRouter

403 может прийти от защитного слоя или самого приложения. Отличить причины помогает тело ответа: HTML указывает на сетевой фильтр, JSON — на ошибку API.

Поможет ли VPN, если OpenRouter не работает

VPN часто и вызывает HTML-403. Начните с запроса без него.