ブログ/developers·2026年9月8日·2分·執筆:eroqチーム
eroq Films APIで絵コンテをレンダリング:全シーンを1回で撮影
ルックと順序付きのシーンでフィルムのレシピを作り、1回のrender呼び出しで全シーンを非同期ジョブとして撮影。ジョブをポーリングし、カバーを付けて公開するまでを解説します。
1つのプロンプトで作れるのは1本のクリップです。フィルムとは、同じルックを共有し、つなげて1本になるクリップの連なりのこと。スタジオのフィルムモードでは、シーンを追加してレンダリングし、次のシーンを追加する、という流れで対話的にフィルムを組み立てます。Films APIは、同じことをクリックなしで行うためのものです。絵コンテを一度定義し、1回の呼び出しで全シーンを撮影し、ジョブをポーリングして公開する。同じスポット広告を10社のクライアント向けに10パターン制作しているなら、これこそ求めていたエンドポイントです。
フィルムはレシピであり、メディアではない
POST /v1/filmsは、タイトルとdataオブジェクトをそのまま保存します。APIはレンダリングするまでレシピを解釈せず、レンダリング結果は常にフィルムではなく作品のライブラリに入ります。レシピは2つの部分からなります。
look:全シーンが共有する設定。model、aspect、filmType、era、tempo、cameraType、lens、aperture、resolution。scenes:{ prompt, shot, seconds, cast }の順序付き配列。shotはカメラワーク、castは自分のキャラクターIDのリストです。
curl https://eroq.ai/v1/films \
-H "Authorization: Bearer $EROQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Rooftop night — cut 1",
"data": {
"look": {
"model": "eroq-motion-one", "aspect": "16:9",
"filmType": "noir", "era": "1960s", "tempo": "tense",
"cameraType": "35mm", "lens": "anamorphic", "aperture": "f1-4"
},
"scenes": [
{ "prompt": "A woman in a silver dress steps out onto a rooftop bar at dusk, city lights flickering on below, slow pan following her to the railing, warm practicals against the deep blue sky, wind in her hair, expectant mood.", "shot": "slow-pan", "seconds": 5 },
{ "prompt": "Close-up of her hands on the cold railing, a glass of something amber beside them, push-in as the skyline blurs behind, neon reflections crawling across the glass, quiet and tense.", "shot": "push-in", "seconds": 5 },
{ "prompt": "Wide shot from behind as she turns toward the door, a silhouette waiting there against the bar light, crane-up revealing the whole rooftop and the city beyond, patient, ominous mood.", "shot": "crane-up", "seconds": 10 }
]
}
}'
レスポンスにはフィルムのidが含まれます。下書きは1アカウントあたり最大50件です。GET /v1/films/{id}はレシピ全体を返し、PATCHはtitleまたはdataを更新し、DELETEは下書きを削除します(レンダリング結果はライブラリに残ります)。スタジオのフィルムモードが保存・再読み込みするのはまさにこの下書きなので、スクリプトで作ったレシピを/studio/videoで開いて手で直すことも、その逆もできます。
シーンのプロンプトは、エンジンが好む書き方で書きましょう。被写体、動き、カメラ、光、雰囲気を盛り込んだ、ひと続きの1段落です。残りはルックが補ってくれるので、「フィルム・ノワール、1960年代」を全シーンで繰り返す必要はありません。
1回の呼び出しですべてを撮影
curl -X POST https://eroq.ai/v1/films/FILM_ID/render \
-H "Authorization: Bearer $EROQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "store": true }'
プロンプトを持つシーンはそれぞれ非同期の動画ジョブになり(シーンごとにPOST /v1/videos/generationsが1回、ルックのパラメーターをマージした形で実行されます)、呼び出しはシーンごとのレポートとともに202を返します。
{
"id": "FILM_ID",
"scenes": [
{ "scene": 0, "id": "job-a…", "status": "processing" },
{ "scene": 1, "id": "job-b…", "status": "processing" },
{ "scene": 2, "id": "job-c…", "status": "processing" }
],
"usage": { "credits_spent": 380, "credits_remaining": 5620 }
}
シーンは個別に課金され、順番にキューに入ります。そのため途中でウォレットが空になっても、残りのシーンが中途半端に課金されることはなく、きれいに停止します。キューに入れられなかったシーンは、その位置にエラーを返します(たとえばロックされたエンジンならplan_required)。そのあいだも、ほかのシーンの処理は進みます。あとでレンダリングに失敗したシーンは、自動で返金されます。
プランによる制限は、ルックのmodelに適用されます。Motion Oneはすべてのアカウントで利用できる検閲なしのエンジンです。Seedance、Kling、Hailuo、Veoは提供元側でモデレーションされており、それぞれを解放するプランが必要です。シーンあたりのsecondsにも、プランごとの上限があります(10、15、20、30秒)。
ジョブをポーリングする
キューに入った各シーンは、通常の動画ジョブです。statusがsucceededかfailedになるまで、数秒おきにGET /v1/videos/generations/{id}をポーリングしてください。ポーリングは無料です。
const BASE = 'https://eroq.ai/v1'
const headers = { Authorization: `Bearer ${process.env.EROQ_API_KEY}` }
async function renderFilm(filmId) {
const report = await fetch(`${BASE}/films/${filmId}/render`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json' },
body: JSON.stringify({ store: true }),
}).then(r => r.json())
const segments = []
for (const scene of report.scenes.filter(s => s.status === 'processing')) {
let job
do {
await new Promise(r => setTimeout(r, 4000))
job = await fetch(`${BASE}/videos/generations/${scene.id}`, { headers }).then(r => r.json())
} while (job.status === 'processing')
if (job.status === 'succeeded') segments[scene.scene] = job.data[0].url
}
return segments.filter(Boolean)
}
3シーンなら順番にポーリングしても問題ありません。30シーンになったら、並列でポーリングするか、video.generation.succeededのWebhookを購読して、届いた順にURLを集めましょう。どちらの方法でも、最後には順番どおりに並んだクリップのURLが手元に残ります。公開に必要なのは、まさにそれです。
カバーを付けて公開する
呼び出しは2回です。まずはカバー。multipart形式で、5 MBまでの画像を送ります(無料)。
curl -X POST https://eroq.ai/v1/films/FILM_ID/cover \
-H "Authorization: Bearer $EROQ_API_KEY" \
-F "[email protected]"
次に、フィルム本体です。
curl -X POST https://eroq.ai/v1/films/FILM_ID/publish \
-H "Authorization: Bearer $EROQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Rooftop night",
"segments": ["https://…/scene-1.mp4", "https://…/scene-2.mp4", "https://…/scene-3.mp4"],
"durationSeconds": 20
}'
segmentsは1〜24個の順序付きURLで、どれも自分のライブラリにホストされたレンダリング結果でなければなりません。外部のメディアは拒否されます。フィルムはコミュニティの棚に1つのエントリーとして並び、セグメントを続けて再生します。カバーはカードとプレーヤーに表示されます。視聴者に見えるのはタイトル、カバー、クリップ、各種カウントで、プロンプト、ルック、キャストは非公開のままです。DELETE /v1/films/{id}/publishで公開を取り下げられ、いいねとコメントは再公開に備えて保持されます。下書きを削除するとコミュニティのエントリーも削除されますが、シーンのレンダリング結果はライブラリに残ります。
エージェンシー向けのバッチ処理
スケールするのは次のパターンです。クライアントごとに1つのレシピをテンプレートとして用意し、変数を差し替えるループを回し、ワークスペースを使ってチーム全員が1つのウォレットから支払えるようにします。
- バリエーションもレシピで作る。 同じ3シーンでも、YouTube向けの
16:9とReels向けの9:16は、2つのルックを持つ2本のフィルムです。作成、レンダリング、ポーリング、納品まで、レビューの段階になるまで人の手は要りません。 - コストは単純な計算。 5秒、5秒、10秒の3シーンからなるMotion Oneのフィルムは180クレジットで、エントリーパックの単価なら約$1.80です。Studioプランの月20,000クレジットでおよそ50本をまかなえ、レート制限は4倍になります。テイク数を増やせばその分だけ掛け算で増えるので、レビューに本当に必要な代替案の数を決めておきましょう。
- スループットはキーごと。 動画リクエストのレート制限はキーごとにかかります(基本ティアで1分あたり6件、プランに応じて倍増)。パイプラインごとに専用のキーを用意すれば、あるクライアントのバッチが別のクライアントの処理を詰まらせることはありません。
- キャラクターは引き継がれる。 クライアントのおなじみのプレゼンターを
castに入れれば、画像から動画を通じて、すべてのシーンで同じ顔が保たれます。より広いワークフローはエージェンシー向けの活用法をご覧ください。
よくある質問
1つのシーンが失敗したらどうなりますか?
ほかのシーンには影響しません。失敗したシーンは自動で返金されます。POST /v1/videos/generationsと同じルックのパラメーターで、そのシーンだけを再レンダリングし、そのURLをsegmentsに差し込んでください。フィルムに対してもう一度renderを呼ぶと、全シーンが撮り直され、もう一度課金されます。
スタジオで誰かが作ったフィルムをレンダリングできますか?
はい。GET /v1/filmsは、スタジオのフィルムモードで保存された下書きを一覧で返します。どれでもIDを指定してレンダリングできます。
公開にクレジットはかかりますか?
かかりません。カバーのアップロードと公開の呼び出しは無料です。支払うのはシーンのレンダリング代だけです。
まずは無料クレジットで、3シーンのレシピから始めましょう。APIキーを取得して撮影してみてください。
この記事で使ったモデルで作ってみましょう。無料の50クレジットで始めるか、全エンジンと料金をご覧ください。