Ключора

SDK Ключоры

Python и JavaScript/TypeScript. Бесплатно, без зависимостей. Чат и стриминг, все типы моделей шлюза, список доступных моделей, лимиты ключа, баланс кабинета и оценка стоимости запроса.

Скачать для PythonСкачать для JS/TS

Версия 0.1.0, 6 октября 2026. Лицензия MIT.

Установка

Пакеты без зависимостей. Скачайте с этого сайта: в PyPI и npm мы пока не публикуем.

Python 3.8+

pip install https://klyuchora.ru/sdk/downloads/klyuchora-0.1.0-py3-none-any.whl

JavaScript / TypeScript (Node 18+, Bun, Deno, браузер)

npm install https://klyuchora.ru/sdk/downloads/klyuchora-0.1.0.tgz

Файлы и контрольные суммы: SHA256SUMS. Проверка: sha256sum -c SHA256SUMS. Лицензия MIT.

Ключ и токен

Для запросов к моделям нужен API-ключ из кабинета (Ключи API). Передайте его в клиент или через переменную окружения KLYUCHORA_API_KEY.

Баланс кабинета и список ваших ключей лежат на уровне аккаунта, поэтому ключа мало: нужен токен доступа (KLYUCHORA_ACCESS_TOKEN) из раздела «Безопасность и доступ». Остальные методы токена не требуют.

ПеременнаяЗачем
KLYUCHORA_API_KEYключ для запросов к моделям и для лимитов ключа
KLYUCHORA_ACCESS_TOKENтокен аккаунта: баланс и список ключей
KLYUCHORA_BASE_URLадрес API, по умолчанию https://klyuchora.ru

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

Быстрый старт

Python

from klyuchora import Klyuchora

client = Klyuchora()  # ключ берётся из KLYUCHORA_API_KEY
reply = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Привет!"}],
)
print(reply.choices[0].message.content)

JavaScript

import { Klyuchora } from "klyuchora";

const client = new Klyuchora(); // KLYUCHORA_API_KEY
const reply = await client.chat.completions.create({
  model: "gpt-4o-mini",
  messages: [{ role: "user", content: "Привет!" }],
});
console.log(reply.choices[0].message.content);

CommonJS тоже работает: const { Klyuchora } = require("klyuchora").

Чат и стриминг

Ответы моделей приходят в том же виде, что и в OpenAI API: поля называются так же (choices, usage). Для стриминга передайте stream=True (в JS stream: true). SDK сам просит у шлюза статистику токенов в конце потока.

# Python
with client.chat.completions.create(model="gpt-4o-mini", messages=msgs, stream=True) as stream:
    for text in stream.text_deltas():
        print(text, end="", flush=True)

# или собрать поток в один ответ
full = client.chat.completions.create(model="gpt-4o-mini", messages=msgs, stream=True).collect()
print(full.choices[0].message.content, full.usage)
// JavaScript
const stream = await client.chat.completions.create({ model: "gpt-4o-mini", messages, stream: true });
for await (const text of stream.textDeltas()) process.stdout.write(text);

// или сырые куски
for await (const chunk of stream) console.log(chunk.choices[0]?.delta);
// или целиком
const full = await (await client.chat.completions.create({ model: "gpt-4o-mini", messages, stream: true })).collect();

stream.request_id / stream.requestId пригодится для обращения в поддержку.

Все методы

Только то, что есть в шлюзе. Если вы не нашли нужный маршрут, используйте request().

PythonJSМаршрут
chat.completions.createchat.completions.create/v1/chat/completions
completions.createcompletions.create/v1/completions
responses.createresponses.create/v1/responses
messages.createmessages.create/v1/messages (формат Anthropic)
embeddings.createembeddings.create/v1/embeddings
images.generate, images.editimages.generate, images.edit/v1/images/generations, /v1/images/edits
audio.speech.createто же/v1/audio/speech (байты аудио)
audio.transcriptions.create, audio.translations.createто же/v1/audio/transcriptions, /v1/audio/translations
rerank.creatererank.create/v1/rerank
moderations.createmoderations.create/v1/moderations
models.list / ids / retrieveто же/v1/models

Не поддерживаются шлюзом, поэтому и в SDK их нет: /v1/files, /v1/images/variations. Конкретная модель работает только с теми маршрутами, которые она сама поддерживает.

# Python: примеры
client.embeddings.create(model="text-embedding-3-small", input="текст")
client.images.generate(model="gpt-image-1", prompt="кот на облаке", size="1024x1024")
audio = client.audio.speech.create(model="gpt-4o-mini-tts", input="Привет", voice="alloy")
open("out.mp3", "wb").write(audio)
text = client.audio.transcriptions.create(model="whisper-1", file=open("a.mp3", "rb"))
client.messages.create(model="claude-sonnet-4-5", max_tokens=200,
                       messages=[{"role": "user", "content": "Привет"}])

Названия моделей берите из client.models.ids(): список зависит от вашего ключа. Пример имён выше только показывает формат вызова.

Модели и цены

models.ids() возвращает модели, доступные именно вашему ключу. models.catalog() читает публичный каталог цен: ключ не нужен. Цены уже итоговые, ничего сверху не добавляется.

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

client.models.ids()                                # ["gpt-4o-mini", ...]
client.models.catalog(search="gpt-4o")             # поиск по названию
client.models.catalog(endpoint="image-generation") # по типу
client.models.catalog(group="Имя-группы")          # по группе
item = client.models.price("gpt-4o-mini")
item.prices   # [{group, input_per_1m_usd, output_per_1m_usd, cached_input_per_1m_usd}, ...]
                # у моделей с оплатой за запрос: {group, per_request_usd}

