# Сгенерировать музыку

`POST https://api.souz.ai/v1/audio/generations`

Трек по описанию — с текстом песни, который напишет модель, со своим текстом (`lyrics`)
или без вокала (`instrumental`). Ждёт результат и отвечает `200` с завершённой задачей:
звук — в `data[]`, у моделей, которые за один запрос дают два варианта трека, — оба, по
порядку. Не успело за 9 минут или прислан `Prefer: respond-async` — `202` с задачей в
работе.

Задача, провалившаяся во время ожидания, отвечает статусом по причине (`400`
`invalid_input`/`content_policy`/`capability_mismatch`, `502 generation_failed` или
`unknown_error`, `503 model_unavailable`) и телом — объектом задачи с `error`.

## Авторизация

- `BearerAuth`: API-ключ из кабинета souz.ai — запускает модели. Ключ управления здесь не подходит: `403 forbidden` с `detail[].reason: requires_api_key`.

## Параметры

| Имя | Где | Обязательно | Тип | Описание |
|---|---|---|---|---|
| `Prefer` | header | нет | `string` | RFC 7240. Понимаем `respond-async` — не ждать результат, сразу ответить `202` с задачей; остальные предпочтения игнорируются. Долгим моделям — вместе с `Idempotency-Key` и вебхуком (`callback_url`): ответ всегда `202`, один путь кода. |
| `Idempotency-Key` | header | нет | `string` | Строка до 255 символов, уникальная для аккаунта. Повтор с тем же ключом и параметрами возвращает ту же задачу с текущим статусом без новой задачи и повторного списания, в том числе при одновременных запросах, даже если настройки аккаунта за это время изменились: сравниваются только поля запроса. Другие параметры — `409 idempotency_key_conflict`; store и callback_url в сравнение не входят. У изображений, видео и музыки также не сравнивается response_format; у синтеза речи формат звука сравнивается. Ключ хранится вместе с задачей, сейчас без ограничения срока. Повтор задачи со статусом failed не запускает её заново: для новой попытки нужен новый ключ. Срок хранения файлов результата — `retention.files_days` из `GET /v1/key`; повтор его не продлевает. Поддерживается для генерации изображений, видео и музыки, транскрибации, синтеза речи и чата. У чата сравнивается тело запроса целиком; повтор дожидается идущего вызова и получает тот же ответ (и поток), что первый; ответ хранится сутки. |

## Тело запроса (`application/json`)

Схема `MusicGenerationRequest`.

