動画生成 非同期タスク OpenAI 互換 メディアプロキシ API 統合

動画生成 API 統合:タスク、ポーリング、コンテンツ

create/poll/content フロー、編集・延長・キャラクター、webhook、時間上限、認可付きメディア配信を含む動画生成統合を解説します。

AveMujica API 4 分で読めます

動画生成 API 統合は、ジョブを作成し、完了または失敗まで待ち、失効する可能性があり認可を必要とする content URL からバイトをダウンロードする非同期メディアワークフローです。Videos サーフェスに従う OpenAI 互換ゲートウェイでは、主要ルートは POST /v1/videos、GET /v1/videos/{task_id}、GET /v1/videos/{task_id}/content です。現在の OpenAI 公式ドキュメントは create/retrieve に加え、編集、延長、キャラクター、webhook、Batch を中心に据えています。一方、従来の remix エンドポイントは新規開発向けには非推奨です。この記事では、根拠のないレイテンシや価格を作り出さず、リポジトリから確認できる挙動と公式資料を使って、これらのフローを安全に統合する方法を説明します。

日付に関する前提(2026-07-15): OpenAI は Videos API と Sora 2 モデル別名を非推奨とし、2026-09-24 に終了すると発表しています(OpenAI の非推奨情報)。Sora 2 だけに依存する長期製品を新たに開始してはいけません。ゲートウェイ経由でまだ Sora トラフィックを扱う場合、この期間を移行ウィンドウとして扱ってください。create/poll/content を維持し、remix だけに依存する新しい UX を作らず、二つのベンダーへ向けた別名を今から計画します。

直接回答:動画は chat completion ではなくタスクとして扱う

# 1) create
curl -sS https://YOUR_GATEWAY/v1/videos \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "YOUR_VIDEO_MODEL_ALIAS",
    "prompt": "Slow aerial push-in over a misty cedar forest at dawn",
    "seconds": "4",
    "size": "1280x720"
  }'

# 2) poll (prefer webhooks when the upstream supports them; see below)
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID \
  -H "Authorization: Bearer $GATEWAY_KEY"

# 3) download when status=completed
curl -sS https://YOUR_GATEWAY/v1/videos/TASK_ID/content \
  -H "Authorization: Bearer $GATEWAY_KEY" \
  -o forest.mp4

このコードベースの動画 DTO でモデル化されている、明示的に処理すべき状態には queued、in_progress、completed、failed があります。タスクオブジェクトには通常、id、model、status、progress、created_at、completed_at、expires_at、seconds、size、任意の error、派生ジョブがある場合の remixed_from_video_id などの系譜フィールドが含まれます。

