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

Как перейти с прямого Anthropic/OpenAI API на совместимый шлюз, не переписывая код

Короткий ответ: меняются две вещи — base_url и ключ. Всё остальное (структура запроса, SSE-стрим, tool calls) остаётся прежним, потому что совместимость здесь не «похожесть», а один и тот же протокол. Ниже — что именно совпадает, что не совпадает, где ломается Claude Code и как посчитать, сколько это экономит.

Какие три стены реально останавливают разработчика

Стен ровно три, и они независимы друг от друга. Когда разработчик ищет аналог Anthropic API, он в 9 случаях из 10 ищет не другую модель, а другой способ до неё дотянуться.

Почему Claude API не принимает карту

Биллинг Anthropic и OpenAI требует карты, выпущенной в поддерживаемой юрисдикции. Ситуация «Claude API не принимает карту» — это не баг и не временный сбой, а отказ на стороне платёжного процессинга. Перевыпуск карты, смена банка и повторные попытки её не лечат: проверяется страна эмитента.

Что означает region not supported в Claude

Даже с оплаченным аккаунтом запрос из неподдерживаемого региона получает region not supported. Claude отвечает не ошибкой модели, а отказом на уровне edge — до инференса дело не доходит. VPN формально решает задачу, но добавляет второй источник отказов: смена IP-адресов регулярно приводит к блокировке аккаунта. Для продакшена это неприемлемая архитектура: зависимость от компонента, который никто не поддерживает.

Почему прямой тариф дорог именно для кодинг-агента

Официальный тариф Claude Opus 5 — $5.00 за 1M входных токенов и $25.00 за 1M выходных. Для агента, который на каждом шаге перечитывает контекст репозитория, это набегает быстро. Причём основная строка счёта — не input и не output, а чтение кэша, о чём ниже будет отдельный расчёт с арифметикой.

Шлюз с совместимым протоколом закрывает все три стены сразу: платёж проходит рублями через СБП или криптовалютой, запрос идёт на домен без региональных ограничений — то есть Anthropic-совместимый API доступен из России и не требует зарубежной карты, — а цена по каждой модели опубликована рядом с официальным тарифом на странице цен.

Что значит «совместимый API» на уровне протокола

Слово «совместимый» в маркетинге означает что угодно. OpenAI-совместимый API и Anthropic-совместимый API — конкретное техническое утверждение: сервер принимает те же тела запросов и отдаёт те же тела ответов, что и вендорский. Проверяется оно этим списком.

Что совпадает дословно

ЧтоAnthropic-протоколOpenAI-протокол
EndpointPOST /v1/messagesPOST /v1/chat/completions
Авторизациязаголовок x-api-keyAuthorization: Bearer …
Поля запросаmodel, max_tokens, messagesmodel, max_tokens, messages
СтримингSSESSE (stream: true)
Tool callsподдерживаютсяподдерживаются
Стоимость запросаusage.cost_usdusage.cost_usd

То есть SDK от вендора работает как есть: anthropic для Python/JS и openai для Python/TS не различают, куда именно они стучатся, если сервер отвечает тем же контрактом. Никаких форков SDK, никаких прокси-обёрток, никакого переписывания слоя работы с LLM.

Дополнительно шлюз возвращает usage.cost_usd — фактическую стоимость запроса в долларах, в том числе в финальном usage-блоке SSE-стрима. Такого поля у вендоров нет, оно удобно для сверки биллинга прямо из кода.

Что не совпадает — список закрытый

Опубликованы три endpoint'а с ключом: /v1/messages, /v1/chat/completions, /v1/images/generations. И три без ключа: /status, /v1/models, /api/pricing.

Не опубликованы: Responses API (/v1/responses), embeddings, image edits, video, audio. Если ваш код использует client.responses.create(...) или client.embeddings.create(...) — это не мигрирует сменой base_url, это переписывается или остаётся у прежнего провайдера.

Media на вход не принимается. Изображения, PDF и любой бинарь в текстовых endpoint'ах дают 400 unsupported_content_type. Генерация изображений работает (/v1/images/generations), а вот vision-сценарий «отправить скриншот и спросить, что на нём» — нет. Это частая неожиданная поломка: мультимодальный вход легко спрятан внутри одной функции.

Как сменить base_url в Anthropic SDK

Один аргумент конструктора. Ниже диффы для Python и JS.

Python

