Один ключ вместо пяти SDK: как устроен OpenAI-совместимый API

23.09.2026 · 3 мин

Меняете base_url на gdevse.ru/api/v1 — и весь каталог моделей работает тем же клиентом: стриминг SSE, tool calling, fallback, лимиты ₽/день.

Что именно «совместимый»

Формат запросов OpenAI — де-факто стандарт: messages, role, choices, usage. Шлюз Gdevse принимает его без изменений, поэтому подключение — это одна строка в конфиге, а не переписывание клиента:

from openai import OpenAI

client = OpenAI(
    base_url="https://gdevse.ru/api/v1",
    api_key="sk-vk-…",  # ключ из личного кабинета
)
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://gdevse.ru/api/v1",
  apiKey: process.env.GDEVSE_KEY,
});

Дальше меняется только поле model. ID модели — <вендор>/<имя>, как в OpenRouter: openai/gpt-4o-mini, deepseek/deepseek-v4.1-flash, anthropic/claude-sonnet-4.5. Полный список с ценами отдаёт GET /api/v1/models — публично, без ключа; там же цены в ₽ за токен и context_length.

Токены приходят в ответе, рубли — в отдельном запросе

В стандартном OpenAI-ответе поле usage несёт разбивку по токенам, включая кэш:

{
  "usage": {
    "prompt_tokens": 1024,
    "completion_tokens": 180,
    "prompt_tokens_details": { "cached_tokens": 768 }
  }
}

При стриминге ("stream": true) финальный чанк перед [DONE] несёт тот же usage. Это единственный надёжный способ учесть расход в потоковом приложении: суммировать дельты по словам — не считается.

Баланс и лимиты — из того же ключа

curl https://gdevse.ru/api/v1/key -H "Authorization: Bearer $GDEVSE_KEY"
# data: { name, usage — ₽, limit — ₽/сутки, rate_limit, is_enabled }

curl https://gdevse.ru/api/v1/credits -H "Authorization: Bearer $GDEVSE_KEY"
# data: { total_credits, usage, total_credits_remaining }

limit на ключе — дневной расход в рублях. Это то, что стоит поставить первым делом, если ключ попадает в публичное приложение: перебор защиты не спасёт от счёта, а лимит в 5 ₽/сутки спасёт. Ошибки — в едином JSON-формате OpenAI, так что обрабатывать их можно на уровне клиента:

{ "error": { "message": "insufficient balance for this request",
             "type": "billing_error", "code": "BILLING_REJECTED" } }

Fallback: подписка на один вендор — это риск доступности

{
  "model": "openai/gpt-4o-mini",
  "models": ["openai/gpt-4o-mini", "google/gemini-flash-1.5"],
  "messages": [{ "role": "user", "content": "Привет!" }]
}

Основная модель недоступна или упёрлась в лимит — запрос уходит по списку дальше, клиент не меняется. Полезная деталь для продакшена: ответ содержит, какая модель его реально сгенерировала, поэтому логировать стоит её, а не запрошенную первую строку.

Остальное, что ожидают от «взрослого» API

  • Tool calling — как в OpenAI: массив tools с описанием функций, finish_reason: "tool_calls" в ответе, результат возвращается ролью tool. Поддерживается не всеми моделями — флаг «инструменты» есть в карточке каждой модели в каталоге.
  • Структурированный вывод — response_format с json_object или строгой схемой json_schema.
  • Anthropic-формат — POST /api/v1/messages с заголовком x-api-key для клиентов SDK Claude.
  • Атрибуция — заголовки X-Title и HTTP-Referer: запросы с ними видны отдельным приложением в разделе «Расход → Приложения».
  • Лимиты в заголовках — X-RateLimit-* читаемы из браузера, CORS разрешён, так что счётчик запросов можно строить прямо в JS.
  • Provisioning — ключи создаются и отзываются программно управлением по отдельному ключу aik-…: POST /api/v1/keys с {"name": "ci-bot", "limit": 5}. Ключ вывода sk-vk-… управлять аккаунтом не может.

С чего начать, чтобы не сжечь баланс

  1. Отдельный ключ на каждое приложение, а не один на всё — иначе расход не разобрать.
  2. limit в рублях в сутки на каждый ключ, даже тестовый.
  3. Модель выбирать по странице сравнения, а не по названию: цена входа и выхода отличается в десятки раз при близком качестве на типовых задачах.
  4. Логируйте usage из ответа, а сверяйтесь с /api/v1/key — токены это вы, а рубли уже посчитаны на стороне шлюза.