Справочник API

.md

Все эндпоинты API СОЮЗ на одной странице — аутентификация, модели, чат, картинки, видео, джобы, файлы, вебхуки. Параметры, форматы ответов, коды ошибок.

Базовый URL: https://api.souz.ai/v1

Аутентификация — Bearer-ключ на защищённых /v1/*-эндпоинтах. Исключения: публичные GET /v1/models и GET /health, а файлы авторизуются подписью в URL:

Authorization: Bearer sk-souz-...

Обычные API-запросы и ответы — JSON (Content-Type: application/json). Исключения: chat stream идёт как SSE, файловый endpoint отдаёт байты или redirect, неизвестный маршрут/необработанное исключение сейчас могут быть простым текстом, а direct-host файла — произвольным ответом хранилища. Обрабатываемые ошибки приходят коротким конвертом либо объектом failed-job. Подробности: Ошибки.


GET /v1/credits

Остаток кредитов и лимит ключа — для мониторинга («алерт до того, как кончились»).

curl https://api.souz.ai/v1/credits -H "Authorization: Bearer sk-souz-..."
Поле Описание
balance Доступно к трате (кредиты)
reserved Удержано выполняющимися джобами
credit_value_usd Курс: 0.01 (1 кредит = 1¢)
rate_limit.requests_per_minute Действующий лимит этого ключа

GET /v1/models

На внутреннем ProductionGo-профиле endpoint по умолчанию выключен и отвечает 404. Он включается только после того, как RSA-123 сформирует сертифицированное пересечение возможностей, а RSA-118 докажет одну ревизию для discovery, admission и worker routing.

curl https://api.souz.ai/v1/models -H "Authorization: Bearer sk-souz-..."

До прохождения gate список сертифицированных моделей передаётся внутреннему продукту вне API. Код больше не строит контракт из первого provider variant. Формат будущей полной типизированной витрины (constraints, pricing impact и degradation choices) — RSA-102.

Поле Описание
id ID модели (souz/...) — его передаёшь в model
name Человеческое название
modality chat / image / video
pricing Правило цены (см. Кредиты)
limits max_prompt_chars, max_image_mb, image_formats

POST /v1/chat/completions

Синхронный чат, OpenAI-совместимый (текст, vision, tools, reasoning, стриминг). Полное описание: Чат.

Тело: стандартное OpenAI (model, messages, stream, temperature, max_tokens, tools, response_format, reasoning_effort, …). Сейчас проверяется только объявленный Content-Length до 25 МБ; hard limit для chunked/отсутствующего заголовка — RSA-27.

Ответ: стандартный OpenAI chat.completion (или SSE-поток при stream: true). Без стриминга в usage.cost возвращаются списанные кредиты; в стриме cost добавляется в usage-чанк, если его прислал апстрим.

Ошибки: short-envelope 400 invalid_request для плохого JSON/обязательных полей и 400 invalid_input|content_blocked при терминальном отказе апстрима; 401, 402 insufficient_credits (только здесь, у чата), 404 model_not_found, 413, 429, 502 model_unavailable (только здесь). Текст message — всегда наш, по коду: ответ апстрима в него не попадает. Логику строй на code (Принципы).


POST /v1/images/generations

Создать джобу генерации картинки. Полное описание: Картинки.

Поле Тип Обяз. Описание
model string ID модели
prompt string Описание
aspect_ratio string 1:1 2:3 3:2 3:4 4:3 4:5 5:4 9:16 16:9 21:9 2:1 1:2 3:1 1:3 9:21 1:4 4:1 1:8 8:1 auto (по умолчанию 1:1); variant может поддерживать subset
resolution string 1K / 2K / 4K (по умолчанию 1K)
quality string standard / high / ultra; отдельный quality-tier, не alias разрешения
output_format string png / jpeg; jpg нормализуется в jpeg
size string OpenAI-стиль: 1024x1024 / 1792x1024 / 1024x1792 / 2048x2048
image / images string / string[] Референсы: data URL или https URL; глобально не больше 14 до обхода/хеширования, модель может ограничить сильнее
callback_url string Вебхук этой джобы
priority string cost / speed (по умолчанию cost) — что оптимизировать при выборе порядка маршрутов; на цену не влияет. Вне словаря → invalid_request без джобы. Режима «надёжность» нет: надёжность — свойство всей системы (водопад доводит запрос до результата, пусть и дольше)
прочие поля Только поля typed frozen-профиля модели, верхним уровнем; неизвестное/невалидное → invalid_request до job

Неизвестное значение size, сочетание size с aspect_ratio/resolution и универсальный вложенный params: {...} отклоняются invalid_request до claim/job/reserve.

Заголовки: Idempotency-Key — end-to-end ключ replay для async image/video. Claim берётся до catalog/callback/reference preflight; mismatch → 409 idempotency_conflict, одинаковый незавершённый admission → retryable 409 idempotency_in_progress. Старый exact bound v1 replay'ится даже если текущая версия уже отвергает его форму; этот read-only путь не создаёт и не takeover'ит invalid-now claim. Детали — Джобы.

Ответы: 202 + объект джобы status: "queued" — принята; 200 + объект джобы — идемпотентный повтор для существующей джобы, которая не failed (в любом статусе, включая queued и in_progress); 400 + объект джобы failed — отказ сразу (модель отключена, поле не поддержано, не хватило кредитов) или идемпотентный повтор для упавшей джобы; 400 + короткий конверт invalid_request — ошибка на границе. Разбор — Ошибки. При callback_url в ответ добавляется webhook_secret: keyed replay возвращает тот же секрет, unkeyed путь показывает его один раз. До RSA-109 unkeyed callback прикрепляется отдельным UPDATE после enqueue и может проиграть редкую гонку с завершением; polling остаётся источником истины.


POST /v1/videos/generations

Создать джобу генерации видео. Полное описание: Видео.

Поле Тип Обяз. Описание
model string ID модели
prompt string Описание (до 5000 символов)
aspect_ratio string 16:9 9:16 1:1 4:3 3:4 21:9 auto (по умолчанию 16:9); вне списка → 400 invalid_request без джобы. Что умеет конкретная модель — в capabilities.aspect_ratios; каноничное, но неподдержанное моделью значение → 400 с failed-джобой capability_mismatch, price: 0
duration string|number Целое число секунд строкой или числом ("5"/5); другой JSON-тип или не целое → 400 invalid_request без джобы. Значения проверяются по манифестам модели. Не передан → capabilities.default_duration модели
image / images string / string[] Референсы (data URL или https URL)
callback_url string Вебхук этой джобы
priority string cost / speed (по умолчанию cost) — что оптимизировать при выборе порядка маршрутов; на цену не влияет. Вне словаря → invalid_request без джобы. Режима «надёжность» нет: надёжность — свойство всей системы (водопад доводит запрос до результата, пусть и дольше)
прочие поля Продвинутые параметры модели: mode, sound, resolution, …

Ответ: как у картинок (object: "video").

Длительность, по которой считается цена, — та же, с которой запрос уходит к модели: значение вне capabilities.durations отвергается до резервирования кредитов — 400 с failed-джобой (error.code: capability_mismatch, price: 0); молчаливой подмены на провайдерский дефолт нет. Значение вне общего словаря параметра отклоняется раньше, коротким конвертом 400 invalid_request, и джоба вообще не создаётся. Для aspect_ratio такая же гарантия сегодня действует только у Seedance 2.0 и Veo 3.1 (Seedance принимает весь свой официальный набор: 1:1 4:3 3:4 16:9 9:16 21:9 auto); у Kling image-to-video соотношение сторон определяется картинкой-референсом. auto — каноническое имя «пусть решает модель»; провайдерские написания наружу не выходят. На видео auto работает только у моделей, чей capabilities.aspect_ratios его содержит (Seedance 2.0, Veo 3.1) — у остальных это обычное неподдержанное значение.


GET /v1/jobs/{id}

Статус и результат джобы. Полное описание: Джобы.

Объект джобы:

Поле Описание
id ID джобы
object image / video / chat
model Модель
status queuedin_progresscompleted / failed
price Целые микро-USD (1 кредит = 10 000 µUSD), как все денежные поля API. До terminal state — верхняя оценка (maximum reserve); при completed — итоговое списание: себестоимость выполнившего маршрута × наценка, не выше оценки; при refund — 0
created_at Unix-время создания
parameters Для новых normalized job: { schema, requested, effective, degradations }; у legacy job отсутствует. Reference source/URL наружу не возвращается
data При completed: [{ "url": "подписанная ссылка" }]
error При failed: { code, message, type }; у capability_mismatch также versioned provider-opaque details

GET /v1/files/{name}?exp=...&sig=...

Скачать сгенерированный файл. Аутентификация — подпись в URL (ссылку выдаёт джоба), Bearer не нужен. Ссылку можно открывать в браузере.

Ошибки: 403 forbidden — обычно истёкшая подпись ссылки (файл может быть на месте). 410 file_expired — наш структурированный ответ: отдаём через прокси и объекта в хранилище нет. 404 — либо наш not_found в локальной ветке, либо непрозрачный ответ файлового хоста при прямой раздаче. Пока локальный handler сводит к 404 все ошибки чтения, включая права/I/O, поэтому ни один из этих 404 сам по себе не доказывает удаления. 502 storage_unavailable — временная проблема хранилища. Сначала свежая ссылка, потом повтор с паузой, дальше — поддержка; перегенерация оправдана после 410 или отдельно подтверждённого отсутствия (Джобы, RSA-92).


POST /v1/webhooks

Зарегистрировать постоянный вебхук. Тело: { "url": "https://..." }. Ответ 201: { id, object: "webhook", url, secret }secret показывается один раз. Полное описание: Вебхуки.

GET /v1/webhooks

Список вебхуков: { "object": "list", "data": [{ id, url, enabled, created_at }] }.

DELETE /v1/webhooks/{id}

Отключить вебхук. Ответ: { id, object: "webhook", deleted: true }.


GET /health

Проверка живости API (без аутентификации): { "ok": true }.


Частота запросов

1000 запросов/мин по умолчанию на ключ; сейчас limiter покрывает только POST создания image/video и chat completions, а не всю защищённую поверхность (RSA-20). Индивидуальный лимит может отличаться. При превышении — 429 + Retry-After. Подробности: Лимиты.