# СОЮЗ | Документация API (полная)

> Единый OpenAI-совместимый API ко всем нейросетям. База: https://api.souz.ai/v1. 1 кредит = 1 цент США.

---

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

СОЮЗ — единый API ко всем основным нейросетям: чат-модели (GPT, Claude, Gemini, Grok, DeepSeek), генерация картинок (Nano Banana, GPT Image) и видео (Veo, Kling, Seedance) через **один ключ** и **один формат**.

API совместим с OpenAI: если у тебя уже есть код под OpenAI SDK — поменяй две строки, и он работает.

```text
base_url = "https://api.souz.ai/v1"
api_key  = "sk-souz-..."
```

## 1. Получи API-ключ

Зарегистрируйся на [dash.souz.ai](https://dash.souz.ai), раздел **API-ключи** → «Создать ключ». Ключ показывается один раз — сохрани его.

## 2. Чат — через любой OpenAI SDK

```python
from openai import OpenAI

client = OpenAI(
    base_url="https://api.souz.ai/v1",
    api_key="sk-souz-...",
)

resp = client.chat.completions.create(
    model="souz/gpt-5.4-mini",
    messages=[{"role": "user", "content": "Привет! Что ты умеешь?"}],
)
print(resp.choices[0].message.content)
print("потрачено кредитов:", resp.usage.cost)
```

То же на JavaScript:

```javascript
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://api.souz.ai/v1",
  apiKey: "sk-souz-...",
});

const resp = await client.chat.completions.create({
  model: "souz/claude-sonnet-4-6",
  messages: [{ role: "user", content: "Привет!" }],
});
console.log(resp.choices[0].message.content);
```

Стриминг, картинки в сообщениях (vision), tools и reasoning — в разделе [Чат](/chat).

## 3. Картинка — один POST и короткий опрос

Генерация картинок и видео асинхронная: запрос сразу возвращает джобу, результат забираешь опросом или вебхуком.

```bash
curl https://api.souz.ai/v1/images/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "souz/nano-banana-pro",
    "prompt": "уютный дом в горах на закате, кинематографичный свет",
    "aspect_ratio": "16:9",
    "resolution": "2K"
  }'
```

Ответ `202`:

```json
{
  "id": "job_a1b2c3...",
  "object": "image",
  "model": "souz/nano-banana-pro",
  "status": "queued",
  "price": 20,
  "created_at": 1781250000
}
```

Опрашивай джобу раз в 2–5 секунд:

```bash
curl https://api.souz.ai/v1/jobs/job_a1b2c3... \
  -H "Authorization: Bearer sk-souz-..."
```

Когда `status` станет `completed`, в `data[0].url` будет ссылка на файл:

```json
{
  "id": "job_a1b2c3...",
  "status": "completed",
  "price": 20,
  "data": [{ "url": "https://api.souz.ai/v1/files/res_....png?exp=...&sig=..." }]
}
```

> Файлы хранятся ~24 часа — скачивай результат сразу. Подробнее: [Джобы и результаты](/jobs).

## 4. Видео — так же

```bash
curl https://api.souz.ai/v1/videos/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "souz/veo3-fast",
    "prompt": "дрон пролетает над осенним лесом, утренний туман",
    "aspect_ratio": "16:9",
    "duration": "8"
  }'
```

Дальше тот же цикл: `GET /v1/jobs/{id}` → `completed` → `data[0].url` (mp4).

## Что дальше

- [Модели и цены](/models) — живой каталог со всеми возможностями
- [Чат](/chat) · [Картинки](/images) · [Видео](/videos)
- [Вебхуки](/webhooks) — результат без опроса
- [Ошибки](/errors) и [Лимиты](/limits)
- [Справочник API](/api-reference) — все эндпоинты на одной странице

## Для ИИ-агентов

- Индекс документации: [/llms.txt](/llms.txt)
- Вся документация одним файлом: [/llms-full.txt](/llms-full.txt)
- Любая страница в чистом Markdown: добавь `.md` к адресу (например `/chat.md`)

---

# Принципы

## Снаружи — всегда OpenAI-формат

Публичный API СОЮЗ всегда в формате OpenAI — де-факто стандарте индустрии. Клиент подключается, меняя **две строки**: `base_url` и `api_key`. Код, написанный под OpenAI SDK, работает как есть.

Провайдерские форматы (Google Native, внутренние API видео-провайдеров) — наша внутренняя кухня: мы переводим твой запрос в формат нужного провайдера сами. Ты их никогда не видишь.

Там, где у OpenAI нет устоявшегося стандарта (видео), мы добавляем тонкий слой в той же манере: тот же Bearer-ключ, тот же стиль JSON и ошибок.

## Просто по умолчанию — полная мощь по желанию

Базовый запрос максимально простой: `model` + `prompt`, и всё работает с разумными настройками.

Но если нужен полный функционал модели — любые продвинутые параметры (`negative_prompt`, `cfg_scale`, `sound`, `mode`, …) кладутся **прямо верхним уровнем** в тот же JSON. Они проверяются по белому списку конкретной модели: неизвестное поле → понятная ошибка `invalid_input`, без списания кредитов. Какие поля у какой модели — в [каталоге моделей](/models) и в `GET /v1/models`.

Простой путь никогда не усложняется из-за продвинутого.

## Надёжность: водопад провайдеров

У каждой модели может быть несколько провайдеров. Если первый недоступен или вернул сбой — запрос автоматически уходит к следующему. Ты этого не замечаешь: модель, цена и формат ответа не меняются.

Цена для тебя **фиксирована за модель** — переключение провайдеров меняет нашу маржу, а не твой счёт.

## Деньги: честно и прозрачно

- **1 кредит = 1 цент США ($0.01).** Все цены — в кредитах.
- Цена видна заранее ([каталог](/models)) и по факту: поле `price` у джобы, `usage.cost` в ответе чата.
- Списание — только за успешный результат. Сбой генерации → автоматический возврат резерва.
- Баланс и история — на [dash.souz.ai](https://dash.souz.ai).

## Асинхронность для тяжёлых задач

Картинки и видео создаются асинхронно: сразу получаешь `job_id`, результат — опросом `GET /v1/jobs/{id}` или [вебхуком](/webhooks). Это единственная схема, которая честно масштабируется и не рвёт соединения на минутных генерациях. Чат — синхронный (и со стримингом).

## Результаты — по ссылке, хранение ~24 часа

Готовые файлы отдаются подписанной ссылкой. Хранение — около суток, дальше файл удаляется (политика zero-retention: мы не храним твой контент дольше необходимого). Скачивай результат сразу после готовности.

---

# Кредиты и оплата

## Курс

**1 кредит = 1 цент США ($0.01).** Все цены в API и каталоге — в кредитах. Баланс пополняется и отслеживается в [дашборде](https://dash.souz.ai).

## Как считается цена

Цена зависит от модели и параметров запроса. Актуальные тарифы — в [каталоге моделей](/models) и в `GET /v1/models` (поле `pricing`).

| Модальность | Формула | Пример |
|---|---|---|
| Картинки | цена за тир разрешения (1K / 2K / 4K) | nano-banana-2: 1K = 8, 2K = 14, 4K = 24 |
| Видео | кредиты/сек × длительность × множитель режима + надбавки | kling-3: 12/сек, режим `pro` ×1.4 → 5 сек = 84 |
| Чат | за 1М входных + за 1М выходных токенов (минимум 1 кредит за ответ) | gpt-4o-mini: 25 вход / 90 выход за 1М |

## Остаток по API

`GET /v1/credits` — программная проверка баланса (для мониторинга и алертов «кредиты кончаются»):

```bash
curl https://api.souz.ai/v1/credits -H "Authorization: Bearer sk-souz-..."
```

```json
{
  "object": "credits",
  "balance": 12345,
  "reserved": 84,
  "currency": "credits",
  "credit_value_usd": 0.01,
  "rate_limit": { "requests_per_minute": 100 }
}
```

`balance` — доступно к трате, `reserved` — временно удержано выполняющимися джобами (вернётся в `balance` при успехе/сбое). Бонусом — действующий лимит запросов твоего ключа.

## Когда списываются кредиты

1. При создании запроса резервируется ожидаемая стоимость.
2. Успех → резерв списывается (для чата — пересчитывается по фактическим токенам).
3. Сбой → **полный возврат резерва автоматически**. За неудачные генерации ты не платишь.

Если баланса не хватает, запрос сразу отклоняется с ошибкой `insufficient_credits` (HTTP 402).

## Стоимость каждого запроса

- Картинки и видео: поле `price` в объекте джобы (и в ответе создания, и при опросе `GET /v1/jobs/{id}`).
- Чат: поле `usage.cost` в ответе (и в последнем чанке при стриминге).

```json
{ "usage": { "prompt_tokens": 16, "completion_tokens": 120, "cost": 3 } }
```

## История расходов

Полная история запросов и график расходов по дням и моделям — в [дашборде](https://dash.souz.ai), раздел «История».

---

# Модели и цены

Каталог моделей СОЮЗ с **актуальными ценами** (цены подтягиваются живьём, как в [дашборде](https://dash.souz.ai)). Все цены в кредитах: **1 кредит = 1 цент США**. Машиночитаемый каталог с возможностями и лимитами: `GET /v1/models`.

## Картинки

Эндпоинт: `POST /v1/images/generations` — [гайд](/images). Цена — за тир разрешения.

| Модель | ID | Цена (кредиты за 1K / 2K / 4K) | Референсы | Описание |
|---|---|---|---|---|
| Nano Banana | `souz/nano-banana` | 1K = 8 | до 14 референсов (image-to-image) | Gemini 2.5 Flash — быстрая генерация и редактирование картинок (1K). |
| Nano Banana 2 | `souz/nano-banana-2` | 1K = 8 · 2K = 14 · 4K = 24 | до 14 референсов | Gemini 3.1 Flash — до 4K, выше качество. |
| Nano Banana Pro | `souz/nano-banana-pro` | 1K = 12 · 2K = 20 · 4K = 36 | до 14 референсов | Gemini 3 Pro — флагман, до 4K, до 14 референсов. |
| GPT Image 2 | `souz/gpt-image-2` | 1K = 10 · 2K = 18 · 4K = 32 | до 8 референсов | OpenAI GPT-Image-2 — точные размеры 1K/2K/4K, текст и картинка→картинка. |

## Видео

Эндпоинт: `POST /v1/videos/generations` — [гайд](/videos). Цена = кр/сек × длительность × множитель режима (+ надбавки).

| Модель | ID | Цена | Длительности, сек | Референсы | Описание |
|---|---|---|---|---|---|
| Kling 2.1 Master | `souz/kling-2.1` | 10 кр/сек | 5, 10 | до 1 (необязательно — приложишь, оживит картинку) | Текст или картинка → видео (режим выбирается сам), кинематографично. |
| Kling 3.0 | `souz/kling-3` | 12 кр/сек × 4K:2.2/pro:1.4/std:1 | 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 | до 2 (первый/последний кадр) | Текст/картинка → видео, режимы качества, звук, мультишот. |
| Kling 2.6 | `souz/kling-2.6` | 10 кр/сек | 5, 10 | 1 картинка (обязательно) | Оживляет картинку. Соотношение берётся из изображения. |
| Seedance 2.0 | `souz/seedance-2` | 12 кр/сек (+10 за generate_audio) | 5, 10 | — | Мультимодал: текст, картинки, видео, аудио → видео. Камера, звук. |
| Veo 3.1 Quality | `souz/veo3` | 18 кр/сек | 5, 8 | до 2 (первый/последний кадр) | Google Veo 3.1 — топовое качество, нативное 9:16, со звуком. |
| Veo 3.1 Fast | `souz/veo3-fast` | 10 кр/сек | 5, 8 | до 2 кадров | Veo 3.1 Fast — дешевле, всё ещё сильное качество. |

Продвинутые поля каждой видео-модели (режимы, звук, кадры) — в [гайде по видео](/videos) и в `capabilities.advanced_params`.

## Чат

Эндпоинт: `POST /v1/chat/completions` — [гайд](/chat). Цена — за 1М входных / выходных токенов, минимум 1 кредит за ответ.

| Модель | ID | Вход / выход (кр за 1М токенов) | Vision | Описание |
|---|---|---|---|---|
| GPT-5.5 | `souz/gpt-5.5` | 750 / 4500 | ✅ | Флагман OpenAI — сложные задачи, код, reasoning (thinking). |
| GPT-5.4 | `souz/gpt-5.4` | 375 / 2250 | ✅ | Сильная универсальная модель OpenAI, вдвое дешевле 5.5. |
| GPT-5.4 Mini | `souz/gpt-5.4-mini` | 115 / 675 | ✅ | Лучшая цена/качество для продакшена. |
| GPT-5.2 | `souz/gpt-5.2` | 265 / 2100 | ✅ | Проверенная фронтир-модель OpenAI. |
| GPT-5 | `souz/gpt-5` | 190 / 1500 | ✅ | Классический GPT-5. |
| GPT-5 Mini | `souz/gpt-5-mini` | 40 / 300 | ✅ | Быстрый и дешёвый GPT-5. |
| GPT-4o | `souz/gpt-4o` | 375 / 1500 | ✅ | Мультимодальная классика OpenAI (текст + картинки). |
| GPT-4o Mini | `souz/gpt-4o-mini` | 25 / 90 | ✅ | Самый ходовой дешёвый мультимодал. |
| GPT-4.1 | `souz/gpt-4.1` | 300 / 1200 | ✅ | Контекст 1М токенов — длинные документы. |
| GPT-4.1 Mini | `souz/gpt-4.1-mini` | 60 / 240 | ✅ | 1М контекста за копейки. |
| OpenAI o3 | `souz/o3` | 450 / 1800 | — | Reasoning-модель для сложных рассуждений. |
| OpenAI o4-mini | `souz/o4-mini` | 165 / 660 | — | Дешёвый reasoning. |
| Claude Opus 4.8 | `souz/claude-opus-4-8` | 750 / 3750 | ✅ | Топ Anthropic — код и сложные задачи. |
| Claude Sonnet 4.6 | `souz/claude-sonnet-4-6` | 450 / 2250 | ✅ | Рабочая лошадка Anthropic. |
| Grok 4 | `souz/grok-4` | 450 / 2250 | ✅ | xAI Grok 4. |
| DeepSeek V3.2 | `souz/deepseek-v3.2` | 45 / 65 | — | Самые дешёвые сильные токены. |
| Gemini 2.5 Pro | `souz/gemini-2.5-pro` | 190 / 1500 | ✅ | Google Gemini Pro — мультимодал. |
| Gemini 2.5 Flash | `souz/gemini-2.5-flash` | 45 / 360 | ✅ | Быстрый дешёвый Gemini. |
| Gemini 2.5 Flash Lite | `souz/gemini-2.5-flash-lite` | 15 / 60 | ✅ | Самый дешёвый vision — картинки за копейки. |
| Gemini 3 Flash | `souz/gemini-3-flash` | 66 / 400 | ✅ | Gemini 3 поколение — быстрый мультимодал. |
| Gemini 3.1 Flash Lite | `souz/gemini-3.1-flash-lite` | 38 / 225 | ✅ | Свежий дешёвый Gemini с vision. |
| Gemini 3.1 Pro | `souz/gemini-3.1-pro` | 300 / 1800 | ✅ | Флагман Google — сложные задачи, vision. |
| Gemini 3.5 Flash | `souz/gemini-3.5-flash` | 225 / 1350 | ✅ | Новейший быстрый Gemini. |

## Примеры цен

- Nano Banana, 1K → **8 кр** (~$0.08)
- Kling 2.1 Master, минимальная длительность → **50 кр** (~$0.50)
- Чат: короткий вопрос-ответ на дешёвой модели → обычно **1–3 кр**

> Точная цена каждого запроса видна по факту: `price` у джобы, `usage.cost` в ответе чата. Подробнее: [Кредиты и оплата](/credits).

---

# Чат

```text
POST /v1/chat/completions
```

Синхронный OpenAI-совместимый эндпоинт. Работает с любым OpenAI SDK — меняешь `base_url` и `api_key`, остальное без изменений. Тело запроса пробрасывается модели целиком («полная мощь по желанию»): стандартные параметры OpenAI поддерживаются как есть.

## Параметры

| Поле | Тип | Описание |
|---|---|---|
| `model` | string, **обяз.** | ID модели, например `souz/gpt-5.4-mini` — [каталог](/models) |
| `messages` | array, **обяз.** | Сообщения в формате OpenAI (`system` / `user` / `assistant` / `tool`) |
| `stream` | boolean | `true` → стриминг SSE |
| `temperature`, `top_p`, `max_tokens`, `stop`, … | — | Стандартные параметры OpenAI, пробрасываются модели |
| `tools`, `tool_choice` | — | Вызов инструментов (function calling) — для моделей с поддержкой |
| `response_format` | object | Например `{"type": "json_object"}` |
| `reasoning_effort` | string | `low` / `medium` / `high` — глубина размышлений для thinking-моделей (gpt-5.5, o3, …) |

Лимит тела запроса — 25 МБ (vision-картинки едут внутри JSON).

## Пример

```python
from openai import OpenAI

client = OpenAI(base_url="https://api.souz.ai/v1", api_key="sk-souz-...")

resp = client.chat.completions.create(
    model="souz/claude-sonnet-4-6",
    messages=[
        {"role": "system", "content": "Отвечай кратко."},
        {"role": "user", "content": "Объясни, что такое вебхук."},
    ],
)
print(resp.choices[0].message.content)
print("кредитов:", resp.usage.cost)
```

В ответе — стандартный объект OpenAI. Дополнительно `usage.cost` — фактически списанные кредиты (как у OpenRouter).

## Стриминг

```python
stream = client.chat.completions.create(
    model="souz/gpt-5.4-mini",
    messages=[{"role": "user", "content": "Напиши хокку про API"}],
    stream=True,
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="")
    if chunk.usage:  # последний чанк
        print("\nкредитов:", chunk.usage.cost)
```

Поток — стандартный SSE (`data: {...}`, в конце `data: [DONE]`). Последний чанк всегда содержит `usage` с полем `cost`.

## Vision — картинки в сообщениях

Модели с пометкой «vision» в [каталоге](/models) принимают картинки в сообщениях (data URL, как у OpenAI):

```python
resp = client.chat.completions.create(
    model="souz/gemini-2.5-flash-lite",  # самый дешёвый vision
    messages=[{
        "role": "user",
        "content": [
            {"type": "text", "text": "Что на фото?"},
            {"type": "image_url", "image_url": {"url": "data:image/jpeg;base64,..."}},
        ],
    }],
)
```

## Reasoning (thinking-модели)

```python
resp = client.chat.completions.create(
    model="souz/gpt-5.5",
    messages=[{"role": "user", "content": "Сложная задача..."}],
    reasoning_effort="high",
)
```

Токены размышлений учитываются как выходные — это видно в `usage`.

## Ошибки

| HTTP | `code` | Когда |
|---|---|---|
| 401 | `invalid_api_key` | Нет/неверный ключ |
| 402 | `insufficient_credits` | Не хватает кредитов |
| 404 | `model_not_found` | Неизвестная модель |
| 413 | `invalid_request` | Тело больше 25 МБ |
| 429 | `rate_limited` | Превышен лимит запросов ([лимиты](/limits)) |
| 502 | `model_unavailable` | Все провайдеры модели недоступны — повтори позже |

Формат ошибок общий для всего API — см. [Ошибки](/errors).

---

# Генерация картинок

```text
POST /v1/images/generations
```

Создаёт асинхронную джобу генерации. Ответ приходит сразу (`202`), результат забираешь через [опрос джобы](/jobs) или [вебхук](/webhooks).

## Параметры

| Поле | Тип | Описание |
|---|---|---|
| `model` | string, **обяз.** | ID модели, например `souz/nano-banana-pro` — [каталог](/models) |
| `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` `auto`. По умолчанию `1:1` |
| `resolution` | string | `1K` / `2K` / `4K` (поддержка зависит от модели). По умолчанию `1K` |
| `size` | string | OpenAI-стиль вместо пары выше: `1024x1024`, `1792x1024`, `1024x1792`, `2048x2048` |
| `image` | string | Референс (image-to-image): **data URL** (`data:image/png;base64,...`) или **https URL** |
| `images` | string[] | Несколько референсов (максимум — у модели в каталоге) |
| `callback_url` | string | Вебхук для этой джобы — [подробнее](/webhooks) |
| *продвинутые поля* | — | Любые параметры конкретной модели кладутся верхним уровнем; проверяются по белому списку модели (`advanced_params` в `GET /v1/models`) |

Заголовок `Idempotency-Key` защищает от двойного создания при повторе запроса (см. [Справочник](/api-reference)).

## Текст → картинка

```bash
curl https://api.souz.ai/v1/images/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "souz/nano-banana-2",
    "prompt": "акварельный кот в космическом шлеме",
    "aspect_ratio": "1:1",
    "resolution": "2K"
  }'
```

Ответ `202` — объект джобы:

```json
{
  "id": "job_...",
  "object": "image",
  "model": "souz/nano-banana-2",
  "status": "queued",
  "price": 14,
  "created_at": 1781250000
}
```

`price` — итоговая цена в кредитах, посчитанная по параметрам запроса (тут 2K = 14).

## Картинка + референсы (image-to-image)

Референс можно передать как угодно — мы сами приведём его к формату провайдера:

```python
import base64, requests

img = base64.b64encode(open("face.jpg", "rb").read()).decode()

r = requests.post(
    "https://api.souz.ai/v1/images/generations",
    headers={"Authorization": "Bearer sk-souz-..."},
    json={
        "model": "souz/nano-banana-pro",
        "prompt": "этот человек в стиле киберпанк-постера",
        "image": f"data:image/jpeg;base64,{img}",
        "resolution": "2K",
    },
)
job = r.json()
```

Принимаются PNG, JPEG, WEBP и HEIC (айфоновские фото работают как есть) — сервер сам нормализует формат. Размер — до лимита модели (`limits.max_image_mb` в `GET /v1/models`, обычно 50 МБ для картинок).

## Забрать результат

```python
import time

while True:
    j = requests.get(
        f"https://api.souz.ai/v1/jobs/{job['id']}",
        headers={"Authorization": "Bearer sk-souz-..."},
    ).json()
    if j["status"] in ("completed", "failed"):
        break
    time.sleep(3)

if j["status"] == "completed":
    url = j["data"][0]["url"]
    open("result.png", "wb").write(requests.get(url).content)
```

Картинки обычно готовы за 5–30 секунд. Файл хранится ~24 часа — скачивай сразу. Подробности жизненного цикла: [Джобы и результаты](/jobs).

## Продвинутые параметры

У каждой модели — свой набор опциональных полей (белый список `advanced_params` в `GET /v1/models`). Они кладутся прямо верхним уровнем рядом с обычными. Поле не из списка → ошибка `invalid_input` без списания кредитов.

У картиночных моделей сейчас всё управляется базовыми полями (`aspect_ratio`, `resolution`, референсы); продвинутые поля активно используются у [видео-моделей](/videos).

---

# Генерация видео

```text
POST /v1/videos/generations
```

Создаёт асинхронную джобу. Жизненный цикл тот же, что у картинок: `202` → [опрос](/jobs) или [вебхук](/webhooks) → `data[0].url` (mp4). Видео генерируется от ~1 до десятков минут в зависимости от модели и длительности.

## Параметры

| Поле | Тип | Описание |
|---|---|---|
| `model` | string, **обяз.** | ID модели, например `souz/veo3-fast` — [каталог](/models) |
| `prompt` | string, **обяз.** | Описание сцены (до 5000 символов) |
| `aspect_ratio` | string | `16:9` / `9:16` / `1:1` / `auto`. По умолчанию `16:9` |
| `duration` | string или число | Секунды, допустимые значения — у модели в каталоге. По умолчанию `5` |
| `image` | string | Картинка-референс (data URL или https URL): первый кадр / оживление |
| `images` | string[] | Несколько референсов (например первый + последний кадр) |
| `callback_url` | string | Вебхук для этой джобы — [подробнее](/webhooks) |
| *продвинутые поля* | — | Параметры конкретной модели верхним уровнем (белый список `advanced_params`) |

Цена видео = кредиты/сек × длительность × множитель режима (+ надбавки). Точная цена возвращается в `price` сразу при создании. Тарифы — в [каталоге](/models).

## Текст → видео

```bash
curl https://api.souz.ai/v1/videos/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "souz/kling-3",
    "prompt": "волна разбивается о скалы в замедленной съёмке, золотой час",
    "aspect_ratio": "16:9",
    "duration": "5",
    "mode": "pro",
    "sound": true
  }'
```

`mode` и `sound` — продвинутые поля Kling 3.0 (режим качества `std`/`pro`/`4K` и генерация звука).

## Картинка → видео (оживление)

```python
import base64, requests

img = base64.b64encode(open("photo.jpg", "rb").read()).decode()

r = requests.post(
    "https://api.souz.ai/v1/videos/generations",
    headers={"Authorization": "Bearer sk-souz-..."},
    json={
        "model": "souz/kling-2.6",
        "prompt": "лёгкий ветер, человек улыбается и машет рукой",
        "image": f"data:image/jpeg;base64,{img}",
        "duration": "5",
    },
)
```

Для видео-референсов строже лимиты: PNG/JPEG, до 10 МБ (мы автоматически конвертируем WEBP/HEIC в допустимый формат).

## Примеры продвинутых полей

| Модель | Поля | Что делают |
|---|---|---|
| `souz/kling-3` | `mode`, `sound`, `multi_shots`, `negative_prompt` | режим `std`/`pro`/`4K`, звук, мультишот, негативный промпт |
| `souz/kling-2.1` | `negative_prompt`, `cfg_scale` | негативный промпт, строгость следования промпту (0–1) |
| `souz/seedance-2` | `first_frame_url`, `last_frame_url`, `reference_image_urls`, `camera_fixed`, `generate_audio` | кадры, референсы, фиксация камеры, аудио (+10 кредитов) |
| `souz/veo3`, `souz/veo3-fast` | `generationType`, `seeds` | режим (`TEXT_2_VIDEO` / `FIRST_AND_LAST_FRAMES_2_VIDEO`), сид |

Актуальный список — всегда в [каталоге](/models) и `GET /v1/models` (`capabilities.advanced_params`).

## Забрать результат

Опрашивай `GET /v1/jobs/{id}` раз в 5–10 секунд (видео — не торопится). Или укажи `callback_url` — пришлём готовую ссылку [вебхуком](/webhooks), без опроса.

```json
{
  "id": "job_...",
  "object": "video",
  "status": "completed",
  "price": 84,
  "data": [{ "url": "https://api.souz.ai/v1/files/res_....mp4?exp=...&sig=..." }]
}
```

Файл хранится ~24 часа — скачивай сразу.

---

# Джобы и результаты

Картинки и видео создаются асинхронно: `POST .../generations` сразу возвращает **джобу**, а результат появляется в ней позже.

## Статусы

```text
queued → in_progress → completed
                      ↘ failed
```

| Статус | Значение |
|---|---|
| `queued` | Принята, ждёт обработки |
| `in_progress` | Генерируется у провайдера |
| `completed` | Готово — ссылка в `data[0].url` |
| `failed` | Не получилось — причина в `error.code`, резерв кредитов возвращён |

## Опрос

```text
GET /v1/jobs/{id}
```

```bash
curl https://api.souz.ai/v1/jobs/job_a1b2c3 \
  -H "Authorization: Bearer sk-souz-..."
```

Ответ — всегда полный объект джобы:

```json
{
  "id": "job_a1b2c3",
  "object": "image",
  "model": "souz/nano-banana-pro",
  "status": "completed",
  "price": 20,
  "created_at": 1781250000,
  "data": [{ "url": "https://api.souz.ai/v1/files/res_....png?exp=...&sig=..." }]
}
```

При `failed` вместо `data` приходит `error`:

```json
{ "status": "failed", "error": { "code": "content_blocked", "message": "content_blocked", "type": "content_blocked" } }
```

Рекомендуемая частота опроса: картинки — раз в 2–5 сек, видео — раз в 5–10 сек. Чтобы не опрашивать вовсе — используй [вебхуки](/webhooks).

## Файлы результатов

`data[0].url` — **подписанная ссылка** (`?exp=...&sig=...`): её можно открывать в браузере и отдавать куда угодно без API-ключа, пока не истекла подпись. Если подпись истекла — просто запроси джобу ещё раз, получишь свежую ссылку.

**Хранение — около 24 часов.** Потом файл удаляется, и ссылка вернёт:

```json
HTTP 410 Gone
{ "error": { "code": "file_expired", "message": "file has expired: generated files are kept for ~24 hours — download results right after completion, or generate again" } }
```

Поэтому правило простое: **скачивай результат сразу после `completed`** и храни у себя.

## Идемпотентность

Передай заголовок `Idempotency-Key: <твой-уникальный-id>` при создании джобы — повторный запрос с тем же ключом вернёт ту же джобу, а не создаст (и не оплатит) новую. Полезно при ретраях по таймауту.

```bash
curl https://api.souz.ai/v1/images/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Idempotency-Key: order-42-avatar" \
  -H "Content-Type: application/json" \
  -d '{ "model": "souz/nano-banana", "prompt": "..." }'
```

## Дедлайн

Если генерация зависла у провайдера — джоба автоматически помечается `failed` и кредиты возвращаются. Потолки с запасом: **картинки — 15 минут**, **видео — 90 минут** (реальные генерации укладываются в разы быстрее; долгие, но живые генерации не обрубаются). Бесконечного `queued` не бывает.

---

# Вебхуки

Вместо опроса `GET /v1/jobs/{id}` СОЮЗ может сам прислать `POST` на твой URL, когда джоба завершится (успехом или ошибкой).

Два способа:

1. **Постоянный вебхук** — регистрируешь URL один раз, получаешь события по всем своим джобам.
2. **`callback_url` на запрос** — указываешь URL прямо в теле `POST .../generations`, событие придёт только по этой джобе.

Требования к URL: только `https`, публичный адрес (не локальная сеть), без редиректов.

## Постоянный вебхук

```bash
curl https://api.souz.ai/v1/webhooks \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/souz/hook" }'
```

```json
{ "id": "wh_1a2b3c", "object": "webhook", "url": "https://example.com/souz/hook", "secret": "whsec_..." }
```

`secret` показывается **один раз** — сохрани, им подписывается каждая доставка.

Список и удаление:

```text
GET    /v1/webhooks
DELETE /v1/webhooks/{id}
```

## callback_url на один запрос

```bash
curl https://api.souz.ai/v1/images/generations \
  -H "Authorization: Bearer sk-souz-..." \
  -H "Content-Type: application/json" \
  -d '{
    "model": "souz/nano-banana",
    "prompt": "...",
    "callback_url": "https://example.com/hooks/job-42"
  }'
```

В ответе `202` появится `webhook_secret` (один раз) — секрет подписи для этой джобы.

## Что приходит

`POST` с JSON — тот же объект джобы плюс `event`:

```json
{
  "event": "job.completed",
  "id": "job_a1b2c3",
  "object": "image",
  "model": "souz/nano-banana-pro",
  "status": "completed",
  "price": 20,
  "created_at": "2026-06-12T10:00:00.000Z",
  "data": [{ "url": "https://api.souz.ai/v1/files/res_....png?exp=...&sig=..." }],
  "error": null
}
```

События: `job.completed` и `job.failed` (при сбое `data: null`, причина в `error.code`). Заголовки: `Souz-Event` (тип события), `Souz-Delivery-Id` (уникальный ID доставки — для дедупликации), `Souz-Signature` (подпись).

## Проверка подписи

Подпись в стиле Stripe. Заголовок:

```text
Souz-Signature: t=1781250000,v1=9f86d081884c7d659a2feaa0c55ad015...
```

где `v1 = HMAC_SHA256(secret, "{t}.{сырое_тело}")` (hex). Проверяй по **сырому** телу запроса (до парсинга JSON) и отклоняй старые `t` (защита от повтора):

```python
import hmac, hashlib, time

def verify(secret: str, signature_header: str, raw_body: bytes) -> bool:
    parts = dict(p.split("=", 1) for p in signature_header.split(","))
    t, v1 = parts["t"], parts["v1"]
    if abs(time.time() - int(t)) > 300:  # старше 5 минут — отказ
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)
```

```javascript
import { createHmac, timingSafeEqual } from "node:crypto";

function verify(secret, signatureHeader, rawBody) {
  const parts = Object.fromEntries(signatureHeader.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return expected.length === parts.v1.length &&
    timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}
```

## Доставка и повторы

- Ответь `2xx` быстро (до 10 секунд) — лучше принять и обработать асинхронно.
- Не `2xx` или таймаут → повторы с нарастающей паузой, до 12 попыток на протяжении ~суток.
- Дедуплицируй по `Souz-Delivery-Id`: при повторах одно событие может прийти больше одного раза.
- Вебхук — это уведомление, а не источник истины: при сомнениях перепроверь статус через `GET /v1/jobs/{id}`.

---

# Ошибки

## Формат

Все ошибки API — единый JSON:

```json
{
  "error": {
    "code": "invalid_request",
    "message": "`model` and `prompt` are required",
    "type": "invalid_request"
  }
}
```

`code` — машиночитаемый, на него и завязывайся. `message` — пояснение для человека.

## Коды HTTP-ответов

| HTTP | `code` | Когда | Что делать |
|---|---|---|---|
| 400 | `invalid_request` | Кривое тело, неизвестное поле, неподдерживаемое значение, плохой референс | Исправить запрос. Не ретраить как есть |
| 401 | `invalid_api_key` | Нет заголовка / неверный или отключённый ключ | Проверить ключ |
| 402 | `insufficient_credits` | Не хватает кредитов | Пополнить баланс на [dash.souz.ai](https://dash.souz.ai) |
| 403 | `forbidden` | Невалидная/истёкшая подпись ссылки на файл | Перезапросить `GET /v1/jobs/{id}` — там свежая ссылка |
| 404 | `not_found` | Джоба не найдена / чужая | Проверить ID |
| 404 | `model_not_found` | Чат: неизвестная модель | Список — `GET /v1/models`, [каталог](/models) |
| 410 | `file_expired` | Файл удалён по сроку хранения (~24 ч) | Скачивать сразу; перегенерировать при необходимости |
| 413 | `invalid_request` | Тело чата больше 25 МБ | Сжать картинки |
| 429 | `rate_limited` | Превышен лимит запросов | Подождать `Retry-After` секунд, повторить |
| 500 | `internal_error` | Неожиданная ошибка на нашей стороне | Повторить позже; если повторяется — напиши нам |
| 502 | `model_unavailable` | Все провайдеры модели сейчас недоступны | Повторить позже или взять другую модель |
| 502 | `storage_unavailable` | Хранилище файлов временно недоступно | Повторить через минуту |

## Ошибки джоб (асинхронные)

Если генерация не удалась, джоба завершается `status: "failed"` с кодом в `error.code`, а **резерв кредитов возвращается автоматически**:

| `error.code` | Значение |
|---|---|
| `invalid_input` | Провайдер отклонил вход (промпт/референс/параметры) — исправь запрос |
| `content_blocked` | Контент заблокирован политиками модели — переформулируй промпт |
| `model_unavailable` | Водопад провайдеров исчерпан — повтори позже |
| `insufficient_credits` | Не хватило кредитов на резерв |

## Правила ретраев

- **Ретраить:** `429` (после `Retry-After`), `500`, `502`, сетевые таймауты — с нарастающей паузой.
- **Не ретраить без изменений:** `400`, `401`, `402`, `404`, `content_blocked`, `invalid_input`.
- При ретраях создания джобы используй `Idempotency-Key` — иначе рискуешь создать (и оплатить) дубль. См. [Джобы](/jobs).

---

# Лимиты

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

**100 запросов в минуту** на API-ключ по умолчанию (token bucket: короткие всплески допускаются, средняя — 100/мин). Лимит — **индивидуальный на каждый ключ**: текущее значение видно в [дашборде](https://dash.souz.ai) на странице ключей и в `GET /v1/credits` (`rate_limit.requests_per_minute`).

При превышении — `429 rate_limited` с заголовком `Retry-After` (секунды до следующей попытки):

```json
HTTP 429
Retry-After: 2
{ "error": { "code": "rate_limited", "message": "too many requests" } }
```

Нужно больше — напиши нам, поднимем под твою нагрузку (для интеграций поднимаем до тысяч запросов в минуту).

## Загружаемые картинки (референсы и vision)

Принимаем **PNG, JPEG, WEBP, HEIC** — сервер сам конвертирует в формат, который понимает провайдер выбранной модели (фото с iPhone работают без танцев).

| Что | Картиночные модели | Видео-модели |
|---|---|---|
| Макс. размер файла | до 50 МБ* | до 10 МБ |
| Промпт | до 32 000 символов* | до 5 000 символов |
| Кол-во референсов | по модели (до 14–16) | по модели (обычно 1–2) |

\* — точные значения зависят от модели: смотри `limits` у каждой модели в `GET /v1/models` (поля `max_prompt_chars`, `max_image_mb`, `image_formats`). Мы всегда показываем «минимальную планку» по самому строгому провайдеру модели — то, что точно пройдёт.

GIF и SVG не принимаются.

## Чат

- Тело запроса — до **25 МБ** (vision-картинки едут внутри JSON как data URL).
- Контекст и максимум токенов — по выбранной модели.

## Джобы

- Потолок генерации **картинок — 15 минут**, **видео — 90 минут** (с большим запасом от реальных времён: обычная картинка — секунды, тяжёлая — до пары минут). Если провайдер завис — джоба завершается `failed: model_unavailable` с **возвратом кредитов**, бесконечного `queued` не бывает.
- Если апстрим-провайдер не отвечает, СОЮЗ сам переключается на резервного — клиент этого не видит и получает `completed`.
- Результаты хранятся **~24 часа** — дальше `410 file_expired`. Скачивай сразу.

## Проверить лимиты модели

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

```json
{
  "id": "souz/kling-3",
  "modality": "video",
  "limits": { "max_prompt_chars": 5000, "max_image_mb": 10, "image_formats": ["png", "jpeg", "webp", "heic"] }
}
```

---

# Справочник API

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

Аутентификация — Bearer-ключ в каждом запросе (кроме файлов по подписанной ссылке):

```text
Authorization: Bearer sk-souz-...
```

Все запросы и ответы — JSON (`Content-Type: application/json`). Ошибки — единый формат `{ "error": { "code", "message", "type" } }`, подробности: [Ошибки](/errors).

---

## GET /v1/credits

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

```bash
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

Каталог моделей с возможностями, лимитами и тарифами.

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

Ответ: `{ "object": "list", "data": [ ... ] }`, элемент:

| Поле | Описание |
|---|---|
| `id` | ID модели (`souz/...`) — его передаёшь в `model` |
| `name` | Человеческое название |
| `modality` | `chat` / `image` / `video` |
| `capabilities.aspect_ratios` | Допустимые соотношения сторон |
| `capabilities.resolutions` | Разрешения (картинки): `1K`/`2K`/`4K` |
| `capabilities.durations` | Длительности (видео), сек |
| `capabilities.max_references` | Макс. референсов |
| `capabilities.requires_reference` | `true` — референс обязателен (например, оживление картинки) |
| `capabilities.advanced_params` | Белый список продвинутых полей |
| `pricing` | Правило цены (см. [Кредиты](/credits)) |
| `limits` | `max_prompt_chars`, `max_image_mb`, `image_formats` |

---

## POST /v1/chat/completions

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

**Тело:** стандартное OpenAI (`model`, `messages`, `stream`, `temperature`, `max_tokens`, `tools`, `response_format`, `reasoning_effort`, …). Лимит — 25 МБ.

**Ответ:** стандартный OpenAI `chat.completion` (или SSE-поток при `stream: true`). Дополнительно `usage.cost` — списанные кредиты.

**Ошибки:** `401`, `402 insufficient_credits`, `404 model_not_found`, `413`, `429`, `502 model_unavailable`.

---

## POST /v1/images/generations

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

| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
| `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` `auto` (по умолчанию `1:1`) |
| `resolution` | string | — | `1K` / `2K` / `4K` (по умолчанию `1K`) |
| `size` | string | — | OpenAI-стиль: `1024x1024` / `1792x1024` / `1024x1792` / `2048x2048` |
| `image` / `images` | string / string[] | — | Референсы: data URL или https URL |
| `callback_url` | string | — | Вебхук этой джобы |
| *прочие поля* | — | — | Продвинутые параметры модели (белый список) |

**Заголовки:** `Idempotency-Key` — защита от дублей при ретраях.

**Ответ `202`** (или `200`, если джоба уже разрешилась — например, идемпотентный повтор): объект джобы — см. ниже. При `callback_url` добавляется `webhook_secret` (показывается один раз).

---

## POST /v1/videos/generations

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

| Поле | Тип | Обяз. | Описание |
|---|---|---|---|
| `model` | string | ✅ | ID модели |
| `prompt` | string | ✅ | Описание (до 5000 символов) |
| `aspect_ratio` | string | — | `16:9` / `9:16` / `1:1` / `auto` (по умолчанию `16:9`) |
| `duration` | string\|number | — | Секунды (по умолчанию `5`; допустимые — у модели) |
| `image` / `images` | string / string[] | — | Референсы (data URL или https URL) |
| `callback_url` | string | — | Вебхук этой джобы |
| *прочие поля* | — | — | Продвинутые параметры модели: `mode`, `sound`, `negative_prompt`, … |

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

---

## GET /v1/jobs/{id}

Статус и результат джобы. Полное описание: [Джобы](/jobs).

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

| Поле | Описание |
|---|---|
| `id` | ID джобы |
| `object` | `image` / `video` / `chat` |
| `model` | Модель |
| `status` | `queued` → `in_progress` → `completed` / `failed` |
| `price` | Цена в кредитах |
| `created_at` | Unix-время создания |
| `data` | При `completed`: `[{ "url": "подписанная ссылка" }]` |
| `error` | При `failed`: `{ code, message, type }` |

---

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

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

**Ошибки:** `403 forbidden` (подпись истекла — перезапроси джобу), `410 file_expired` (файл удалён по сроку ~24 ч), `502 storage_unavailable`.

---

## POST /v1/webhooks

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

## 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 }`.

---

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

60 запросов/мин на ключ; `429` + `Retry-After` при превышении. Подробности: [Лимиты](/limits).