В JS поля пишутся в camelCase: inputPer1mUsd, outputPer1mUsd, cachedInputPer1mUsd, perRequestUsd.

Лимиты ключа

Методу достаточно самого ключа. Он показывает, сколько выдано, потрачено и осталось, какие модели разрешены и когда ключ истекает. Суммы в долларах.

u = client.key.usage()
u.name; u.unlimited                  # безлимитный ключ тратит баланс аккаунта
u.granted_usd; u.used_usd; u.remaining_usd
u.model_limits_enabled; u.model_limits   # список разрешённых моделей
u.expires_at                         # unix-секунды, 0 = без срока
const u = await client.key.usage();
console.log(u.remainingUsd, u.modelLimits, u.expiresAt);

Баланс кабинета

Нужен токен доступа. Возвращает баланс в долларах и примерно в рублях по курсу ЦБ, который использует сайт.

client = Klyuchora(access_token="...")      # или KLYUCHORA_ACCESS_TOKEN
b = client.account.balance()
b.balance_usd; b.spent_usd; b.requests; b.balance_rub_approx
client.account.keys()                       # ваши ключи: лимиты, группы, IP, срок (сами ключи замаскированы)
client.rates.usd_rub()                      # курс: rub_per_usd, date

SDK только читает. Создавать и удалять ключи нужно в кабинете: это требует подтверждения безопасности.

Оценка стоимости

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

e = client.estimate_cost("gpt-4o-mini", input_tokens=1000, output_tokens=500)
e.min_usd, e.max_usd, e.min_group, e.max_group, e.by_group
e.min_rub, e.max_rub                 # по курсу ЦБ
client.estimate_cost("gpt-image-1", requests=3)   # модели с оплатой за запрос

Сверено с реальным списанием: для запроса на 3010 токенов на входе списание совпало с минимальной ценой диапазона. Цена ниже одного внутреннего кванта округляется вверх, на очень мелких запросах списание выглядит чуть больше оценки.

Ошибки и повторы

Все ошибки наследуются от KlyuchoraError. Ошибки ответа шлюза (APIError) несут status, code, request_id.

КлассКогда
AuthenticationError401: нет или неверный ключ/токен
InsufficientBalanceErrorзакончился баланс или лимит ключа (403 или 402)
PermissionDeniedError403: нет доступа к модели или IP не разрешён
NotFoundError404, а также «модель недоступна» (model_not_found)
BadRequestError400, 413, 422
RateLimitError429, есть retry_after
ServerError5xx
ConnectionFailed, RequestTimeoutсеть, таймаут

Повторы по умолчанию: 2 раза с паузой, для 408, 409, 429, 5xx и обрыва сети. Уважается Retry-After. Не повторяются запросы без денег на балансе и «модель недоступна». Настройка: max_retries / maxRetries, timeout (в Python секунды, в JS миллисекунды).

from klyuchora import InsufficientBalanceError, RateLimitError
try:
    client.chat.completions.create(model="gpt-4o-mini", messages=msgs)
except InsufficientBalanceError:
    print("Пополните баланс в кабинете")
except RateLimitError as e:
    print("Подождите", e.retry_after)

Async и CLI

В Python есть AsyncKlyuchora с теми же методами, их нужно ждать через await. В JS всё и так асинхронное.

from klyuchora import AsyncKlyuchora
client = AsyncKlyuchora()
reply = await client.chat.completions.create(model="gpt-4o-mini", messages=msgs)
stream = await client.chat.completions.create(model="gpt-4o-mini", messages=msgs, stream=True)
async for text in stream.text_deltas():
    print(text, end="")

Командная строка

klyuchora models                 # модели вашего ключа
klyuchora models --catalog --search gpt   # каталог с ценами
klyuchora price gpt-4o-mini      # цены по группам
klyuchora usage                  # лимиты ключа
klyuchora balance                # баланс кабинета (нужен токен)
klyuchora keys                   # ваши ключи (нужен токен)
klyuchora rate                   # курс
klyuchora chat gpt-4o-mini "Привет" --max-tokens 50

TypeScript

Типы идут в пакете: ChatCompletion, ChatChunk, KeyUsage, Balance, CatalogModel, CostEstimate и другие. Потоковый вызов с stream: true возвращает Stream<ChatChunk>, обычный возвращает ChatCompletion.

Любой другой маршрут

Если маршрут или параметр появился раньше, чем в SDK, вызовите его напрямую: ключ, повторы и разбор ошибок сохраняются.

client.request("POST", "/v1/chat/completions", json={...})
client.request("POST", "/v1/chat/completions", json={..., "stream": True}, stream=True)

Любые дополнительные параметры методов (temperature, tools, response_format и так далее) передаются как есть.

Версии

ВерсияДатаЧто внутри
0.1.06 октября 2026Первый выпуск: Python и JS/TS, чат и стриминг, responses, Anthropic messages, embeddings, картинки, аудио, rerank, moderations, модели и цены, лимиты ключа, баланс кабинета, оценка стоимости, CLI, повторы и типизированные ошибки.

Актуальная версия в машинном виде: /sdk/version.json.

Вопросы

Почему не на PyPI и npm?

Пока ставится по ссылке с этого сайта. Команда установки выше работает без аккаунтов в сторонних сервисах.

Как проверить, что файл не подменили?

Сравните с SHA256SUMS.

Что значит «баланс недоступен»?

Баланс аккаунта читается по токену доступа, а не по API-ключу. Создайте токен в кабинете и передайте его в access_token.

Почему в цене диапазон?

Списание идёт по группе, которая обслужила запрос. SDK показывает минимум и максимум по всем группам модели.

Нашли ошибку?

Напишите в поддержку и укажите request_id из ошибки.