動画生成APIの使い方:ジョブを投げて、待って、受け取る
動画生成は、リクエストを投げてその場で結果が返るAPIではありません。 レンダリングに数分かかるため、ジョブを作成してIDを受け取り、完成するまでポーリングし、完成したらMP4をダウンロードする——という3段構えになります。
チャットや画像生成とは作りが違うので、この記事では流れと実装上の注意点を整理します。
3つのステップ
1. POST /openrouter/videos/create → job_id が返る(ここで課金)
↓
2. GET /openrouter/videos/jobs/<id> → status を確認(無料・繰り返す)
↓
3. GET /openrouter/videos/jobs/<id>/content?index=0 → MP4(無料)
チャットの /v1/chat/completions とはパスの系統が違う点に注意してください。認証は同じAPIキーです。
ステップ1:ジョブを作成する
curl -X POST https://api.fastmetal.ai/openrouter/videos/create \
-H "Authorization: Bearer $FASTMETAL_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "bytedance/seedance-2.0-fast",
"prompt": "溶けた金属が型に流れ込む様子のクローズアップ"
}'
成功時は HTTP 202 が返り、ボディに id(ジョブID)と status が入っています。200ではないので、status_code == 200 で判定しているコードは失敗扱いにしてしまいます。
返ってくるジョブIDを保存してください。このIDが、支払った1本ぶんの引き換え券です。 失うと、生成中の動画を取り出す手段がなくなります。
解像度や長さといったパラメータは、モデルごとにサーバー側で固定されています。prompt と model を送るだけです。これは課金を1本あたりの定額に固定するための設計で、パラメータ次第で価格が変わることがありません。
ステップ2:完成までポーリングする
curl https://api.fastmetal.ai/openrouter/videos/jobs/<JOB_ID> \
-H "Authorization: Bearer $FASTMETAL_API_KEY"
status が完了を示すまで繰り返します。ポーリングは無料です。 課金はステップ1で確定しているので、何回状態を確認しても追加費用は発生しません。
とはいえ、1秒間隔で叩き続ける必要はありません。レンダリングは分単位なので、5〜10秒間隔で十分です。
ステップ3:MP4をダウンロードする
curl https://api.fastmetal.ai/openrouter/videos/jobs/<JOB_ID>/content?index=0 \
-H "Authorization: Bearer $FASTMETAL_API_KEY" \
-o out.mp4
こちらも無料です。index=0 が1本目の動画を指します。
Pythonでまとめて
import os, time, requests
BASE = "https://api.fastmetal.ai"
HEADERS = {"Authorization": f"Bearer {os.environ['FASTMETAL_API_KEY']}"}
def generate_video(prompt: str, model: str = "bytedance/seedance-2.0-fast",
timeout_s: int = 900, interval_s: int = 10) -> bytes:
# 1. ジョブを作成(ここで課金される)
r = requests.post(
f"{BASE}/openrouter/videos/create",
headers=HEADERS,
json={"model": model, "prompt": prompt},
timeout=60,
)
r.raise_for_status()
job_id = r.json()["id"]
print(f"job_id={job_id}") # ← 必ず記録する
# 2. 完成までポーリング(無料)
deadline = time.time() + timeout_s
while time.time() < deadline:
s = requests.get(f"{BASE}/openrouter/videos/jobs/{job_id}",
headers=HEADERS, timeout=30)
s.raise_for_status()
status = s.json().get("status")
print(status)
if status in ("completed", "succeeded"):
break
if status in ("failed", "cancelled"):
raise RuntimeError(f"生成に失敗しました: {s.json()}")
time.sleep(interval_s)
else:
raise TimeoutError(f"タイムアウト。job_id={job_id} で後から取得できます")
# 3. ダウンロード(無料)
c = requests.get(f"{BASE}/openrouter/videos/jobs/{job_id}/content",
headers=HEADERS, params={"index": 0}, timeout=300)
c.raise_for_status()
return c.content
open("out.mp4", "wb").write(generate_video("溶けた金属が型に流れ込む様子のクローズアップ"))
status の文字列はモデルや上流の仕様で変わりうるので、実際に一度叩いて確認してから判定条件を固めてください。上のコードが完了を複数の値で見ているのはそのためです。
課金は1本あたりの定額
料金体系がチャットとまったく違います。
| 操作 | 課金 |
|---|---|
| ジョブ作成 | 1本あたりの定額(モデルごとに固定) |
| ポーリング | 無料 |
| ダウンロード | 無料 |
トークン数もプロンプトの長さも価格に影響しません。課金されるのはステップ1の瞬間で、そこから先は何度確認しても無料です。現在の1本あたりの価格は料金ページで確認してください。
実装上、これは重要な意味を持ちます。ジョブ作成のレスポンスを取りこぼすと、支払い済みの動画を回収できなくなります。 ネットワークが切れてもリトライしないでください——リトライは新しいジョブになり、二重に課金されます。job_id は受け取った直後にログなり DB なりへ書き出すのが鉄則です。
エージェントから使う場合
タイムアウトの問題があります。レンダリングは分単位なのに、多くのMCPクライアントはリクエストのタイムアウトを60秒程度に設定しています。完成を待ち切る前にクライアント側が諦めると、課金済みのジョブIDを載せたレスポンスごと捨てられます。
そのためMCPサーバーの generate_video は、一定時間だけ待って、間に合わなければ job_id を返します。後から get_video で取りに行く設計です。自前で実装する場合も同じ考え方——待ち時間はクライアントのタイムアウトより短くしてください。
つまずきやすい点
同期で返ると思って実装する ジョブ方式です。1回のリクエストでMP4は返りません。
job_id を保存していない
課金は作成時点で確定しています。IDを失うと動画は取り出せません。
失敗したと思ってリトライする レスポンスが届かなかっただけで、ジョブは動いている可能性があります。リトライすると二重課金です。まず既存のジョブを確認してください。
ポーリング間隔が短すぎる 無料ですが、分単位の処理を1秒間隔で叩く意味はありません。5〜10秒で十分です。
チャットの暗号化会話で使おうとする チャットUIでは、暗号化された会話で動画生成は使えません。生成された大きなファイルをクライアント側で暗号化する仕組みが未整備なためです。
次のステップ
静止画なら画像生成APIの使い方のほうが単純で、同期で返ります。まず画像で試してから動画に進むと理解が早いはずです。
動画生成の提供開始のお知らせはこちら、APIの詳細はドキュメントにあります。
よくある質問
Q. 動画生成は1回のリクエストで完結しますか? いいえ。ジョブを作成してIDを受け取り、完成までポーリングし、MP4をダウンロードする3ステップです。レンダリングには数分かかります。
Q. ポーリングするたびに課金されますか? されません。課金はジョブ作成時の1回だけで、状態確認とダウンロードは無料です。
Q. リクエストが失敗したように見えたらリトライしていいですか? いけません。レスポンスが届かなかっただけでジョブは進行している可能性があり、リトライは二重課金になります。既存のジョブを先に確認してください。
Q. 解像度や長さは指定できますか? モデルごとにサーバー側で固定されています。これにより1本あたりの価格が変動しません。仕様はモデルカタログと料金ページを確認してください。
まとめ
動画生成は「作成 → ポーリング → ダウンロード」の非同期ジョブです。課金は作成時の1回だけで1本あたりの定額、ポーリングとダウンロードは無料。だからこそ job_id の保存と、安易にリトライしないことが実装上いちばん大事になります。
APIキーを取得して、まず1本作ってみてください。