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.
- klyuchora-0.1.0-py3-none-any.whl (Python wheel)
- klyuchora-0.1.0.tar.gz (Python, исходники)
- klyuchora-0.1.0.tgz (npm)
Ключ и токен
Для запросов к моделям нужен 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().
| Python | JS | Маршрут |
|---|---|---|
chat.completions.create | chat.completions.create | /v1/chat/completions |
completions.create | completions.create | /v1/completions |
responses.create | responses.create | /v1/responses |
messages.create | messages.create | /v1/messages (формат Anthropic) |
embeddings.create | embeddings.create | /v1/embeddings |
images.generate, images.edit | images.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.create | rerank.create | /v1/rerank |
moderations.create | moderations.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, dateSDK только читает. Создавать и удалять ключи нужно в кабинете: это требует подтверждения безопасности.
Оценка стоимости
До запроса можно прикинуть цену по каталогу. Ответ даёт диапазон, потому что итог зависит от группы, которая обслужит запрос.
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.
| Класс | Когда |
|---|---|
AuthenticationError | 401: нет или неверный ключ/токен |
InsufficientBalanceError | закончился баланс или лимит ключа (403 или 402) |
PermissionDeniedError | 403: нет доступа к модели или IP не разрешён |
NotFoundError | 404, а также «модель недоступна» (model_not_found) |
BadRequestError | 400, 413, 422 |
RateLimitError | 429, есть retry_after |
ServerError | 5xx |
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 50TypeScript
Типы идут в пакете: 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.0 | 6 октября 2026 | Первый выпуск: Python и JS/TS, чат и стриминг, responses, Anthropic messages, embeddings, картинки, аудио, rerank, moderations, модели и цены, лимиты ключа, баланс кабинета, оценка стоимости, CLI, повторы и типизированные ошибки. |
Актуальная версия в машинном виде: /sdk/version.json.
Вопросы
Почему не на PyPI и npm?
Пока ставится по ссылке с этого сайта. Команда установки выше работает без аккаунтов в сторонних сервисах.
Как проверить, что файл не подменили?
Сравните с SHA256SUMS.
Что значит «баланс недоступен»?
Баланс аккаунта читается по токену доступа, а не по API-ключу. Создайте токен в кабинете и передайте его в access_token.
Почему в цене диапазон?
Списание идёт по группе, которая обслужила запрос. SDK показывает минимум и максимум по всем группам модели.
Нашли ошибку?
Напишите в поддержку и укажите request_id из ошибки.