パラメータマトリクスは、ベンダーの最新ドキュメント—OpenAI の 動画生成ガイド と Videos API リファレンス—で必ず再確認してください。Google Veo / Gemini 動画サーフェス、Runway、Luma、Kling、ByteDance/Volcengine などは、異なるジョブ形式の一次資料を公開しています。チャネルアダプターによっては、ゲートウェイが /v1/video/generations や Kling 形式の /kling/v1/videos/* など、ベンダー固有ルートを公開する場合もあります。ゲートウェイが対応するなら、アプリケーションコードでは正規化された OpenAI 形式のタスク API を優先してください。

OpenAI 公式サーフェスと現在のゲートウェイ登録状況

能力(OpenAI ドキュメント、2026-07-15)公式ルート / イベント本リポジトリのゲートウェイ実装
動画作成POST /v1/videosOpenAI 形式アダプターの主要タスク送信経路として対応
取得 / ポーリングGET /v1/videos/{id}対応
content ダウンロードGET /v1/videos/{id}/content所有権検査付きで対応
既存動画の編集POST /v1/videos/edits(推奨。remix は非推奨)現時点では第一級のゲートウェイルートとして未正規化
動画延長POST /v1/videos/extensions現時点では未正規化
キャラクターPOST /v1/videos/characters + 作成時の characters現時点では未正規化
従来 remixPOST /v1/videos/{id}/remix(新規統合では非推奨)既存 Sora 形式アダプター向け remix ルートとして引き続き検出 / 登録される
Webhookvideo.completed, video.failedOpenAI 上流機能。ゲートウェイクライアントはポーリング fallback も実装する
BatchPOST /v1/videos への Batch API 行上流機能。製品のジョブテーブルを置き換えるものではない

アーキテクチャレビューでは、この差を明示してください。create/poll/content だけを知る製品コードはマルチベンダールーティングに耐えますが、「編集」ボタンを remix に強く依存させると、OpenAI の非推奨化と、ゲートウェイでの編集 / 延長 / キャラクター正規化不足の両方に直面します。

動画統合が画像統合より難しい理由

懸念一般的な画像一般的な動画
レイテンシ秒数十秒から数分
API 形式多くは単一応答作成 + 待機 + content
ペイロードサイズKB〜MB容易に数 MB
失敗モードモデレーション / 不正サイズ長い timeout、部分進捗、失効 content
コストリスクn と解像度時間、解像度、編集 / 延長チェーン
作成後の AuthZ任意の場合があるcontent ダウンロードで必須

chat completion の timeout、例えばポーリングなしで 60 秒後に強制キャンセルする設定を適用すると、後でジョブが成功していても動画統合は「壊れている」ように見えます。初日からアプリケーションにジョブテーブルを設計してください。

推奨アプリケーションデータモデル

video_jobs
  id (your id)
  provider_task_id
  model
  prompt_hash / prompt_text (policy-dependent)
  status
  progress
  seconds
  size
  billing_owner_type / billing_owner_id
  team_id / project_id (nullable)
  content_expires_at
  storage_key (nullable until persisted)
  source_task_id (edit/extension/remix lineage)
  last_error
  created_at / updated_at

worker はポーリングまたは webhook から status と progress を更新します。completed になったら、ダウンロード worker が /content を一度だけ取得し、オブジェクトストレージへ保存して storage_key を設定します。failed では無限 retry をせず、error.message / error.code を表示してください。

時間と課金の上限

時間は課金乗数です。本リポジトリではユーザー入力の動画時間を MaxTaskDurationSeconds = 3600 に制限し、検証時に範囲外の seconds を拒否します。プラットフォームがより長い時間を許可しても、製品の UX 上限はより厳しく、例えばプレビューでは 4〜12 秒に設定すべきです。OpenAI の公式作成例は通常、離散的な秒数区分を使い、現行 Sora ドキュメントには長い 16/20 秒のバリエーションもあります。自由な時間値を作り出してはいけません。

統合規則:

  • DTO が文字列として保持する可能性があるため、seconds を慎重に解析する
  • サーバー側で再検証せず、クライアント入力の時間を価格表示に信用しない
  • 実行者だけでなく、ユーザーまたはチームの課金所有者からクォータを事前消費する
  • 事前消費後にタスクが失敗した場合は精算または返金する
  • 編集 / 延長 / remix チェーンにも同じ原則を適用し、ユーザーが意図せずコストを増幅できないようにする

所有者と実行者の分離は マルチテナント LLM ゲートウェイアーキテクチャ、帰属フィールドは LLM 利用ログとコスト追跡 を参照してください。

待機戦略:webhook を優先し、ポーリングを fallback にする

OpenAI の動画ガイドは、backoff を使って約 10〜20 秒ごとにポーリングし、利用可能な場合は webhook(video.completed / video.failed)を優先するよう推奨しています。ダウンロード URL は短期間のみ有効で、OpenAI のガイドでは生成後約 1 時間と説明されています。速やかに自社ストレージへコピーしてください。

製品 worker 向けの実用的なデフォルト:

  1. プロバイダとゲートウェイ / 運用経路が署名付き配信に対応する場合は webhook を登録する。
  2. 安全網としてポーリングを維持する。10 秒付近から開始し、jitter を加え、負荷時または in_progress が続く場合は 20〜30 秒へ backoff する。
  3. Retry-After がある場合は尊重する。
  4. 総待機時間を厳格な timeout で制限し、ローカルで終端状態 expired / failed にする。
  5. ブラウザタブごとに数百ミリ秒間隔でポーリングしない。
type VideoTask = {
  id: string;
  status: "queued" | "in_progress" | "completed" | "failed" | string;
  progress?: number;
  expires_at?: number;
  error?: { message?: string; code?: string };
};

async function sleep(ms: number) {
  await new Promise((r) => setTimeout(r, ms));
}

async function pollVideo(taskId: string, timeoutMs = 15 * 60_000): Promise<VideoTask> {
  const started = Date.now();
  let interval = 10_000;
  while (Date.now() - started < timeoutMs) {
    const res = await fetch(`${process.env.GATEWAY_BASE}/v1/videos/${taskId}`, {
      headers: { Authorization: `Bearer ${process.env.GATEWAY_KEY}` },
    });
    if (res.status === 429) {
      const ra = Number(res.headers.get("retry-after"));
      await sleep(Number.isFinite(ra) ? ra * 1000 : interval);
      interval = Math.min(interval + 5_000, 30_000);
      continue;
    }
    if (!res.ok) throw new Error(await res.text());
    const task = (await res.json()) as VideoTask;
    if (task.status === "completed" || task.status === "failed") return task;
    const jitter = Math.floor(Math.random() * 2_000);
    await sleep(interval + jitter);
    interval = Math.min(Math.floor(interval * 1.2), 30_000);
  }
  throw new Error("video poll timeout");
}

別チームのブログではなく、自社モデルと地域で測定した完了時間から調整してください。

Content ダウンロードの AuthZ とワークベンチスコープ

タスクを作成できることと、後でそのバイトをストリーミングできることは同じではありません。マルチテナントゲートウェイでは、/v1/videos/{id}/content が所有権を強制する必要があります。ジョブ作成時と同じユーザー / チーム / プロジェクトスコープ、または明示的な共有ポリシーが必要です。別テナントのタスク ID 推測はフェイルクローズしてください。

本リポジトリのワークベンチ経路:

  • UI:動画ワークベンチ
  • /api/user/video-workbench 以下の個人 API
  • プロジェクトスコープ action を持つ /api/teams/:team_id/video-workbench 以下のチーム API
  • 動画生成と動画資産管理などの個別権限

これは個人専用の 画像ワークベンチ とは異なります。ワークベンチで永続的な再生にオブジェクトストレージが必要なら、恒久履歴を約束する前に設定してください。/v1/videos/{id}/content を指す fallback 再生 URL にも有効な AuthZ が必要で、expires_at の制約を受ける場合があります。

編集、延長、キャラクター、従来 remix

新規統合に対する OpenAI 公式指針:

  • 編集: 対象変更には prompt と元 video を指定した POST /v1/videos/edits を使う。この用途の remix は非推奨。
  • 延長: 完了クリップを続けるには POST /v1/videos/extensions を使う。合成後の総時間となり、OpenAI ガイドによると延長ではキャラクター非対応。
  • キャラクター: POST /v1/videos/characters で作成し、一貫性のため作成時にキャラクター ID を参照する。
  • Batch: POST /v1/videos JSON 行のオフラインキュー。OpenAI ドキュメントでは Batch 出力に独自の保持期間がある。

このゲートウェイに残る従来 remix を含め、すべての派生ジョブに適用すべき統合上の注意:

  • 呼び出し元が元タスクを読める場合だけ派生ジョブを許可する
  • 元タスクからテナンシーフィールドをコピーし、派生を誤ったプロジェクトへ孤立させない
  • 編集 / 延長 / remix は無料の微調整ではなく、新しい課金対象ジョブだと表示する
  • サポートとモデレーションのため系譜を永続化する
  • ベンダー固有 metadata bag は feature flag の背後に置き、時間 / サイズをグローバル上限で検証する

ゲートウェイが編集 / 延長 / キャラクターを正規化するまでは、それらを明示的なアダプター flag またはネイティブ上流クライアントの背後に置き、remix を現代的な OpenAI 経路であるかのように扱わないでください。

永続化ポリシー

次を前提にします。

  1. 上流 content URL とゲートウェイの一時プロキシは失効する可能性がある。expires_at は第一級フィールドで、OpenAI は対話型ダウンロードを約 1 時間と説明している
  2. 製品ページには自社オブジェクトキーが必要である
  3. サムネイルはダウンロード後に生成し、プロバイダ CDN から都度取得しない
  4. チーム離脱またはユーザーの保持権行使時に削除できる必要がある

安全なパイプライン:

completed → 認可付き content 取得 → 必要ならウイルス / type 検査 → オブジェクトストレージへ保存 → DB の storage_key → アプリ認証付き CDN で配信。

ストレージを「必要になるまで」省略すると、デモはインシデントチケットへ変わります。上流 Videos API 自体が終了予定なら、特に深刻です。

可観測性とサポート

少なくとも、ゲートウェイのリクエスト ID / タスク ID、モデル別名、秒数、サイズ、状態遷移、課金所有者と実行者、webhook / poll 経路、最終エラーコードを記録します。ダッシュボードでは動画失敗クラスをチャット失敗から分けてください。サポートツールは MP4 全体をチケットシステムへダウンロードせずに、タスクと利用ログを開けるべきです。

遭遇する可能性がある別ルート

チャネルアダプターによっては、運用者が次を有効にする場合があります。

  • /v1/video/generations 形式のエンドポイント
  • Kling /kling/v1/videos/*
  • Gemini/Vertex Veo タスクアダプター
  • Jimeng などのルート背後にあるその他のベンダータスク API

アプリケーションチームはすべてのベンダー経路をハードコードすべきではありません。一つの正規化クライアント(/v1/videos + 安定した別名)を優先し、チャネル対応付けはゲートウェイに任せます。motion brush や cinema preset のようにベンダー経路だけにある機能は feature flag の背後へ隔離し、非ポータブル契約を文書化してください。

関連記事

出典

運用 Q&A

動画が完成するまで HTTP リクエストをブロックできますか?

短時間の社内ツールだけにしてください。製品 UI はジョブレコードを作り、webhook またはポーリングを使用すべきです。長い同期リクエストはゲートウェイとロードバランサーの timeout を増幅します。

どのポーリング間隔を使うべきですか?

jitter 付きで 10 秒付近から始め、20〜30 秒へ backoff し、Retry-After を尊重し、利用可能なら video.completed / video.failed webhook を優先します。OpenAI ガイドは約 10〜20 秒のポーリングを示しています。

completed 後に content ダウンロードが失敗したのはなぜですか?

一般的な原因は、content の失効、誤った認証スコープ、別プロジェクト所有のタスク、ストレージ / プロキシ設定不備です。生成を retry する前に expires_at とテナンシーフィールドを確認してください。

新規製品は remix を使うべきですか?

主要な編集経路としては使用しません。OpenAI 公式ドキュメントは新しい編集を POST /v1/videos/edits へ移行し、remix を非推奨としています。このゲートウェイは互換性のため remix 形式ルートを受け入れる場合がありますが、greenfield 設計ではなく従来機能への橋渡しとして扱ってください。

/v1/videos を呼んでいても動画ワークベンチは必要ですか?

純粋なバックエンドパイプラインには不要です。人が共有履歴、プリセット、UI 上のチームスコープ資産管理を必要とする場合は有用です。

最初に出荷する worker

可能なら安定した非 Sora 別名で、なければ 2026-09-24 より前の移行日を明記した一時的な Sora 別名で短い動画を作成する worker を一つ実装します。10 秒 + jitter でポーリングし、webhook は任意とし、/content を一度だけダウンロードしてオブジェクトストレージへアップロードし、別チームのキーがそのタスク ID をダウンロードできないことを証明してください。その後で初めて正常経路を製品 UI へ接続します。