Было (прямой вызов Anthropic):

from anthropic import Anthropic

client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])

Стало:

import os
from anthropic import Anthropic

client = Anthropic(
    base_url="https://go2llm.tech",
    api_key=os.environ["GO2LLM_API_KEY"],
)

msg = client.messages.create(
    model="claude-opus-5",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Привет"}],
)
print(msg.usage)  # у шлюза там ещё cost_usd

Обратите внимание на две детали. Первая: для Anthropic-протокола base URL указывается без /v1 — SDK добавит путь сам. Вторая: ключ шлюза имеет префикс gk_sk_…, он не взаимозаменяем с ключом вендора.

JavaScript / TypeScript

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

const client = new Anthropic({
  apiKey: "YOUR_API_KEY",
  baseURL: "https://go2llm.tech",
});

const response = await client.messages.create({
  model: "claude-sonnet-5",
  max_tokens: 120,
  messages: [{ role: "user", content: "Скажи OK" }],
});

console.log(response.content);

Проверка одним curl

Прежде чем трогать приложение, проверьте ключ:

curl https://go2llm.tech/v1/messages \
  -H "x-api-key: YOUR_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "content-type: application/json" \
  -d '{"model":"claude-sonnet-5","max_tokens":120,"messages":[{"role":"user","content":"Ответь одним словом: работает"}]}'

Заголовок anthropic-version: 2023-06-01 сохраняется — это часть протокола, а не привязка к вендору.

Как выглядит миграция с OpenAI API

Здесь base_url наоборот с /v1: https://go2llm.tech/v1. Путается это постоянно, поэтому запомните правило — Anthropic SDK сам дописывает /v1, OpenAI SDK ждёт его в base URL.

Python

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://go2llm.tech/v1",
)

response = client.chat.completions.create(
    model="gpt-5.6-sol",
    messages=[{"role": "user", "content": "Ответь: OK"}],
)

print(response.choices[0].message.content)

TypeScript со стримом

Стриминг — обычная точка, где «совместимый api» ломается у самодельных прокси. Здесь это тот же SSE, итератор SDK работает без изменений:

import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://go2llm.tech/v1",
  apiKey: process.env.GO2LLM_API_KEY,
});

const stream = await client.chat.completions.create({
  model: "gpt-5.6-sol",
  stream: true,
  messages: [{ role: "user", content: "Сгенерируй SQL" }],
});

for await (const chunk of stream) {
  process.stdout.write(chunk.choices[0]?.delta?.content ?? "");
}

Одна важная оговорка про надёжность стрима: до начала ответа шлюз может использовать совместимый fallback-маршрут на разрешённых классах ошибок, но после первого байта или валидного SSE-события переключение не выполняется. Поток нельзя автоматически повторить после получения первого валидного фрагмента — ретрай стрима должен быть решением вашего приложения, а не фоновой магией.

Как перевести Claude Code на другой endpoint

Три переменные окружения, никаких конфигов:

export ANTHROPIC_BASE_URL=https://go2llm.tech
export ANTHROPIC_AUTH_TOKEN=YOUR_API_KEY
export ANTHROPIC_MODEL=claude-sonnet-5
claude

Почему ANTHROPIC_AUTH_TOKEN, а не ANTHROPIC_API_KEY — и откуда берётся 401

Это главная ловушка миграции, и её почти никто не документирует.

Claude Code умеет аутентифицироваться двумя разными способами: по сохранённому логину (вы когда-то залогинились через claude.ai или Anthropic Console — креды лежат в профиле на машине) и по переданному токену. Эти два пути имеют разный приоритет.

Если на машине уже есть вход в Claude Code под личным аккаунтом, ANTHROPIC_API_KEY может уступить сохранённому логину, и запрос уйдёт мимо go2llm с 401.

Симптом выглядит абсурдно: вы выставили ANTHROPIC_BASE_URL, экспортировали ключ в ANTHROPIC_API_KEY, curl с тем же ключом отрабатывает отлично, а Claude Code возвращает 401. Причина в том, что клиент подставил не ваш ключ, а сохранённые OAuth-креды личного аккаунта — которые на стороннем base URL, разумеется, невалидны.

ANTHROPIC_AUTH_TOKEN ведёт себя иначе: он всегда обращается к указанному ANTHROPIC_BASE_URL с переданным значением. Сохранённый логин в эту цепочку не вмешивается.

