動画生成 API 統合:タスク、ポーリング、コンテンツ
create/poll/content フロー、編集・延長・キャラクター、webhook、時間上限、認可付きメディア配信を含む動画生成統合を解説します。
動画生成 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/videos | OpenAI 形式アダプターの主要タスク送信経路として対応 |
| 取得 / ポーリング | GET /v1/videos/{id} | 対応 |
| content ダウンロード | GET /v1/videos/{id}/content | 所有権検査付きで対応 |
| 既存動画の編集 | POST /v1/videos/edits(推奨。remix は非推奨) | 現時点では第一級のゲートウェイルートとして未正規化 |
| 動画延長 | POST /v1/videos/extensions | 現時点では未正規化 |
| キャラクター | POST /v1/videos/characters + 作成時の characters | 現時点では未正規化 |
| 従来 remix | POST /v1/videos/{id}/remix(新規統合では非推奨) | 既存 Sora 形式アダプター向け remix ルートとして引き続き検出 / 登録される |
| Webhook | video.completed, video.failed | OpenAI 上流機能。ゲートウェイクライアントはポーリング fallback も実装する |
| Batch | POST /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 向けの実用的なデフォルト:
- プロバイダとゲートウェイ / 運用経路が署名付き配信に対応する場合は webhook を登録する。
- 安全網としてポーリングを維持する。10 秒付近から開始し、jitter を加え、負荷時または
in_progressが続く場合は 20〜30 秒へ backoff する。 Retry-Afterがある場合は尊重する。- 総待機時間を厳格な timeout で制限し、ローカルで終端状態
expired/failedにする。 - ブラウザタブごとに数百ミリ秒間隔でポーリングしない。
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/videosJSON 行のオフラインキュー。OpenAI ドキュメントでは Batch 出力に独自の保持期間がある。
このゲートウェイに残る従来 remix を含め、すべての派生ジョブに適用すべき統合上の注意:
- 呼び出し元が元タスクを読める場合だけ派生ジョブを許可する
- 元タスクからテナンシーフィールドをコピーし、派生を誤ったプロジェクトへ孤立させない
- 編集 / 延長 / remix は無料の微調整ではなく、新しい課金対象ジョブだと表示する
- サポートとモデレーションのため系譜を永続化する
- ベンダー固有 metadata bag は feature flag の背後に置き、時間 / サイズをグローバル上限で検証する
ゲートウェイが編集 / 延長 / キャラクターを正規化するまでは、それらを明示的なアダプター flag またはネイティブ上流クライアントの背後に置き、remix を現代的な OpenAI 経路であるかのように扱わないでください。
永続化ポリシー
次を前提にします。
- 上流 content URL とゲートウェイの一時プロキシは失効する可能性がある。
expires_atは第一級フィールドで、OpenAI は対話型ダウンロードを約 1 時間と説明している - 製品ページには自社オブジェクトキーが必要である
- サムネイルはダウンロード後に生成し、プロバイダ CDN から都度取得しない
- チーム離脱またはユーザーの保持権行使時に削除できる必要がある
安全なパイプライン:
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 の背後へ隔離し、非ポータブル契約を文書化してください。
関連記事
出典
- OpenAI 動画生成ガイド
- OpenAI Videos API リファレンス
- OpenAI の非推奨情報(Videos API / Sora 2 → 2026-09-24)
- OpenAI webhook ガイド
- Google Gemini 動画生成
- Runway 開発者ドキュメント
- Luma AI API ドキュメント
- OWASP Top 10 for LLM Applications
運用 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 へ接続します。