| Поле | Обязательно | Тип | Описание |
|---|---|---|---|
| `action` | нет | `string`; значения: `generate`, `sounds`, `cover`, `extend`, `add_vocals`, `add_instrumental`, `mashup`, `replace_section`, `separate_vocals`, `split_stems`, `isolate_stem`, `wav`, `midi`, `video`, `cover_image`, `lyrics`, `boost_style`, `timestamps`, `persona`, `voice_validate`, `voice_generate`, `voice_regenerate`, `voice_check` | Действие с музыкой или звуком; без поля — создание музыки. |
| `audio_weight` | нет | `number` | Влияние аудиоэлементов; доступно и при создании в custom_mode. |
| `author` | нет | `string` | Автор. |
| `callback_url` | нет | `string, uri` | Куда прислать вебхук — https на публичный хост; без поля — адрес по умолчанию из настроек аккаунта. |
| `continue_at` | нет | `number` | С какой секунды продолжить исходный трек. |
| `custom_mode` | нет | `boolean` | Создание по своему стилю и тексту; для инструментала текст не нужен. |
| `description` | нет | `string` | Описание. |
| `domain_name` | нет | `string` | Подпись сайта. |
| `duration_seconds` | нет | `integer` | Желаемая длительность в режиме своего текста или стиля. |
| `end_seconds` | нет | `number` | Конец фрагмента. |
| `full_lyrics` | нет | `string` | Полный текст после замены. |
| `grab_lyrics` | нет | `boolean` | Сохранить текст звука. |
| `instrumental` | нет | `boolean | null` | Трек без вокала. |
| `language` | нет | `string` | Язык проверки голоса. |
| `lyrics` | нет | `string` | Текст песни — модель споёт его как написан; разделы размечаются `[Verse]`, `[Chorus]`, `[Bridge]`. Без поля текст пишет модель. Вместе с `instrumental` не присылается. |
| `max_price_multiplier` | нет |  |  |
| `model` | да | `string` |  |
| `name` | нет | `string` | Имя. |
| `negative_tags` | нет | `string` | Какие стили и элементы исключить. |
| `persona_id` | нет | `string` | ID задачи Союза, создавшей персону или голос. |
| `persona_model` | нет | `string`; значения: `style_persona`, `voice_persona` | Тип сохранённой персоны. |
| `prompt` | нет | `string` | Описание трека: жанр, настроение, инструменты, темп, голос. Язык текста песни, который напишет модель, — язык описания. В custom_mode и при lyrics это музыкальный стиль. |
| `reference_audio` | нет | `array` | Входные аудиофайлы — ссылки https или идентификаторы загруженных файлов. |
| `routing` | нет | схема `Routing` |  |
| `routing_options` | нет |  |  |
| `singer_skill_level` | нет | `string` | Уровень вокала. |
| `sound_key` | нет | `string` | Тональность звука из схемы параметров модели. |
| `sound_loop` | нет | `boolean` | Зацикленный звук. |
| `sound_tempo` | нет | `integer` | Темп звука в ударах в минуту. |
| `source_file` | нет | `string` | ID аудиофайла из data исходной задачи. |
| `source_job` | нет | `string` | ID готовой задачи Союза, принадлежащей вашему аккаунту. |
| `start_seconds` | нет | `number` | Начало фрагмента. |
| `stem_name` | нет | `string` | Дорожка или инструмент. |
| `store` | нет | `boolean | null` | `false` — запрос без хранения: тексты запроса и ответа не сохраняются; файлы живут обычный срок. По умолчанию тексты хранятся; `true` не отменяет режим без хранения аккаунта. |
| `style_weight` | нет | `number` | Точность следования стилю. |
| `title` | нет | `string` | Название в режиме своего текста или стиля и при переработке аудио. Без него — первая строка текста песни или описания. В простом режиме название выбирает модель. |
| `user` | нет | `string` | Поле OpenAI (id конечного пользователя); принимается, ни на что не влияет и не хранится. |
| `version` | нет | `string` | Версия модели из её схемы параметров. |
| `vocal_gender` | нет | `string`; значения: `m`, `f` | Предпочтительный вокал; результат не гарантирован. |
| `weirdness` | нет | `number` | Степень экспериментальности. |

## Пример запроса

```bash
curl -X POST 'https://api.souz.ai/v1/audio/generations' \
  -H "Authorization: Bearer $SOUZ_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{
  "instrumental": true,
  "model": "lyria-3-clip-preview",
  "prompt": "Спокойный лоуфай на пианино для учёбы"
}'
```

```python
import os
import requests

response = requests.post(
    "https://api.souz.ai/v1/audio/generations",
    headers={"Authorization": f"Bearer {os.environ['SOUZ_API_KEY']}"},
    json={
        "instrumental": True,
        "model": "lyria-3-clip-preview",
        "prompt": "Спокойный лоуфай на пианино для учёбы",
    },
)
print(response.json())
```

```ts
const response = await fetch("https://api.souz.ai/v1/audio/generations", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.SOUZ_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "instrumental": true,
    "model": "lyria-3-clip-preview",
    "prompt": "Спокойный лоуфай на пианино для учёбы"
  }),
});
console.log(await response.json());
```

## Ответы

### 200

Задача завершена, результат в `data`.

- `application/json`, схема `Job`

```json
{
  "attempt_count": 1,
  "completed_at": "2026-09-25T12:00:09Z",
  "created": 1758801600,
  "created_at": "2026-09-25T12:00:00Z",
  "currency": "RUB",
  "data": [
    {
      "bytes": 618240,
      "content_type": "image/jpeg",
      "created_at": "2026-09-25T12:00:09Z",
      "expired": false,
      "expires_at": "2026-10-02T12:00:09Z",
      "filename": "souz_nano-banana-pro_9f8e7d6c.jpg",
      "height": 1024,
      "id": "file_9f8e7d6c5b4a",
      "kind": "result",
      "object": "file",
      "role": "result",
      "type": "image",
      "url": "https://media.souz.ai/v1/files/file_9f8e7d6c5b4a/souz_nano-banana-pro_9f8e7d6c.jpg?exp=1759406400&sig=abc",
      "width": 1024
    }
  ],
  "error": null,
  "id": "job_1a2b3c4d5e6f",
  "max_price_multiplier": 2,
  "modality": "image",
  "model": "nano-banana-pro",
  "object": "job",
  "price": 5000000,
  "routing": "cheap",
  "routing_options": null,
  "status": "completed",
  "usage": null
}
```