Практический вывод:

  • Для стороннего base URL используйте ANTHROPIC_AUTH_TOKEN. Всегда.
  • ANTHROPIC_API_KEY оставьте пустым или не экспортируйте вовсе — одновременная установка обеих переменных создаёт ровно ту неоднозначность, из-за которой возникает 401.
  • Если 401 остался — проверьте ключ тем же curl из раздела выше. Если curl проходит, а клиент нет, дело в клиенте, а не в ключе.

Что с другими инструментами

ИнструментПротоколСтатус
Claude CodeAnthropic Messages✅ проверено живым запросом
OpenCodeOpenAI Chat Completions✅ проверено живым запросом
Kilo CodeOpenAI Chat Completions📄 по документации, вручную не тестировали
Cline / RooCode / Continue.dev / AiderOpenAI Chat Completions📄 работает, если клиент умеет свой base URL
Codex CLIOpenAI Responses✅ проверено живым запросом 2026-09-14: codex exec 0.151.0, модель qwen3-8-flash
Cursor—📄 живым запросом не проверяли

Общее правило: если клиент умеет свой base URL и говорит на одном из двух протоколов — он подключается. Если не умеет — нет, и настройками это не лечится.

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

Девять пунктов. Проходить до переключения трафика, а не после.

  1. Возьмите model ID из /v1/models, а не из памяти. Идентификаторы моделей в каталоге шлюза — свои (claude-opus-5, gpt-5.6-sol, gemini-3.8-flash). Ошибка в строке даёт 404 model_not_found. Каталог открыт без ключа:

``bash curl https://go2llm.tech/v1/models ``

  1. Сверьте endpoint с протоколом модели. В ответе /v1/models для каждой модели указаны модальности и endpoints. Вызов модели не по её протоколу возвращает 400 model_protocol_mismatch. Не угадывайте — читайте каталог.
  2. Проверьте, что в запросах нет media на вход. Любое изображение, аудио, видео или PDF в текстовом endpoint'е — 400 unsupported_content_type. Пройдитесь грепом по местам, где собирается content-массив.
  3. Добавьте обработку 402 insufficient_balance. Это новый для вас класс ошибок: у вендора с привязанной картой его не было. Реакция — пополнить баланс или уменьшить max_tokens. Баланс не уходит ниже нуля, поэтому 402 — штатное состояние, а не авария.
  4. Реализуйте backoff по 429 с учётом Retry-After. Дефолтный лимит на ключ — 20 RPM. Если ваш пайплайн шлёт параллельные запросы пачками, вы упрётесь в него на первом же прогоне. Слепой ретрай без задержки только усугубит ситуацию.
  5. Отделите 502 upstream_unavailable от логических ошибок. Повторять с задержкой безопасно — но только безопасный текстовый запрос. Media-запрос с ambiguous_upstream_result повторять автоматически нельзя: поставщик мог его принять, и повтор спишет деньги дважды.
  6. Выставьте лимит ключа. На каждый ключ настраиваются квота в долларах, список разрешённых моделей, IP allow-list и срок действия. Ключ, созданный в кабинете с пустым полем квоты, идёт без отдельного лимита — для прода это выставляется вручную в кабинете. Ключ с квотой 0 означает «без отдельного лимита», расход ограничен только балансом.
  7. Логируйте usage.cost_usd. Шлюз резервирует оценочную стоимость до вызова, затем списывает фактическую и освобождает остаток резерва. Сверка по cost_usd из ответа даёт вам собственную картину расходов, независимую от кабинета.
  8. Если используете генерацию изображений — добавьте Idempotency-Key. Для image-запросов он обязателен: 8–128 печатных ASCII, тело до 20 MiB, response_format: "url". Переиспользование одного ключа для разных тел даёт 409 idempotency_conflict.

Какие ошибки вы увидите и что каждая означает

Формат ошибки единый: error.type, error.code, error.message, error.request_id. Последнее поле сохраняйте в логи — по нему разбирают обращения.

