Генерация медиа

POST /api/media/generate — асинхронная генерация изображений, видео, TTS, музыки и 3D. Параметры model, prompt, opts. Опрос через GET /api/media/jobs/{id}.

Асинхронная генерация медиа: изображения, видео, озвучка (TTS), расшифровка речи (STT), музыка и 3D. Создаёте задачу и опрашиваете результат. Полный список моделей — в каталоге медиа-моделей; webhook, ошибки и биллинг — в разделе webhook.

POSThttps://plusvibeapi.ru/api/media/generate
GEThttps://plusvibeapi.ru/api/media/jobs/{id}

Параметры создания

ПараметрТипОписание
modelобяз.stringИмя медиа-модели, например veo-3.1 или gpt-image-2 (см. каталог).
promptобяз.stringТекстовое описание.
optsobjectДоп. параметры генерации (зависят от модели): разрешение, длительность и т. п.

Создание и опрос

Создание возвращает 202 с { ok: true, jobId, status: "processing" }. Опрашивайте GET /api/media/jobs/{jobId} до status: "success", затем заберите resultUrls.

# 1. создать задачу генерации
curl https://plusvibeapi.ru/api/media/generate \
  -H "Authorization: Bearer $PLUSVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "veo-3.1",
    "prompt": "кот на скейте, замедленная съёмка"
  }'
# → {"ok":true,"jobId":"...","status":"processing"}
Списание считается по фактическому объёму генерации (разрешение, длительность). Если модель недоступна или запрос отклонён, ответ приходит с ok: false без списания. Цены на сайте — ориентировочные; точная сумма списания возвращается в заголовке x-pv-cost-rub каждого принятого ответа (в рублях, с учётом нашей маржи). По умолчанию тело потока не меняется; для стоимости в финальном usage-событии передайте x-pv-cost: 1.

Расширенные параметры (opts)

Помимо model и prompt, в opts можно передать дополнительные параметры. Набор зависит от модели. Полный машиночитаемый контракт — через GET /api/model-capabilities (или GET /api/model-capabilities/{model} для конкретной модели).

Часто используемые расширенные параметры
ПараметрТипОписание
aspect_ratiostringСоотношение сторон: 1:1, 16:9, 9:16, 4:3, 3:4.
durationstring|numberДлительность видео в секундах (5, 10, 15).
resolutionstringРазрешение: 480p, 720p, 1080p, 4K.
image_urlstring (URL)Исходное изображение для I2V / image-to-image.
negative_promptstringЧто исключить из генерации (qwen-image, wan-2-7).
guidancenumberGuidance scale — точность следования промпту (flux-2, qwen-image, seedance).
seednumberSeed для воспроизводимого результата (flux-2).
stabilitynumberСтабильность 0–1 (hailuo, happyhorse, seedance, TTS).
camerastringДвижение камеры, напр. "pan left" (kling-3.0, hailuo).
first_frame_urlstring (URL)Первый кадр для I2V (kling-3.0, wan-2-7).
last_frame_urlstring (URL)Последний кадр для I2V (seedance, kling-3.0, wan-2-7).
reference_imagestring (URL)Референс для стиля/персонажа (happyhorse).
similarity_boostnumberСходство голоса 0–1 (ElevenLabs TTS).
speednumberСкорость речи 0.5–2 (ElevenLabs TTS).
Все параметры опциональны, если не указано иное. Неизвестный параметр игнорируется. Полный список с типами, диапазонами и примерами — в ответе GET /api/model-capabilities/{model}.

Свои файлы: base64 вместо ссылки

Поля с URL (image_url, input_urls, mask_url и другие) — это ссылки, которые скачивает провайдер, поэтому в них принимаются только публичные https:// адреса. Инлайн-строка data:image/...;base64,… в таком поле отклоняется с 400.

Чтобы отправить свой файл, положите его в парное *_base64 поле: сервис сам сохранит байты, опубликует их и подставит ссылку провайдеру. Максимум 16 файлов в input_base64 за запрос.