### 202

Задача принята и выполняется.

- `application/json`, схема `Job`

```json
{
  "attempt_count": 0,
  "completed_at": null,
  "created": 1758801600,
  "created_at": "2026-09-25T12:00:00Z",
  "currency": "RUB",
  "data": [],
  "error": null,
  "id": "job_1a2b3c4d5e6f",
  "max_price_multiplier": null,
  "modality": "video",
  "model": "seedance-2",
  "object": "job",
  "price": null,
  "routing": "cheap",
  "routing_options": null,
  "status": "queued",
  "usage": null
}
```

### 400

Запрос не принят — `Error`; задача провалилась во время ожидания — объект задачи с `error` (то же поле, что у `Error`, поэтому разбирается одним кодом). `503` на плановых работах — `Error` с кодом `maintenance` (ответ `Maintenance`).

- `application/json`

### 401

Нет ключа или ключ недействителен.

- `application/json`, схема `Error`

### 402

Баланса не хватает на самый дешёвый канал с учётом запросов, которые ещё выполняются (`insufficient_balance`), или исчерпан лимит трат ключа (`key_spend_limit_exceeded`) либо участника, которому он выдан (`member_spend_limit_exceeded`). Повтор не поможет, пока баланс не пополнят, а лимит не начнётся заново или его не поднимут: потолок ключа со `spend_limit_reset: none` — на всё время ключа.

- `application/json`, схема `Error`

```json
{
  "error": {
    "code": "insufficient_balance",
    "message": "insufficient balance",
    "type": "billing_error"
  }
}
```

### 403

Нельзя: у ключа не тот вид (модели запускает API-ключ, аккаунт — ключ управления), у роли участника нет права или подпись ссылки на файл не сходится. `detail[].reason` говорит, что именно: `requires_api_key`, `requires_management_key`, `cabinet_only` (только в кабинете), `insufficient_role` (в `allowed` — роли, которым можно), `not_key_author` (секрет ключа открывает только тот, кто его создал).

- `application/json`, схема `Error`

```json
{
  "error": {
    "code": "forbidden",
    "detail": [
      {
        "reason": "requires_api_key"
      }
    ],
    "message": "this endpoint takes an API key; a management key manages the account only",
    "type": "permission_error"
  }
}
```

### 404

Нет такого объекта у этого аккаунта.

- `application/json`, схема `Error`

### 409

Тот же `Idempotency-Key` с другим телом.

- `application/json`, схема `Error`

### 413

Тело или файл больше предела (`invalid_input`, `detail[].reason: too_large`) или — только у `POST /v1/files` — загрузки аккаунта заняли квоту (`storage_limit_exceeded`).

- `application/json`, схема `Error`

### 415

Тип тела не тот, что принимает метод: `Content-Type: application/json` (у загрузки файла и транскрибации — `multipart/form-data`). В `detail[]` — `{"path": "body", "reason": "unsupported_format"}` и принимаемые типы.

- `application/json`, схема `Error`

### 429

Слишком часто — повторите через `Retry-After` секунд. Запуск моделей, задачи и файлы результатов частотой не ограничены (их ограничивают баланс и лимиты трат); здесь 429 — на поток запросов с ключом, который сервер не знает, с одного адреса, и на потоки сверх 1000 одновременных на аккаунт (события задачи, чат с `stream: true`). Пределы — раздел «Лимиты» руководства.

- `application/json`, схема `Error`

### 502

Запрос не принят — `Error`; задача провалилась во время ожидания — объект задачи с `error` (то же поле, что у `Error`, поэтому разбирается одним кодом). `503` на плановых работах — `Error` с кодом `maintenance` (ответ `Maintenance`).

- `application/json`

### 503

Запрос не принят — `Error`; задача провалилась во время ожидания — объект задачи с `error` (то же поле, что у `Error`, поэтому разбирается одним кодом). `503` на плановых работах — `Error` с кодом `maintenance` (ответ `Maintenance`).

- `application/json`

---

Оглавление документации: https://souz.ai/llms.txt. Всё руководство одним файлом: https://souz.ai/llms-full.txt. Справочник методов: https://souz.ai/docs/api-reference.md.