HTTPКодЧто произошло на самом деле
400invalid_requestТело запроса не проходит валидацию: битый JSON или нет обязательного поля. Проверяется без обращения к модели.
400unsupported_content_typeВ текстовый endpoint попало изображение/аудио/видео/PDF. Уберите media из запроса.
400model_protocol_mismatchМодель вызвана не тем endpoint'ом. Возьмите правильный из /v1/models.
401no-keyКлюч не дошёл до сервера. В Claude Code — почти всегда та самая история с ANTHROPIC_API_KEY вместо ANTHROPIC_AUTH_TOKEN.
402insufficient_balanceНа балансе меньше, чем резерв под запрос. Пополнить или снизить max_tokens.
403model / inactive / expired / ipКлюч валиден, но настройки запрещают вызов: модель не в списке, ключ отключён, истёк срок или IP вне allow-list.
404model_not_foundОпечатка в model ID или устаревший каталог. Скопируйте точную строку из /v1/models.
409idempotency_conflictОдин Idempotency-Key отправлен с разными телами запроса.
429quota / rate_limitИсчерпана квота ключа либо превышен RPM. Читайте Retry-After.
502upstream_unavailableПроблема у внешнего поставщика. Безопасный текстовый запрос можно повторить с задержкой.
503product_paused / no_eligible_routeНет доступного маршрута или продукт на паузе. Смотрите /status, повторяйте позже.

Отдельный случай: 404 на /v1/responses — это не проблема ключа, а несовместимый протокол клиента. Подробный разбор кодов — в документации по ошибкам.

Чего в шлюзе нет — честно

Список короткий и закрытый. Если ваш сценарий попал сюда, сменой base_url вы не отделаетесь.

Responses API. Endpoint /v1/responses не опубликован. Код на client.responses.create() не заработает.

Embeddings. Нет. Векторизацию оставляйте у текущего провайдера или на локальной модели.

Media на вход. Есть генерация изображений, нет их разбора. Vision-пайплайн не мигрирует.

Fine-tuning. Нет. Шлюз отдаёт опубликованный каталог моделей, дообучение в него не входит.

Codex CLI. Подключается с 2026-09-14. Актуальные версии Codex CLI для кастомных провайдеров (model_providers в ~/.codex/config.toml) поддерживают только wire_api = "responses" — формат OpenAI Responses API; значение wire_api = "chat" сам Codex CLI отклоняет с ошибкой «no longer supported». Раньше маршрута /v1/responses у шлюза не было и Codex получал 404. Теперь он опубликован и проверен живым прогоном Codex CLI 0.151.0 на модели qwen3-8-flash: codex exec прочитал файл, исполнил инструменты и внёс правку. Интерактивный TUI codex мы не гоняли. Разбор целиком — на странице про Codex.

Ещё одно, что стоит знать заранее: интеграции за клиента не настраиваются. Документация есть, руки — ваши.

Сколько это экономит: считаем на профиле кодинг-агента

Сравнивать провайдеров по цене input — ошибка: у кодинг-агента распределение токенов другое. Реальный профиль нагрузки — вход 10%, выход 5%, чтение кэша 85%: агент на каждом шаге перечитывает тот же контекст репозитория, и тот приходит из кэша. Смешанная цена считается так:

mixed = input × 0.10 + output × 0.05 + cache_read × 0.85

Считаем обе стороны по одной формуле — иначе сравнение нечестное.

Claude Opus 5: две смешанные цены, шаг за шагом

Официальный тариф: input $5.00, output $25.00, cache read $0.50 за 1M токенов.

input:       5.00 × 0.10 = 0.500
output:     25.00 × 0.05 = 1.250
cache read:  0.50 × 0.85 = 0.425
                   mixed = 2.175  $ / 1M токенов

На 100M токенов смешанного трафика это $217.50 по официальному тарифу. По курсу ЦБ 86,3793 ₽ за $1 (01.09.2026) — примерно 18 787 ₽. Курс справочный: баланс и списания ведутся в USD.

Чтобы получить вторую половину сравнения, подставьте в ту же формулу три ставки шлюза со страницы цен. Смотреть надо именно на все три: экономия кодинг-агента решается строкой cache read, на которую приходится 85% объёма, а не строкой input, по которой обычно сравнивают.

Claude Sonnet 4.5: та же арифметика

Официальный тариф: $2.00 / $10.00 / $0.20.

input:       2.00 × 0.10 = 0.200
output:     10.00 × 0.05 = 0.500
cache read:  0.20 × 0.85 = 0.170
                   mixed = 0.870  $ / 1M токенов

На 100M токенов — $87.00 по официальному тарифу.

Сводка по профилю 10/5/85

МодельОфициально in / out / cache readmixed
Claude Opus 4.55.00 / 25.00 / 0.502.175
Claude Sonnet 4.52.00 / 10.00 / 0.200.870

