Генерация видео
/v1/videosСтавит генерацию видео в очередь: 202 с id джобы, либо готовый результат сразу при wait: true.
Запрос
modelstringbodyобязательноGET /cabinet/api/public/media-models)promptstringbodyобязательноdurationnumberbodysecondsnumberbodyduration; если переданы оба, duration побеждаетaspect_ratiostringbody= 16:9imagestring|arraybodyvideostring|arraybodyimagewaitbooleanbody= falsetrue — держать соединение и вернуть результат, но не дольше 90 сtimeoutnumberbody= 90waitref_video_job_idstringbodyscenesstring|arraybodyОтветы
wait: true
{
"id": "vid_9f1c4a2b7e0d4f5a8c3b6d1e2f0a7b4c",
"status": "completed",
"created": 1757500800,
"duration": 5.0,
"cost_usd": "0.95",
"data": [
{ "url": "https://api.teamtoken.store/v1/videos/vid_9f1c4a2b7e0d4f5a8c3b6d1e2f0a7b4c/content" }
]
}Подробности
Нужен ключ в заголовке Authorization: Bearer или x-api-key.
Генерация асинхронная. По умолчанию ручка отвечает 202 с id джобы и суммой резерва (estimated_cost_usd), а результат забирается через GET /v1/videos/{job_id}. С wait: true (и с любым переданным timeout) шлюз опрашивает провайдера сам — шаг опроса 2 с, потолок ожидания 90 с, и timeout только уменьшает этот бюджет, поднять его выше нельзя. Не успело — придёт 202 с тем же id, джоба остаётся в работе. Опрашивать не обязательно: реконсайлер (проход раз в 150 с) сам досчитает завершившуюся джобу, спишет деньги и сохранит ссылки на результат.
Режимов входа три, и выбирает их не URL, а поля тела: prompt — text-to-video; prompt + image — image-to-video; prompt + video — video-to-video (edit и motion control, где image — персонаж, а video — движение). Что движок сделает со входом, решает он; наша проверка одна — движку, которому входное видео обязательно, запрос без него получает 400 ещё у нас, до провайдера. Список моделей живёт в каталоге (GET /cabinet/api/public/media-models), но обязательность входа и наборы длительностей каталог не отдаёт: это таблица на нашей стороне, наружу видная только текстом ошибки.
/v1/video/generations, /v1/videos/extend и /v1/videos/storyboard — алиасы этого же обработчика: то же тело, те же ответы и ошибки, разницы в поведении между путями нет. Продолжение ролика и сториборд задаются моделью — в каталоге это отдельные движки (*-extend, *-storyboard), — а исходный ролик передаётся полем ref_video_job_id.
Про поля. Длительность и её набор — за движком: seedance — 4–15 с (по умолчанию 5) · kling — 3–15 у 3.0, 3–10 у edit/o1/motion (5) · kling 2.5/2.6 — только 5 или 10 · kling 2.1 — ровно 10 либо ровно 5, смотря какая модель · veo — 4/6/8 (8) · omni-flash — 4/6/8/10, но каждая строка каталога прибита к одному из них · grok — только 6 · extend — 8 у veo, 6 у grok, 4–15 у seedance · сториборд — 6–30 (6). Значение вне набора → 400 с перечислением допустимых (у диапазона — границ). ⚠️ Строка каталога может прибить длительность жёстко (fixed_params) — тогда переданный duration до провайдера не доезжает. ⚠️ Без duration провайдеру уйдёт значение движка по умолчанию, а резерв посчитается по МАКСИМУМУ движка (hold_duration_seconds); списание — по фактической длительности готового ролика. timeout ограничен теми же 90 с, нечисловое значение — те же 90.
Вход принимается под несколькими именами: image — это же images, image_url, image_urls, input_image, init_image, ref_images, а video — videos, video_url, input_video, motion_video, ref_video, ref_videos. URL — картинки и видео одинаково — шлюз скачивает сам (свой User-Agent, свой лимит, запрет внутренних адресов на каждом редиректе); не скачалось или пришло не похожее на медиа тело — ссылка уходит провайдеру как есть. ⚠️ Вход, которого движок не ждёт, шлюз всё равно передаёт провайдеру: каталог сверяется только на обязательность. А параметры вне набора движка (resolution, size, любое незнакомое поле) отбрасываются молча — разрешение и тир задаёт каталог, не запрос.
До провайдера 400 дают: битый JSON, неизвестная или выключенная модель, отсутствующий prompt, duration вне набора движка, обязательный и не переданный вход, вход больше 80 МБ (предел на один декодированный файл). ref_video_job_id проверяется по владельцу: чужой или несуществующий id → 404, чтобы утёкший id ничего не подтверждал. Отказ провайдера на сабмите: его 4xx доезжает как есть — с его кодом и очищенной от имён апстрима причиной, — и это окончательно, джоба failed, резерв снят; 5xx или сеть означают, что заявка МОГЛА быть принята, и возврат наугад был бы двойным зачислением — джоба уходит в unknown_submit и ждёт реконсайлера, который либо её завершит, либо освободит резерв по TTL (у unknown_submit он короткий, 15 минут по умолчанию, у остальных — сутки).