Музыка
Музыка работает по той же асинхронной схеме, что и видео: задача, опрос, скачивание.
Создать трек
Заголовок раздела «Создать трек»import requests
job = requests.post( "https://api.mixen.ai/v1/audio/music", headers={"Authorization": f"Bearer {API_KEY}"}, json={"model": "suno", "prompt": "Меланхоличный синти-поп о ночном городе, женский вокал"},).json()print(job["id"], job["status"])const res = await fetch('https://api.mixen.ai/v1/audio/music', { method: 'POST', headers: { Authorization: `Bearer ${process.env.MIXEN_API_KEY}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ model: 'suno', prompt: 'Меланхоличный синти-поп о ночном городе, женский вокал' }),})const job = await res.json()console.log(job.id, job.status)curl https://api.mixen.ai/v1/audio/music \ -H "Authorization: Bearer $MIXEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "suno", "prompt": "Меланхоличный синти-поп о ночном городе, женский вокал"}'| Поле | Описание |
|---|---|
model |
suno / suno-v6 — песня с вокалом, два трека за запрос. lyria / lyria-pro — инструментал, один трек |
mode |
simple (по prompt) или custom (по lyrics + style + title). Lyria режим игнорирует |
prompt |
Описание трека для простого режима. Потолок зависит от модели: Suno — 3 000 символов в simple и 5 000 в custom (lyrics, поле ниже); Lyria жёсткого лимита не имеет |
lyrics |
Текст песни для авторского режима |
style |
Жанр, стиль, теги |
title |
Название трека |
Авторский режим
Заголовок раздела «Авторский режим»Когда нужен конкретный текст, а не сгенерированный:
{ "model": "suno-v6", "mode": "custom", "title": "Ночной трамвай", "style": "indie rock, 90s, мужской вокал, живые барабаны", "lyrics": "Первый куплет...\n\nПрипев..."}Опрос и скачивание
Заголовок раздела «Опрос и скачивание»curl https://api.mixen.ai/v1/audio/music/music_... \ -H "Authorization: Bearer $MIXEN_API_KEY"
curl -L https://api.mixen.ai/v1/audio/music/music_.../content \ -H "Authorization: Bearer $MIXEN_API_KEY" -o track.mp3Статусы те же: queued → in_progress → completed либо failed.
Suno возвращает два варианта трека за один запрос — это особенность модели, а не ошибка. Оба доступны в ответе на опрос статуса, конкретный трек скачивается параметром ?index=N эндпоинта /audio/music/{id}/content (нумерация с нуля, по умолчанию 0).
Задача, не завершившаяся за 15 минут, помечается failed при следующем опросе и не оплачивается.
Без опроса: webhook, ожидание, идемпотентность
Заголовок раздела «Без опроса: webhook, ожидание, идемпотентность»Три необязательных поля тела POST /v1/audio/music — общие для видео и музыки:
| Поле | Что делает |
|---|---|
webhook_url |
Публичный https-адрес. По статусу completed или failed мы шлём туда POST с тем же объектом задачи, что отдаёт GET. Приватные адреса и http:// отклоняются 400 invalid_webhook_url ещё до создания задачи |
wait |
true — запрос держится, пока задача не завершится, и возвращает финальный объект (ждём до wait_timeout, по умолчанию 60 с, максимум 300). По таймауту — объект как есть (in_progress), без ошибки |
idempotency_key |
До 128 символов. Повтор запроса с тем же ключом возвращает уже созданную задачу, а не новую (и не списывает второй раз); в ответе заголовок X-Mixen-Idempotent-Replay: true. Ключ уникален в пределах вашего аккаунта |
Заголовки webhook-запроса:
| Заголовок | Значение |
|---|---|
X-Mixen-Event |
music.completed или music.failed |
X-Mixen-Delivery |
id задачи |
X-Mixen-Signature |
t=<unix>,v1=<hex> — HMAC-SHA256 от строки "<t>.<сырое тело>"; секрет — sha256-hex вашего API-ключа (сам ключ мы не храним, его хэш вы считаете локально) |
Ваш эндпоинт должен ответить 2xx; иначе доставка повторится через 5, 20, 60 и 180 секунд. Гарантия — «хотя бы один раз»: обрабатывайте повторы по X-Mixen-Delivery идемпотентно. Проверка подписи:
import hashlib, hmac
def verify(raw_body: bytes, header: str, api_key: str) -> bool: secret = hashlib.sha256(api_key.encode()).hexdigest() parts = dict(kv.split('=', 1) for kv in header.split(',')) expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts.get('v1', ''))Музыка тарифицируется за запрос, а не за секунду: поле per_request_rub в каталоге. Два трека Suno — одна оплата.
Цена до запуска
Заголовок раздела «Цена до запуска»POST /v1/audio/music/price принимает то же тело, что и POST /v1/audio/music, и возвращает сумму, не запуская генерацию и ничего не списывая. Считается той же формулой, что и фактическое списание, поэтому котировка совпадает с чеком; валидация тоже общая — невалидные параметры дадут те же 400/404, что и запуск.
{ "object": "price", "model": "suno", "model_id": "suno-music-generate", "price": {"rub": 8.0047, "usd": 0.09}, "per_unit": {"rub": 8.0047, "unit": "generation"}, "quantity": 1, "params": {"mode": "simple", "tracks": 2}}Рублёвая сумма считается по живому курсу — берите котировку непосредственно перед запуском, а не кешируйте.