Официальные ставки Anthropic сверены 2026-09-09, Sonnet — 2026-09-26, по platform.claude.com/docs/en/about-claude/pricing; ставки шлюза — на странице цен, там же посчитана смешанная цена и экономия по этому же профилю. Подставьте в формулу свои доли из логов: чем выше у вас доля cache read, тем сильнее решает именно эта строка. Обе цены опубликованы рядом на /pricing, машиночитаемый источник правды — GET /api/pricing с версионированным snapshot.

Проверка без пополнения

При регистрации на баланс начисляется $1 welcome-грантом, который тратится на обычные API-запросы. Разделите $1 на смешанную цену нужной модели со страницы цен — получите объём трафика, который грант покрывает. Для миграции и первого взгляда на реальные cost_usd его хватает с запасом. Минимальное пополнение потом — $1, максимум — $10 000, подписок и обязательной ежемесячной платы нет.

Итог

Миграция с прямого Anthropic или OpenAI API на совместимый шлюз — это не рефакторинг, а два изменения в конфиге:

  • Anthropic SDK и Claude Code: base_url = https://go2llm.tech (без /v1), ключ через ANTHROPIC_AUTH_TOKEN.
  • OpenAI SDK: base_url = https://go2llm.tech/v1, ключ в api_key.

Реальная работа не в смене строки, а в чек-листе: взять точный model ID из /v1/models, добавить обработку 402/429/502, выставить квоту на ключ и убедиться, что в запросах нет media на вход и Responses API. Это час работы, не спринт. Полная документация по протоколам и полям — в /docs.

FAQ

Можно ли использовать официальный Anthropic SDK без форков и патчей? Да. Anthropic SDK для Python и JavaScript принимает параметр base_url / baseURL в конструкторе клиента, и этого достаточно. Протокол /v1/messages совпадает по полям запроса, SSE-стримингу и tool calls, поэтому остальной код не меняется. Заголовок anthropic-version: 2023-06-01 сохраняется как есть.

Почему Claude Code возвращает 401, хотя тот же ключ работает в curl? Потому что использована переменная ANTHROPIC_API_KEY вместо ANTHROPIC_AUTH_TOKEN. Если на машине уже есть вход в Claude Code под личным аккаунтом claude.ai или Anthropic Console, ANTHROPIC_API_KEY может уступить сохранённому логину, и запрос уйдёт мимо шлюза с 401. ANTHROPIC_AUTH_TOKEN всегда обращается к указанному ANTHROPIC_BASE_URL с переданным значением.

Чем отличается base URL для Anthropic SDK и для OpenAI SDK? Anthropic SDK и Claude Code ждут базовый адрес без /v1 — https://go2llm.tech, путь SDK дописывает сам. OpenAI SDK и OpenAI-совместимые клиенты ждут его с /v1 — https://go2llm.tech/v1. Перепутанный вариант обычно выглядит как 404 на несуществующем пути.

Почему Codex CLI не подключается к некоторым OpenAI-совместимым шлюзам? Актуальные версии Codex CLI для кастомных провайдеров в ~/.codex/config.toml поддерживают только wire_api = "responses", то есть формат OpenAI Responses API. Значение wire_api = "chat" сам Codex CLI отклоняет с ошибкой «no longer supported». Если у шлюза endpoint /v1/responses не опубликован, Codex получает 404. У go2llm он опубликован и проверен живым прогоном 2026-09-14 — Codex CLI подключается; другие проверенные варианты для терминала — Claude Code и OpenCode.

Как понять, сколько стоил конкретный запрос, не заходя в кабинет? Шлюз возвращает стоимость каждого запроса в поле usage.cost_usd прямо в ответе, включая финальный usage-блок SSE-стрима. Списание работает так: сначала резервируется оценочная стоимость, затем списывается фактическая, остаток резерва освобождается. Баланс при этом не уходит ниже нуля, а при нехватке средств приходит 402 insufficient_balance.


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

Ключ выдаётся сразу, при регистрации на баланс начисляется $1 — хватит, чтобы прогнать миграцию целиком:

curl https://go2llm.tech/v1/chat/completions \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "content-type: application/json" \
  -d '{"model":"gpt-5.6-sol","max_tokens":120,"messages":[{"role":"user","content":"Ответь одним словом: работает"}]}'