Инлайн-файлы
ПараметрТипОписание
image_base64stringИсходное изображение. Заменяет image_url.
mask_base64stringМаска для inpainting (только image/*). Заменяет mask_url.
input_base64string[]Референсы для image-to-image и мультиввода. Заменяет input_urls.
audio_base64stringИсходный звук. Заменяет audio_url.
video_base64stringИсходное видео. Заменяет video_url.
Значение — это полная строка вида data:image/png;base64,…, включая префикс: по нему определяется тип файла.

Контракт запроса: strict, quote_id, max_price_rub

POST /api/media/generate и POST /api/media/price принимают одно и то же тело, поэтому его можно сначала оценить, а затем отправить без изменений. Других полей верхнего уровня нет: неизвестное поле отклоняется на обоих адресах ответом 400 с кодом unknown_field и именем поля (field, fields), со strict и без него. Параметры генерации передаются внутри opts.

Поля верхнего уровня
ПараметрТипОписание
modelобяз.stringПубличный id модели или её маршрут (base:alias).
promptstringТекст; обязателен, только если его требует операция модели.
optsobjectПараметры модели. Точная схема — operations[].requestJsonSchema в GET /v1/model-capabilities/{model}.
strictbooleanСтрогий режим (или заголовок x-plusvibe-strict: 1): запрос, который не выполнится ровно как написан (параметр будет отброшен, значение обрезано, ключ не из контракта модели), отклоняется 422 strict_validation_failed со списком violations до расчёта цены и списания. Документированное поле, которое модель принимает и игнорирует (duration у моделей с длиной по входному файлу), нарушением не считается — приходит предупреждение param_ignored.
quote_idstringmq_… из ответа POST /api/media/price. Задача запустится только по этой цене; устаревшая, использованная или сменившая маршрут котировка отклоняется 409/422 до запуска.
max_price_rubnumberПотолок стоимости одной задачи в валюте счёта. Если котировка выше — 422 media_max_price_exceeded, ничего не запущено. Задача с оплатой по счётчику никогда не списывается выше этого числа.
webhook_urlstringПубличный https-адрес для подписанного уведомления о завершении.

Файлы по id (Files API)

Любой исходный файл можно передать тремя способами: ссылкой (image_url, audio_url, video_url…), инлайн-байтами (image_base64, audio_base64, video_base64…) или id своего файла из POST /v1/files. Поля с id перечислены в requestJsonSchema каждой операции и принимаются в строгом режиме.

ПараметрТипОписание
image_file_idstringВместо image_url.
audio_file_idstringВместо audio_url.
video_file_idstringВместо video_url.
mask_file_idstringВместо mask_url.
first_frame_file_id / last_frame_file_idstringВместо first_frame_url / last_frame_url.
input_file_idsstring[]Добавляются к input_urls.
reference_*_file_idsstring[]Добавляются к reference_image_urls / reference_audio_urls / reference_video_urls.

Цена видео по длине входного файла

У моделей, где длину результата задаёт загруженная дорожка — kling-ai-avatar, omnihuman-v1.5, omnihuman-1-5, volcengine-lipsync (аудио), kling-motion-control, wan-animate, topaz-video-upscale (видео), lipsync-2-pro, sync-3, react-1 (оба входа), — /api/media/price и предварительная проверка max_price_rub на /api/media/generate меряют длину этого файла на сервере (ссылка, data:-строка, base64 или *_file_id) и считают цену за измеренные секунды. В ответе — sourceSeconds (или outputSeconds у липсинка), а estimateReason говорит, что длина измерена. Если файл прочитать не удалось, цена считается по прежнему основанию (одна секунда, оценочная длительность каталога или максимум маршрута), и estimateReason прямо это называет. Итог списания — цена за секунду × фактические секунды результата, не выше max_price_rub. opts.duration у этих моделей принимается и игнорируется с предупреждением param_ignored.

Клонирование голоса

POSThttps://plusvibeapi.ru/api/media/voices
GEThttps://plusvibeapi.ru/api/media/voices
POSThttps://plusvibeapi.ru/api/media/voices/{voice_id}/samples
DELETEhttps://plusvibeapi.ru/api/media/voices/{voice_id}

Создание: { name, consent: true, engine, audio_url | audio_base64 } или несколько записей samples: [{ audio_url } | { audio_base64 }, …] (только engine: "elevenlabs"). Голосом ElevenLabs синтезирует voice-clone-tts и пользуется Смена голоса (elevenlabs-voice-changer). Добавление записей к голосу ElevenLabs бесплатно. Каждая запись скачивается и измеряется до обращения к поставщику: при отказе ничего не меняется и не списывается.

Лимиты и коды ошибок
ПараметрТипОписание
одна запись≤ 10 MBwav/mp3, до 60 с. Больше — 422 voice_sample_too_large / voice_sample_invalid.
записей на голос≤ 25Считая уже добавленные. Больше — 422 voice_samples_limit.
длительность голоса≤ 300 sВсе записи вместе, считая уже добавленные. Больше — 422 voice_samples_limit; короче минимума движка — 422 voice_samples_invalid.
размер записей≤ 50 MBВсе записи одного запроса вместе. Больше — 422 voice_samples_too_large.
тело запроса≤ 70 953 644 B50 MB записей в base64 (×4/3) плюс JSON. Больше — 413 payload_too_large (JSON, с max_body_bytes). Длинные наборы отправляйте частями через …/samples или ссылками audio_url.
добавлений в сутки20На клиента. Больше — 429 voice_samples_rate_limited.
Прочие ответы: 404 voice_not_found (неизвестный, удалённый или чужой голос), 409 voice_samples_unsupported (добавлять записи можно только к голосу ElevenLabs), 409 voice_slots_full, 502 voice_samples_failed (поставщик не принял записи, голос не изменён). Голос ElevenLabs оплачивается раз в месяц; цены — в ответе GET /api/media/voices (pricing).

Смена голоса и выравнивание текста

ПараметрТипОписание
elevenlabs-voice-changermodelopts.voice_id (ваш голос ElevenLabs) + исходная запись opts.audio_url | audio_base64 | audio_file_id, до 5 минут. Цена — по измеренной длине записи: 1 минута = 1000 символов.
forced-alignmentmodelprompt — текст записи, opts.audio_url | audio_base64 | audio_file_id — запись. Результат: тайминги слов в resultMeta.words и SRT-файл в resultUrls. Цена — за 1000 символов текста.

Песочница: неизвестный исход отправки

Если подтверждение запуска от поставщика не пришло, задача остаётся в status: "submitting" со stage: "submission_unknown", errorCode: "media_submission_uncertain" и failure.advice: "reconcile_first" — опрашивайте тот же jobId и не создавайте дубль. Чтобы проверить эту ветку без затрат, отправьте POST /api/media/generate sandbox-ключом с заголовком x-pv-sandbox-outcome: submission_uncertain. Ответ — обычный 202 с jobId; опрос этого jobId 60 секунд отвечает как неопределённая отправка, затем — как незапущенная задача (failure.code: "submission_not_started", charged: false). Ничего не сохраняется, поставщику не отправляется и не списывается. Обычный ключ с этим заголовком получает 400 sandbox_outcome_requires_sandbox_key.

Расшифровка речи (speech-to-text)

Тот же эндпоинт, что и остальная генерация: в model — имя STT-модели, prompt оставьте пустой строкой, а ссылку на запись передайте в opts.audio_url. Готовый текст приходит в поле resultText ответа GET /api/media/jobs/{id}; resultUrls у расшифровки пустой — файла на выходе нет.

# расшифровка речи: создать задачу и дождаться текста
curl https://plusvibeapi.ru/api/media/generate \
  -H "Authorization: Bearer $PLUSVIBE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "whisper-large-v3-turbo",
    "prompt": "",
    "opts": {
      "audio_url": "https://example.com/meeting.mp3",
      "language_code": "ru"
    }
  }'
# → {"ok":true,"jobId":"JOB_ID","status":"processing","priceRub":0.03}

curl https://plusvibeapi.ru/api/media/jobs/JOB_ID \
  -H "Authorization: Bearer $PLUSVIBE_API_KEY"
# → {"status":"success","resultText":"расшифрованный текст…","resultUrls":[],"priceRub":0.03}

Модели

  • whisper-large-v3-turbo — 0,02 ₽ за минуту записи. Самая дешёвая и самая быстрая, 99 языков.
  • nemotron-asr-multilingual — 0,02 ₽ за минуту. Многоязычная модель NVIDIA, ставит пунктуацию сама.
  • whisper-large-v3 — 0,06 ₽ за минуту. Полная версия Whisper: медленнее turbo, точнее на шумной записи.
  • universal-2 — 0,35 ₽ за минуту. Сильна на русской речи, разделяет говорящих.
  • speech-to-text — 1 ₽ за минуту (ElevenLabs Scribe). Умеет разделение по говорящим и метки звуковых событий.

Параметры

ПараметрТипОписание
audio_urlобяз.string (URL)Публичная https-ссылка, отдающая файл напрямую. Переадресации и внутренние адреса сети не принимаются. Вместо неё можно передать audio_base64.
audio_base64stringБайты записи строкой data:audio/mpeg;base64,… — если файла нет в интернете. Заменяет audio_url.
language_codestringКод языка (ru, en, …). Без него язык определяется автоматически.
duration_minutesnumberДлительность записи в минутах — по ней считается предварительная стоимость до запуска. Итог по факту (см. ниже).
diarizebooleanРазделение по говорящим (universal-2, speech-to-text).
tag_audio_eventsbooleanМетки звуковых событий: смех, аплодисменты (speech-to-text).
keytermsstring[]Подсказка со списком терминов и имён (speech-to-text; +30% к цене).

Форматы и ограничения

Принимаются mp3, wav, m4a/mp4, flac, ogg/opus и webm. Размер файла — не более 25 МБ (это примерно 26 минут mp3 128 kbps или несколько часов речи в opus). Файл больше лимита отклоняется сразу, с явным сообщением, и не тарифицируется — режьте запись на части.

Списание идёт за минуту звука. У моделей whisper-large-v3-turbo, whisper-large-v3 и nemotron-asr-multilingual итоговая сумма считается по фактической длине записи, измеренной по расшифровке, а не по тому, что вы указали в duration_minutes. Минимальное списание — одна копейка. Точная сумма всегда возвращается в priceRub завершённой задачи.

Webhook готовности (вместо опроса)

Чтобы не опрашивать задачу, зарегистрируйте в личном кабинете один адрес mediaWebhookUrl. Когда задача завершится (успехом или ошибкой), сервис выполнит до пяти попыток доставки POST с JSON-телом:

// POST на ваш mediaWebhookUrl при завершении задачи
{
  "jobId": "...",
  "status": "success",            // или "fail"
  "model": "veo-3.1",
  "kind": "video",                // image | video | audio | music | 3d
  "resultUrls": ["https://plusvibeapi.ru/api/media/file/..."],
  "failMsg": null,
  "createdAt": "2026-06-17T10:00:00.000Z"
}
Подробности доставки, коды ошибок и биллинг — в Webhook и жизненный цикл медиа-задач. Кратко: webhook подписан заголовками Standard Webhooks, дубликаты возможны, а после пяти неудачных попыток доставка прекращается. Опрос остаётся источником состояния.

Получение файла: /api/media/file/{id}/{idx}

GEThttps://plusvibeapi.ru/api/media/file/{id}/{idx}

URL результата генерации (изображение, видео, аудио или 3D-модель) из resultUrls. Используйте его как возвращённый сервисом URL: он открывается без API-ключа и подходит для <img>, <video> или браузер. Провайдер скрыт: upstream-адрес резолвится на сервере, клиент его не видит.

Параметры пути и запроса
ПараметрТипОписание
idобяз.string (path)ID задачи (jobId) из ответа /api/media/jobs/{id}.
idxобяз.integer (path)Индекс результата (0-базированный). Для одного результата — 0.
query-параметрыкак в resultUrlsНе конструируйте URL самостоятельно и не изменяйте параметры, возвращённые сервисом.
downloadstring (query)download=1 — отдать файл как вложение с именем и расширением по содержимому (.glb для 3D-модели). Без него файл открывается в браузере.
# Подписанный URL возвращается в resultUrls ответа /api/media/jobs/{id}
# или в теле webhook. Открывается напрямую в браузере / <img> — без ключа.
https://plusvibeapi.ru/api/media/file/JOB_ID/0?sig=HMAC_SIGNATURE
Результаты хранятся 7 дней после завершения задачи (поле resultsExpireAt в ответе /api/media/jobs/{id}). Готовый файл копируется в наше хранилище, и resultUrls переключаются на постоянный адрес вида https://plusvibeapi.ru/media/r/…; ранее выданный URL /api/media/file/… тоже продолжает работать. Оба поддерживают Range-запросы (перемотка видео и аудио). После 7 дней файл удаляется, и URL отвечает 410 Gone с кодом media_result_expired — сохраните нужные файлы у себя заранее.
Генерация медиа API PlusVibe — image, video, audio, music, 3D | PlusVibe API