API429 / Генерация видео

Video API: создать задачу и сохранить job ID

Начните с одной короткой text-to-video задачи и сохраните её идентификатор до ожидания результата. Для gemini-omni-1.1-flash клиентский справочник описывает создание задачи и чтение по job ID. Важно различать принятую задачу, завершённый результат и неизвестный формат ответа.

Контракт сверен . Опубликовано ; обновлено . Проверены публичные источники и примеры с искусственными ответами. Успешное платное выполнение под клиентским ключом здесь не заявляется.

Что отправить в первом запросе

Перед платным запуском найдите точный ID gemini-omni-1.1-flash в GET /v1/models под своим ключом. Публичная публикация модели и доступ конкретного клиента — разные проверки. Пример ниже использует POST /v1/videos/generations и только text-to-video: model, prompt, duration=5, aspect_ratio=16:9, resolution=720p и n=1. Это ограниченный исходный сценарий, а не доказательство совместимости со всеми нативными режимами модели.

Клиентский справочник задаёт длительность от 3 до 10 секунд, один результат и соотношение сторон 16:9 либо 9:16. Аудио генерируется всегда; audio:false не подходит, поэтому поле audio в примере отсутствует. Не добавляйте seed или параметры соседней модели по аналогии. Сначала сформулируйте одну простую сцену и убедитесь, что можете проверить её содержание, движение и звук после получения результата.

Принять задачу и сохранить идентификатор

Документированный ответ создания имеет HTTP 202, object=video.generation.job, верхнеуровневый id и status=queued. Сохраните id сразу, до первого ожидания: пример пишет video-job.json. Храните идентификатор вместе с исходными параметрами в своём приложении, без API-ключа. Сбой ожидания не должен приводить к потере связи с уже принятой задачей. Если ответ создания оказался неизвестным, не отправляйте новый POST автоматически.

Для чтения используется GET /v1/videos/generations/{job_id} с тем же клиентским ключом. Пример ограничивает ожидание двенадцатью чтениями и тремя минутами; пауза пять секунд — выбранная политика клиента, а не обещание скорости сервера. При ошибке сети, неизвестном состоянии или истечении времени он останавливается с сохранённым job ID. Продолжайте выяснение судьбы этой задачи, а не создавайте замену вслепую.

Граница известного формата результата

Справочник называет успешное состояние succeeded и отдельно показывает объект вывода object=video.generation с точным model и массивом data, где элементы содержат url и mime_type=video/mp4. Однако полный конверт успешного GET, объединяющий состояние с результатом, в проверенном примере не установлен. Поэтому код не угадывает вложенность result.data или других полей и принимает только отдельно документированную форму вывода.

Ответ succeeded без такого вывода останавливает автоматическую обработку: сохраните job ID, изучите ответ без секретов и сверяйтесь с актуальным справочником. Неизвестное состояние также требует ручной проверки. При распознанном объекте проверяются число результатов, HTTPS-ссылка и ожидаемый MIME. Ссылка ещё не доказывает корректность файла: загрузите его отдельно, не пересылая Authorization на сторонний адрес, и проверьте контейнер, воспроизведение, длительность и содержание.

Бюджет, повторные попытки и завершение работы

У точного видео-ID публичный каталог показывает переменную стоимость без строк ставок. Поэтому здесь нет числовой цены, калькулятора или обещания фиксированной суммы за ролик. Отсутствие ставки не означает бесплатную генерацию. До запуска производственного объёма подтвердите применимые клиентские условия оплаты и сохраняйте данные каждой попытки для сверки расхода.

В справочнике видеозапроса встречается Idempotency-Key, но срок хранения, область действия и финансовая гарантия повтора для видео здесь не подтверждены. Не переносите условия другого метода. Пример выполняет один POST и не повторяет его автоматически. Таймаут чтения не означает отмену задачи или отсутствие списания. Документированный метод отмены этой сверкой также не установлен; завершайте наблюдение осознанно, сохраняя ID для дальнейшей проверки.

Проверенные ID и текущие единицы API429

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

Точный IDСтатус и единицы
gemini-omni-1.1-flashОпубликована в свежем каталоге

Переменная стоимость: ставки для расчёта не опубликованы.

Дата каталога: . Числовые ставки скрываются при устаревших, неоднозначных или неподтверждённых данных; внешние цены производителей здесь не приводятся.

Первый запрос: Python и JavaScript

Выберите один пример и запускайте его на сервере. Установите API429_API_KEY через защищённое окружение; для ElevenLabs также нужен подтверждённый API429_VOICE_ID. Код сначала проверяет доступ через GET /v1/models, затем выполняет один платный запрос. Повторный запуск файла создаёт новую попытку: сначала разберите предыдущую.

Видео: один POST, сохранение ID и ограниченный GET

