Документация API QVORA
Один ключ и один баланс в рублях для текстовых моделей, эмбеддингов и медиа-генераций. Совместимо с OpenAI SDK (Chat Completions, Responses), Anthropic SDK и Claude Code (Messages), Cursor, Continue, Cline, Codex CLI, n8n и Make.
Быстрый старт
Base URL — https://qvora.ru/api/v1. Ключ создаётся в кабинете компании → «Ключи» (формат shds-…, показывается один раз). Заголовок — Authorization: Bearer shds-… или x-api-key.
curl https://qvora.ru/api/v1/chat/completions \
-H "Authorization: Bearer $QVORA_API_KEY" -H "Content-Type: application/json" \
-d '{"model":"gpt-5-mini","messages":[{"role":"user","content":"Привет!"}]}'from openai import OpenAI
client = OpenAI(base_url="https://qvora.ru/api/v1", api_key="shds-…")
r = client.chat.completions.create(model="claude-sonnet", messages=[{"role": "user", "content": "Привет!"}])
print(r.choices[0].message.content, r.usage, r.model_extra["qvora"]["cost_rub"])import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://qvora.ru/api/v1", apiKey: process.env.QVORA_API_KEY });
const stream = await client.chat.completions.create({ model: "gpt-5-mini", messages: [{ role: "user", content: "Привет!" }], stream: true });
for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta?.content ?? "");Легаси-префикс /api/v1/ext/* эквивалентен /api/v1/* и сохраняется для существующих интеграций.
Ключи и скоупы
Ключ принадлежит организации и списывает с её баланса. У ключа есть скоупы — ручка вне скоупа отвечает 403 insufficient_scope:
chat— Chat Completions, Responses, Messages;embeddings;media— медиа-задачи и транскрибация;usage— чтение расходов;admin— управление ключами, группами, сотрудниками, аудит.
Настройки ключа — месячный и дневной лимит в ₽, запросов и токенов в минуту, одновременных запросов, allowlist моделей, IP-allowlist, срок действия, группа и сотрудник — применяются следующим запросом: кэша авторизации нет. Отзыв — мгновенный. Ключ хранится как SHA-256, восстановить его нельзя — только ротация (старый живёт ещё 24 часа).
Маршруты
| Метод | Путь | Назначение | Скоуп ключа |
|---|---|---|---|
| POST | /chat/completions | Chat Completions | chat |
| POST | /responses | Responses API | chat |
| POST | /messages | Anthropic Messages API | chat |
| POST | /embeddings | Эмбеддинги | embeddings |
| GET | /models | Модели и цены | — |
| POST | /media/tasks | Медиа-задача | media |
Загружаем схему… Полная схема: /api/v1/openapi.json.
Chat Completions
POST /v1/chat/completions. Поддержано: роли system/developer/user/assistant/tool, текст и картинки (image_url, включая data:), tools / tool_choice / parallel_tool_calls с полным циклом tool_calls → role:tool, response_format text | json_object | json_schema,temperature, top_p, max_tokens / max_completion_tokens, stop, seed,presence_penalty, frequency_penalty, reasoning_effort, stream + stream_options.include_usage, user.
Параметр либо исполняется, либо приходит 400 unsupported_parameter с полем param. Молчаливого игнора нет. В стриме tool_calls идут дельтами по index (первая — с id и type), в конце — чанк с usage и data: [DONE].
// ответ: стандартный chat.completion + блок qvora
{
"choices": [{ "message": { "role": "assistant", "content": null,
"tool_calls": [{ "id": "call_1", "type": "function", "function": { "name": "get_weather", "arguments": "{\"city\":\"Москва\"}" } }] },
"finish_reason": "tool_calls" }],
"usage": { "prompt_tokens": 120, "completion_tokens": 18, "total_tokens": 138,
"prompt_tokens_details": { "cached_tokens": 96 }, "completion_tokens_details": { "reasoning_tokens": 0 } },
"qvora": { "served_model": "gpt-5-mini", "cost_rub": 0.02, "cache_saved_rub": 0.01, "request_ref": "…" }
}Идемпотентность. Заголовок Idempotency-Key (только non-stream) в течение 24 часов возвращает сохранённый ответ без второго списания (Idempotent-Replayed: true). Тот же ключ с другим телом — 409 idempotency_key_reused. Отмена. Разрыв соединения в стриме останавливает генерацию — платите только за полученное.
Responses API и Codex
POST /v1/responses: строка или items во input, instructions, плоские function-tools, циклfunction_call → function_call_output, text.format (json_schema), reasoning.effort, стрим событиямиresponse.created → … → response.completed со сквозным sequence_number. previous_response_id и background не поддержаны (400). Хостовые инструменты (web_search и т.п.) игнорируются, о чём сообщает заголовок x-qvora-dropped-tools.
# ~/.codex/config.toml — Codex CLI через QVORA
model = "gpt-5-mini"
model_provider = "qvora"
[model_providers.qvora]
name = "QVORA"
base_url = "https://qvora.ru/api/v1"
env_key = "QVORA_API_KEY"
wire_api = "responses"Anthropic Messages и Claude Code
POST /v1/messages и /v1/messages/count_tokens: system, блоки text/image/tool_use/tool_result,tools/tool_choice, stop_sequences, thinking, стрим событиями Anthropic (message_start → content_block_* → message_delta → message_stop), ошибки в конверте Anthropic. usage.input_tokens не включаетcache_read_input_tokens — как у Anthropic. Через этот протокол доступны любые модели каталога, не только Claude.
export ANTHROPIC_BASE_URL=https://qvora.ru/api
export ANTHROPIC_AUTH_TOKEN=shds-… # или ANTHROPIC_API_KEY
export ANTHROPIC_MODEL=claude-sonnet-5 # любой Claude из GET /v1/models (псевдонимы понимаются)
claudeСерверные инструменты Anthropic (web_search, computer и т.п.) исполняются у Anthropic и через QVORA недоступны — они игнорируются с заголовком x-qvora-dropped-tools. Thinking-блоки в ответ не возвращаются.
Эмбеддинги
POST /v1/embeddings — input строка или массив (до 2048), dimensions где модель умеет, encoding_format: float. Модели и цены — в GET /v1/models с type: embedding. Списание только за вход, минимум 0,1 ₽ за запрос.
Медиа-задачи
Все медиа-операции асинхронные. Каталог GET /v1/media/models для каждой модели отдаёт операции (generate, edit, animate, upscale, remove_background), JSON Schema параметров (длительности, разрешения, соотношения сторон, голоса, число вариаций), роли входов (image, first_frame, last_frame,video, reference_*) с ограничениями и правило цены. Схема строится из того же каталога, что и Студия — второго списка параметров нет.
# создать картинку и подождать до 60 с
curl -X POST https://qvora.ru/api/v1/media/tasks -H "Authorization: Bearer $QVORA_API_KEY" -H "Content-Type: application/json" -d '{
"model": "nano-banana", "prompt": "красный куб на белом фоне", "params": { "aspect": "16:9", "count": 1 },
"idempotency_key": "order-1042", "webhook_url": "https://example.com/hooks/qvora", "wait": 60 }'
# → 202 { "id": "task_…", "status": "queued|running|succeeded", "results": [{ "url": "…", "expires_at": … }], "cost": { "charged_rub": 13 } }
curl https://qvora.ru/api/v1/media/tasks/task_… -H "Authorization: Bearer $QVORA_API_KEY"- Входы — публичные
https-URL илиdata:-URI (до 200 МБ); тип определяется по содержимому. - Статусы:
queued → running → succeeded | failed | cancelled;progress,cost.charged_rub / refunded_rub,error.code. - Отмена
POST /media/tasks/:id/cancel— пока задача в очереди; деньги возвращаются. Взятую в работу отменить нельзя (409). - URL результатов подписаны и действуют 1 час (
expires_at) — заберите файл или запросите задачу снова. idempotency_key: повтор возвращает ту же задачу (200+Idempotent-Replayed), другое тело —409.
Вебхуки
При webhook_url (только https, публичный адрес) по завершении задачи приходит POST с событиемmedia.task.succeeded | failed | cancelled. Заголовки: X-Qvora-Event, X-Qvora-Delivery-Id, X-Qvora-Timestamp,X-Qvora-Signature: t=<ts>,v1=<hex>, где v1 = HMAC-SHA256(secret, `${ts}.${rawBody}`). Секрет выдаётся вместе с ключом (и по POST /admin/keys/:id/webhook-secret), повторно не показывается.
import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(secret, signature, rawBody, now = Math.floor(Date.now() / 1000)) {
const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(signature); if (!m) return false;
if (Math.abs(now - Number(m[1])) > 300) return false; // защита от replay: 5 минут
const expected = createHmac("sha256", secret).update(`${m[1]}.${rawBody}`).digest("hex");
return timingSafeEqual(Buffer.from(expected, "hex"), Buffer.from(m[2], "hex"));
}Доставка at-least-once: дедуплицируйте по data.id + type. Ретраи при не-2xx: 5 с, 20 с, 1, 3, 10, 30 мин; журнал — GET /media/tasks/:id/webhooks, ручной повтор — в admin API.
Транскрибация
POST /v1/audio/transcriptions — multipart file (как в OpenAI SDK) или JSON { "url": "https://…" }; model: whisper-1; response_format: json | verbose_json | text; language. Синхронно, дедлайн до 10 минут; цена за минуту аудио, списание по факту, стоимость — в x-qvora-cost-rub.
Цены, кэш, биллинг
- Цены — в
GET /v1/models(price_rub_per_1k: input / cached_input / cache_write / output) и в медиа-каталоге (price) — по прайс-буку вашего контракта. - Текст: резерв под максимум запроса → списание по фактическим токенам → возврат разницы. Токены из кэша провайдера (
cached_tokens) тарифицируются по ставкеcached_input; экономия видна вqvora.cache_saved_rub. - Медиа: цена известна до запуска (кроме апскейла видео — по длительности исходника); при ошибке или отмене деньги возвращаются.
- Баланс, резерв, расход и возврат — разные сущности:
GET /v1/balanceпоказываетbalance_rub,credit_limit_rub,available_rub,reserved_rub. - Нехватка средств —
402 insufficient_balanceсrequired_amount_rubиavailable_amount_rub. Постоплата — через кредитный лимит организации. - В ответе всегда
qvora.served_model— наш публичный id модели;request_ref— ссылка на строку в/v1/usage/requests.
Лимиты
| Лимит | Где задаётся | Код при превышении |
|---|---|---|
| Запросов в минуту (rpm) | ключ | 429 rate_limit_exceeded |
| Токенов в минуту (tpm) | ключ | 429 tpm_limit_exceeded |
| Одновременных запросов | ключ | 429 concurrency_limit_exceeded |
| Расход в день / месяц, ₽ | ключ | 429 daily_limit_exceeded / monthly_limit_exceeded |
| Расход группы в месяц | группа ключей | 429 group_limit_exceeded |
| Расход сотрудника в месяц | сотрудник (ключ с member_user_id) | 429 member_limit_exceeded |
| Модели | allowlist ключа ∩ прайс-бук | 404 model_not_found |
| IP | allowlist ключа | 403 ip_not_allowed |
| Контекст | 500 сообщений, 1,5 млн символов, 8 картинок, 512 инструментов | 400 context_length_exceeded и др. |
| Таймауты | стрим: 90 с простоя / 15 мин всего; синхронные вызовы: до 10 мин | 504 deadline_exceeded |
Admin API и usage
Ключ со скоупом admin управляет ключами (/v1/admin/keys: создание, изменение, ротация, отзыв, секрет вебхуков), группами (/admin/groups), лимитами сотрудников (/admin/members), читает аудит (/admin/audit: кто, когда, что изменил — без секретов) и журнал вебхуков. Он не может выдать скоупы шире своих и не трогает владельца, прайс-бук и кредитный лимит.
# расходы за месяц по сотрудникам и по конечным пользователям (поле user в запросах)
curl "https://qvora.ru/api/v1/usage?from=2026-09-01&to=2026-09-30&group_by=member" -H "Authorization: Bearer $QVORA_API_KEY"
curl "https://qvora.ru/api/v1/usage/requests?limit=100&api=chat" -H "Authorization: Bearer $QVORA_API_KEY"Коды ошибок
Конверт: { "error": { "message", "type", "code", "param", "trace_id" } }. trace_id = заголовок x-request-id — присылайте в поддержку. Для /v1/messages — конверт Anthropic (type: error).
| HTTP | code | Когда |
|---|---|---|
| 400 | invalid_value, missing_parameter, unsupported_parameter, unsupported_operation, context_length_exceeded, too_many_*, invalid_input_file, forbidden_address | Ошибка запроса; param указывает поле |
| 401 | invalid_api_key | Нет ключа, отозван, истёк |
| 402 | insufficient_balance | Не хватает средств (с required_amount_rub, available_amount_rub) |
| 403 | insufficient_scope, ip_not_allowed, member_disabled, organization_deactivated, scope_escalation | Доступ |
| 404 | model_not_found, task_not_found, key_not_found | Объект недоступен ключу |
| 409 | idempotency_key_reused, idempotency_in_flight, task_not_cancellable, request_expired, key_revoked | Конфликт состояния |
| 413 | file_too_large | Входной файл больше лимита |
| 429 | rate_limit_exceeded, tpm_limit_exceeded, concurrency_limit_exceeded, daily_limit_exceeded, monthly_limit_exceeded, group_limit_exceeded, member_limit_exceeded | Лимиты — повторите позже |
| 503 | model_unavailable | Модель временно недоступна — повторите или смените модель |
| 504 | deadline_exceeded | Синхронная операция не уложилась в дедлайн |
| 500 | internal_error | Наша ошибка — пришлите trace_id |
Изменения
- v2 (сентябрь 2026) — tools/tool_calls и json_schema в Chat Completions;
/v1/responses;/v1/messages(+count_tokens);/v1/embeddings; медиа-задачи с каталогом схем, вебхуками и идемпотентностью; транскрибация; admin API, группы, дневные/TPM/concurrency-лимиты;/v1/usage;Idempotency-Key; псевдонимы моделей;qvora.served_modelвместо внутреннего названия канала. - Миграция с v1: пути
/ext/*продолжают работать. Полеqvora.channelудалено — используйтеqvora.served_model. Лимиты сообщений/символов увеличены. Ошибки те же, добавлены новые коды.
Схема OpenAPI 3.1: /api/v1/openapi.json. Вопросы — support@qvora.ru.