Python 3 — gemini-omni-1.1-flash
import json
import os
import re
import time
import urllib.parse
import urllib.request
from pathlib import Path

key = os.environ["API429_API_KEY"]
base = "https://gateway.api429.com/v1"
headers = {"Authorization": "Bearer " + key, "Content-Type": "application/json"}
model = "gemini-omni-1.1-flash"
try:
    with urllib.request.urlopen(urllib.request.Request(base + "/models", headers=headers), timeout=30) as response:
        available = {item["id"] for item in json.load(response)["data"]}
except Exception:
    raise ValueError("Invalid models response; stop before generation") from None
if model not in available:
    raise ValueError("Model unavailable to this key")
payload = json.loads("{\"model\":\"gemini-omni-1.1-flash\",\"prompt\":\"A slow camera move around a blue ceramic cup on a table\",\"duration\":5,\"aspect_ratio\":\"16:9\",\"resolution\":\"720p\",\"n\":1}")
request = urllib.request.Request(base + "/videos/generations", data=json.dumps(payload).encode("utf-8"), headers=headers, method="POST")
# One paid POST only. On an ambiguous submit, investigate; do not rerun blindly.
try:
    with urllib.request.urlopen(request, timeout=60) as response:
        job = json.load(response)
        submit_status = response.status
except Exception:
    raise ValueError("Ambiguous submission; job ID unknown; inspect original attempt, no new POST") from None
job_id = job.get("id") if isinstance(job, dict) else None
if not isinstance(job_id, str) or not re.fullmatch(r"[A-Za-z0-9_-]{1,200}", job_id):
    raise ValueError("Unknown submission; investigate before any new POST")
Path("video-job.json").write_text(json.dumps({"id": job_id}), encoding="utf-8")
def stop(reason):
    raise RuntimeError(reason + "; job ID: " + job_id + "; inspect this job, no new POST") from None
if submit_status != 202 or job.get("object") != "video.generation.job" or job.get("status") != "queued":
    stop("Unknown submission shape")
url = base + "/videos/generations/" + urllib.parse.quote(job_id, safe="")
# Client policy: 12 reads, 5-second pause, 180-second deadline; no server timing guarantee.
deadline = time.monotonic() + 180
for attempt in range(12):
    remaining = deadline - time.monotonic()
    if remaining <= 0:
        stop("Client deadline")
    try:
        with urllib.request.urlopen(urllib.request.Request(url, headers=headers), timeout=min(30, remaining)) as response:
            output = json.load(response)
    except Exception:
        stop("Read failed")
    if time.monotonic() >= deadline:
        stop("Client deadline")
    if not isinstance(output, dict):
        stop("Malformed response")
    if output.get("object") == "video.generation":
        items = output.get("data")
        if output.get("model") != model or not isinstance(items, list) or len(items) != 1 or not isinstance(items[0], dict):
            stop("Malformed output")
        item = items[0]
        try:
            parsed = urllib.parse.urlsplit(item.get("url", ""))
            valid_url = parsed.scheme == "https" and bool(parsed.hostname) and parsed.username is None and parsed.password is None
        except (ValueError, TypeError):
            valid_url = False
        if item.get("mime_type") != "video/mp4" or not valid_url:
            stop("Unexpected video URL or MIME")
        # Review/download separately. Never forward API429 Authorization to this URL.
        print(item["url"])
        break
    if output.get("object") != "video.generation.job" or output.get("id") != job_id:
        stop("Unknown GET envelope")
    if output.get("status") == "succeeded":
        stop("Succeeded but full output envelope unverified")
    if output.get("status") != "queued":
        stop("Unknown state")
    time.sleep(min(5, max(0, deadline - time.monotonic())))
else:
    stop("Client read limit")
JavaScript для Node.js — gemini-omni-1.1-flash
import { writeFile } from "node:fs/promises";
const key = process.env.API429_API_KEY;
if (!key) throw new Error("Set API429_API_KEY");
const base = "https://gateway.api429.com/v1";
const headers = { Authorization: "Bearer " + key, "Content-Type": "application/json" };
const model = "gemini-omni-1.1-flash";
const available = await fetch(base + "/models", { headers, signal: AbortSignal.timeout(30000) });
if (!available.ok) throw new Error("Models HTTP " + available.status);
let availableModels;
try { availableModels = await available.json(); }
catch { throw new Error("Invalid models response; stop before generation"); }
if (!Array.isArray(availableModels?.data)) throw new Error("Invalid models response; stop before generation");
if (!availableModels.data.some(item => item && item.id === model)) throw new Error("Model unavailable to this key");
// One paid POST only. Do not repeat an ambiguous submission automatically.
const submitted = await fetch(base + "/videos/generations", {
 method: "POST", headers, body: JSON.stringify({"model":"gemini-omni-1.1-flash","prompt":"A slow camera move around a blue ceramic cup on a table","duration":5,"aspect_ratio":"16:9","resolution":"720p","n":1}), signal: AbortSignal.timeout(60000)
});
let job;
try { job = await submitted.json(); }
catch { throw new Error("Ambiguous submission; job ID unknown; inspect original attempt, no new POST"); }
if (!job || typeof job.id !== "string" || !/^[A-Za-z0-9_-]{1,200}$/.test(job.id)) throw new Error("Unknown submission; investigate before any new POST");
await writeFile("video-job.json", JSON.stringify({ id: job.id }));
function stop(reason) { throw new Error(reason + "; job ID: " + job.id + "; inspect this job, no new POST"); }
if (submitted.status !== 202 || job.object !== "video.generation.job" || job.status !== "queued") stop("Unknown submission shape");
const url = base + "/videos/generations/" + encodeURIComponent(job.id);
// Client policy, not a server guarantee: 12 reads, 5-second pause, 180-second deadline.
const deadline = Date.now() + 180000;
let complete = false;
for (let attempt = 0; attempt < 12; attempt++) {
 const remaining = deadline - Date.now();
 if (remaining <= 0) stop("Client deadline");
 let output;
 try {
  const response = await fetch(url, { headers, signal: AbortSignal.timeout(Math.min(30000, remaining)) });
  if (!response.ok) stop("Read HTTP " + response.status);
  output = await response.json();
 } catch { stop("Read failed"); }
 if (Date.now() >= deadline) stop("Client deadline");
 if (!output || typeof output !== "object" || Array.isArray(output)) stop("Malformed response");
 if (output.object === "video.generation") {
  if (output.model !== model || !Array.isArray(output.data) || output.data.length !== 1 || !output.data[0]) stop("Malformed output");
  const item = output.data[0];
  let parsed;
  try { parsed = new URL(item.url); } catch { stop("Invalid video URL"); }
  if (parsed.protocol !== "https:" || parsed.username || parsed.password || item.mime_type !== "video/mp4") stop("Unexpected video URL or MIME");
  // Review/download separately; never forward API429 Authorization to this URL.
  console.log(parsed.href);
  complete = true;
  break;
 }
 if (output.object !== "video.generation.job" || output.id !== job.id) stop("Unknown GET envelope");
 if (output.status === "succeeded") stop("Succeeded but full output envelope unverified");
 if (output.status !== "queued") stop("Unknown state");
 await new Promise(resolve => setTimeout(resolve, Math.min(5000, Math.max(0, deadline - Date.now()))));
}
if (!complete) stop("Client read limit");

Если сохранён video-job.json, не запускайте файл заново ради проверки. Возьмите его id и читайте только GET /v1/videos/generations/{job_id} с тем же ключом через текущий клиентский справочник. Не публикуйте ключ или полный ответ с пользовательскими данными. Пример выводит проверенную HTTPS-ссылку без скачивания: отдельно проверьте адрес и файл, не пересылайте заголовок Authorization на адрес результата.

Дальнейший маршрут

Каталог моделей · Документация · Условия и тарифы

Оплата и тест $10

  • Карта российского банка. Пополнение баланса в личном кабинете.
  • Счёт для юрлиц. Безналичная оплата с закрывающими документами.
  • USDT и TON. Пополнение криптовалютой.

Тест $10. Подпишитесь на наш Telegram-канал через бота — получите $10 на баланс для первых запросов. Получить $10 в боте

Частые вопросы

Что означает HTTP 202?

Это принятие асинхронной задачи, а не готовое видео. Проверьте документированный объект и сохраните верхнеуровневый id. Далее читайте существующую задачу через GET /v1/videos/generations/{job_id}.

Что делать после таймаута или неизвестного статуса?

Остановите автоматическое ожидание и сохраните job ID. Проверьте ту же задачу по справочнику либо обратитесь с её ID в поддержку. Новый POST не выполняется автоматически; таймаут не устанавливает отмену или отсутствие оплаты.

Где искать ссылку в успешном GET?

Документирован отдельный video.generation с data[].url и MIME video/mp4. Полная вложенность успешного GET не установлена. Если ответ имеет другую оболочку, пример сохраняет ID и требует дополнительной сверки вместо угадывания пути.

Есть ли фиксированная цена и гарантия безопасного повтора?

Каталог показывает переменную стоимость без ставок для расчёта. Наличие Idempotency-Key в примере не устанавливает для видео срок хранения или гарантию отсутствия повторного списания. Условия нужно подтвердить до масштабирования.

Источники и границы проверки

Клиентский справочник определяет параметры и ответы; каталог — опубликованные точные ID и единицы. Сокращённая OpenAPI не содержит всех разделов полного справочника. Анонимная сверка источников от не подтверждает права ключа или запуск генерации.

Telegram