動画生成
動画を作る API の使い方(申し込み、進み具合の確認、ファイルの受け取り)、モデルごとに指定できる項目と値、料金のかかり方、ファイルを受け取れる期間、エラーをまとめています。
動画の生成には時間がかかるため、1 回の呼び出しでは動画を返しません。タスク(申し込んだあと、生成が終わってから結果を受け取る処理)として、次の 3 つの手順で使います。
| 手順 | メソッドとパス | 内容 |
|---|---|---|
| 1. 申し込む | POST /v1/videos | モデル、プロンプト(作りたい動画の説明)、長さ、解像度を送ります。タスクの ID が返ります |
| 2. 進み具合を確かめる | GET /v1/videos/{タスクの ID} | status が completed(完了)か failed(失敗)になるまで、間をあけて繰り返します |
| 3. ファイルを受け取る | GET /v1/videos/{タスクの ID}/content | 完成した動画を MP4 ファイルで受け取ります |
接続先 URL とキーの送り方は、ほかの OpenAI 形式のエンドポイントと同じです(https://token.echohub.io/v1、Authorization: Bearer キー)。
提供中のモデルは、モデル一覧に載せています。
モデル
| モデル ID | 提供元 | 長さ | 解像度 | 使える入力 |
|---|---|---|---|---|
MiniMax-H3 | MiniMax | [ ] | 768P、2K | [ ] |
doubao-seedance-2-0-260128(Seedance 2.0) | ByteDance(Volcano Engine) | [ ] | 480p、720p、1080p、4k | [ ] |
- 料金(1 秒あたり、または 100 万トークンあたりの単価)は、モデル一覧の各モデルのページに載せます
- 処理地域は、モデル一覧の各モデルのページに載せています。プロンプトと、参照に使う画像・動画・音声は、その地域で処理する提供元の API に渡ります(データの取り扱い)
- 指定できる項目と値は、モデルごとに違います。下の「モデルごとの指定」を見てください
呼び出しの例
MiniMax-H3 で 6 秒・768P の動画を作り、video.mp4 に保存する例です。キーは環境変数 ECHO_API_KEY に入れておきます(クイックスタート)。
# 1. 申し込む。返ってきた id を控えます
curl "https://token.echohub.io/v1/videos" \
-H "Authorization: Bearer $ECHO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"prompt": "夕方の海辺を、柴犬がゆっくり歩いている",
"seconds": 6,
"resolution": "768P"
}'
# 2. 進み具合を確かめる。VIDEO_ID には 1. で返った id を入れます
VIDEO_ID="task_..."
curl "https://token.echohub.io/v1/videos/$VIDEO_ID" \
-H "Authorization: Bearer $ECHO_API_KEY"
# 3. status が completed になったら、ファイルを受け取る
curl -o video.mp4 "https://token.echohub.io/v1/videos/$VIDEO_ID/content" \
-H "Authorization: Bearer $ECHO_API_KEY"# 仮想環境を作って有効にする
python3 -m venv .venv && source .venv/bin/activate
pip install requestsimport os
import time
import requests
BASE = "https://token.echohub.io/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['ECHO_API_KEY']}"}
def check(res):
# エラーのときは、HTTP ステータスとエラー本文を表示して終わる
if not res.ok:
raise SystemExit(f"HTTP {res.status_code}: {res.text}")
return res
# 1. 申し込む
video = check(requests.post(f"{BASE}/videos", headers=HEADERS, json={
"model": "MiniMax-H3",
"prompt": "夕方の海辺を、柴犬がゆっくり歩いている",
"seconds": 6,
"resolution": "768P",
})).json()
print("申し込みました:", video["id"])
# 2. 完了か失敗になるまで、15 秒ごとに進み具合を確かめる
while video["status"] in ("queued", "in_progress"):
time.sleep(15)
video = check(requests.get(f"{BASE}/videos/{video['id']}", headers=HEADERS)).json()
print(video["status"], video["progress"])
if video["status"] != "completed":
raise SystemExit(f"生成できませんでした: {video.get('error')}")
# 3. ファイルを受け取る
res = check(requests.get(f"{BASE}/videos/{video['id']}/content", headers=HEADERS))
with open("video.mp4", "wb") as f:
f.write(res.content)
print("video.mp4 に保存しました")video.py として保存し、python video.py で実行します。
import { writeFile } from "node:fs/promises";
const BASE = "https://token.echohub.io/v1";
const auth = { Authorization: `Bearer ${process.env.ECHO_API_KEY}` };
// エラーのときは、HTTP ステータスとエラー本文を表示して終わる
async function check(res) {
if (!res.ok) throw new Error(`HTTP ${res.status}: ${await res.text()}`);
return res;
}
// 1. 申し込む
const submitted = await check(
await fetch(`${BASE}/videos`, {
method: "POST",
headers: { ...auth, "Content-Type": "application/json" },
body: JSON.stringify({
model: "MiniMax-H3",
prompt: "夕方の海辺を、柴犬がゆっくり歩いている",
seconds: 6,
resolution: "768P",
}),
}),
);
let video = await submitted.json();
console.log("申し込みました:", video.id);
// 2. 完了か失敗になるまで、15 秒ごとに進み具合を確かめる
while (video.status === "queued" || video.status === "in_progress") {
await new Promise((resolve) => setTimeout(resolve, 15_000));
const res = await check(await fetch(`${BASE}/videos/${video.id}`, { headers: auth }));
video = await res.json();
console.log(video.status, video.progress);
}
if (video.status !== "completed") throw new Error(`生成できませんでした: ${JSON.stringify(video.error)}`);
// 3. ファイルを受け取る
const res = await check(await fetch(`${BASE}/videos/${video.id}/content`, { headers: auth }));
await writeFile("video.mp4", Buffer.from(await res.arrayBuffer()));
console.log("video.mp4 に保存しました");Node.js 18 以上で動きます。追加のパッケージは要りません。video.mjs として保存し、node video.mjs で実行します。
1. 申し込む
POST /v1/videos に、JSON で次の項目を送ります。
| パラメータ | 必須 | 説明 |
|---|---|---|
model | 必須 | モデル ID |
prompt | MiniMax-H3 は必須 | 作りたい動画の説明 |
seconds | 動画の長さ(秒)。整数 | |
resolution | 解像度(MiniMax-H3)。Seedance 2.0 では metadata.resolution に書きます | |
images | 画像の URL の配列。最初と最後のフレーム(動画の 1 コマ目と最後のコマ)に使います(MiniMax-H3) | |
input_reference | 最初のフレームにする画像の URL(MiniMax-H3) | |
metadata | モデルごとの追加の指定(Seedance 2.0 の解像度、縦横比、音声の有無、参照素材など)。JSON のオブジェクト |
- 画像・動画・音声は、提供元のサーバーから取得できる公開 URL で渡します
- 書く場所はモデルごとに決まっています。「モデルごとの指定」と違う場所に書いた値は、使われないことがあります。長さ・解像度・画像を Seedance 2.0 が読まない場所に書いたリクエストのように、指定どおりの動画にならない書き方や料金と食い違う書き方は、Echo が受け付けません(HTTP 400。「受け付けない書き方」)
- OpenAI 形式の
size(1280x720など)は使わないでください。縦横比の指定にはならず、モデルによっては解像度として読まれたり、エラーになったりします - MiniMax-H3 では、画像ファイルをリクエストに付けて送ることもできます。フォーム形式(
multipart/form-data)で、input_referenceに 1 枚だけ付けます(20 MB まで)。フォーム形式では、metadataは JSON の文字列にします。Seedance 2.0 はファイルを受け付けません(HTTP 400)。画像は URL で渡します
申し込みを受け付けると、HTTP 200 で次のような JSON が返ります。
{"id":"task_3H0YkK1PMgAiKglDcHbxqtL8WC7C247u","object":"video","model":"MiniMax-H3","status":"queued","progress":0,"created_at":1790796502}申し込みの時点で見込みの料金を残高から差し引きます(下の「料金」)。
2. 進み具合を確かめる
GET /v1/videos/{タスクの ID} で、タスクの状態を返します。
| 項目 | 内容 |
|---|---|
id | タスクの ID(task_ で始まる文字列) |
object | いつも video |
model | モデル ID |
status | 状態(下の表) |
progress | 0〜100 の数。状態ごとに決まった目安です(申し込み直後は 0、待機中は 10(Seedance 2.0)または 30(MiniMax-H3)、生成中は 50、終わると 100)。実際の進み具合を表すものではありません |
created_at | 申し込んだ日時(1970-01-01 からの秒数) |
completed_at | 完了した日時。完了したときだけ入ります |
error | 失敗の理由(code と message)。提供元が理由を返したときだけ入ります(Seedance 2.0)。MiniMax-H3 では入りません |
status | 意味 |
|---|---|
queued | 提供元で順番を待っている |
in_progress | 生成している |
completed | 完了した。ファイルを受け取れます |
failed | 失敗した。料金は全額返金します |
- Echo のサーバーは、15〜30 秒ごとに提供元へ進み具合を問い合わせます。そのため、提供元で生成が終わってから
completedになるまで、30 秒ほどかかることがあります。間隔が 30 秒より長くなることもあります - 進み具合は、10〜15 秒ほど間をあけて確かめてください。Echo から完了を知らせる仕組みはありません
- 申し込みから 24 時間たっても完了しないタスクは、
failedにして全額を返金します。Seedance 2.0 は、申し込みから 23 時間たっても完了しないタスクを提供元が取り消すので、そこでfailedになり、全額を返金します
3. ファイルを受け取る
GET /v1/videos/{タスクの ID}/content で、完成した動画を MP4 ファイル(Content-Type: video/mp4)で返します。HEAD でファイルの大きさだけを確かめたり、Range ヘッダーで一部分だけを受け取ったりもできます。
- Echo は、生成した動画を保存しません。このパスを呼ぶたびに、提供元からファイルを取り寄せて、そのまま渡します
- 受け取れるのは、提供元がファイルを残している間だけです。期間を過ぎると HTTP 410 を返します。完了したら、すぐに受け取って保存してください
| モデル | 提供元がファイルを残す期間 |
|---|---|
| Seedance 2.0 | [ ] |
| MiniMax-H3 | [ ] |
モデルごとの指定
MiniMax-H3
| 項目 | 書く場所 | 値 |
|---|---|---|
| 長さ | seconds | [ ] の整数。省略すると 5 |
| 解像度 | resolution | 768P または 2K。省略すると 768P |
| 縦横比 | metadata.ratio | 16:9、9:16、1:1、4:3、3:4、21:9、adaptive(入力した画像や動画に合わせる)。省略すると、画像や動画を渡したときは adaptive、渡さないときは 16:9。画像も動画も渡さないときは adaptive を使えません |
| 最初と最後のフレーム | images | 画像の URL を 1〜2 個。1 つ目が最初のフレーム、2 つ目が最後のフレームになります。input_reference に書いた画像は最初のフレームになります |
| 参照画像 | metadata.content | 下の例の形で 9 枚まで |
| 参照動画 | metadata.reference_video | URL の配列。3 本まで |
- フレームの指定(
images、input_reference)と参照(画像・動画)は、一緒に使えません - 参照音声は使えません(HTTP 400)
promptを書かないと、HTTP 400 になります
参照画像を使う例です。
{
"model": "MiniMax-H3",
"prompt": "画像のマグカップが、木のテーブルの上でゆっくり回っている",
"seconds": 5,
"resolution": "768P",
"metadata": {
"content": [
{"type": "image_url", "image_url": {"url": "https://example.com/mug.png"}, "role": "reference_image"}
]
}
}| 種類 | 使えるファイル(提供元の仕様) |
|---|---|
| 画像 | JPG、PNG、WEBP、HEIC、HEIF。1 枚 30 MB まで。縦と横は 256〜5760 ピクセル、横÷縦は 0.4〜2.5 |
| 動画 | MP4、MOV。1 本 50 MB まで。1 本 2〜15 秒、合計 15 秒まで |
| リクエスト全体 | 64 MB まで。大きなファイルは URL で渡します |
Seedance 2.0(doubao-seedance-2-0-260128)
| 項目 | 書く場所 | 値 |
|---|---|---|
| 長さ | seconds | [ ] の整数 |
| 解像度 | metadata.resolution | 480p、720p、1080p、4k。省略すると 720p |
| 縦横比 | metadata.ratio | 16:9、4:3、1:1、3:4、9:16、21:9、adaptive。省略すると adaptive(プロンプトや画像に合わせてモデルが選ぶ) |
| 音声 | metadata.generate_audio | true(音声つき)または false(音声なし)。省略すると true |
| 最初のフレーム、最初と最後のフレーム、参照 | metadata.content | 下の例の形。role で使い方を決めます |
| 提供元で待つ時間の上限 | metadata.execution_expires_after | 3600〜82800 の整数(秒)。省略すると Echo が 82800(23 時間)を入れます。この時間内に完了しないタスクは提供元が取り消し、全額を返金します |
- 長さは
seconds、解像度はmetadata.resolutionに書きます。最上位のresolutionやduration、input_reference、プロンプトの後ろに書く--dur 5のような指定は、Seedance 2.0 では使えません(HTTP 400。「受け付けない書き方」) secondsとmetadata.resolutionは省略せずに書いてください。省略すると、見込みの料金を 15 秒・1080p として計算するため、残高が足りずに申し込めないことがあります(生成後に実際の量で計算し直します)- 最初のフレーム、最初と最後のフレーム、参照(画像・動画・音声)の 3 つは、一緒に使えません(提供元の仕様)
- 画像・動画・音声は URL で渡します。フォーム形式でファイルを付けると HTTP 400 になります
- 実在の人物の顔が写った画像や動画は、参照に使えません(提供元の仕様)
最初と最後のフレームを指定する例です。
{
"model": "doubao-seedance-2-0-260128",
"prompt": "つぼみがゆっくり開いて花が咲く",
"seconds": 5,
"metadata": {
"resolution": "720p",
"content": [
{"type": "image_url", "image_url": {"url": "https://example.com/first.png"}, "role": "first_frame"},
{"type": "image_url", "image_url": {"url": "https://example.com/last.png"}, "role": "last_frame"}
]
}
}role | 使い方 | 数 |
|---|---|---|
first_frame | 最初のフレーム(type は image_url)。1 枚だけで使うと、その画像から始まる動画になります | 1 枚 |
last_frame | 最後のフレーム(type は image_url)。first_frame と一緒に使います | 1 枚 |
reference_image | 参照画像(type は image_url) | 1〜9 枚 |
reference_video | 参照動画(type は video_url、URL は video_url.url) | 3 本まで |
reference_audio | 参照音声(type は audio_url、URL は audio_url.url)。画像か動画と一緒に使います | 3 つまで |
| 種類 | 使えるファイル(提供元の仕様) |
|---|---|
| 画像 | JPEG、PNG、WEBP、BMP、TIFF、GIF、HEIC、HEIF。1 枚 30 MB 未満。縦と横は 300〜6000 ピクセル、横÷縦は 0.4〜2.5 |
| 動画 | MP4、MOV。1 本 200 MB まで。1 本 2〜15 秒、合計 15 秒まで |
| 音声 | WAV、MP3。1 つ 15 MB まで。1 つ 2〜15 秒、合計 15 秒まで |
| リクエスト全体 | 64 MB まで |
受け付けない書き方
次の書き方は、指定どおりの動画にならなかったり、料金の計算と食い違ったりするため、Echo が申し込みの時点で断ります。HTTP 400、error.code は invalid_request で、message に正しい書き方が入ります。料金はかかりません。
| 書き方 | モデル | 代わりに | message |
|---|---|---|---|
長さを duration や metadata.duration に書く(seconds を書かない、または seconds と違う値にする) | Seedance 2.0 | seconds に書く | Write the video length in seconds, for example "seconds": 5. This model does not read duration。seconds と違う値のときは duration does not match seconds. Write the video length only in seconds |
seconds に整数でない値を書く(5.5 など) | Seedance 2.0 | 整数(5 または "5") | seconds must be a whole number of seconds, for example "seconds": 5 |
長さを frames や metadata.frames(フレーム数)で書く | Seedance 2.0 | seconds に書く | This model does not read frames. Write the video length in seconds, for example "seconds": 5 |
解像度を最上位の resolution に書く | Seedance 2.0 | metadata.resolution に書く | Write the resolution in metadata.resolution, for example "metadata": {"resolution": "720p"}. This model does not read the top-level resolution |
size だけを書き、metadata.resolution を書かない | Seedance 2.0 | metadata.resolution に書く | Write the resolution in metadata.resolution, for example "metadata": {"resolution": "720p"}. This model does not read size |
metadata.resolution に 480p、720p、1080p、4k 以外を書く(720P など) | Seedance 2.0 | この 4 つのどれか | metadata.resolution must be one of 480p, 720p, 1080p, 4k |
プロンプトの後ろに長さや解像度の指定を書く(--dur 5、--rs 720p など) | Seedance 2.0 | seconds と metadata.resolution に書く | Write the video length in seconds and the resolution in metadata.resolution. This model does not accept --dur in the prompt |
画像を input_reference、image、images に書く | Seedance 2.0 | metadata.content に書く(最初のフレームは role を first_frame にする) | This model does not read input_reference. Put images in metadata.content; for the first frame use {"type": "image_url", "image_url": {"url": "<image URL>"}, "role": "first_frame"} |
| フォーム形式でファイルを付ける | Seedance 2.0 | 画像の URL を metadata.content に書く | This model does not accept uploaded files. Pass images as URLs in metadata.content; for the first frame use {"type": "image_url", "image_url": {"url": "<image URL>"}, "role": "first_frame"} |
metadata.execution_expires_after に 3600〜82800 以外の値を書く | Seedance 2.0 | 3600〜82800 の整数(書かなければ Echo が 82800 を入れます) | metadata.execution_expires_after must be a whole number of seconds from 3600 to 82800 (1 to 23 hours) |
参照音声を付ける(metadata.reference_audio、metadata.content の audio_url) | MiniMax-H3 | 使えません | Reference audio is not supported for this model. Remove audio_url and reference_audio from the request |
動画のモデルを POST /v1/responses や POST /v1/tasks/… で呼ぶ | 両方 | POST /v1/videos で申し込む | Video generation requests must be sent to POST /v1/videos |
messageのうちduration、frames、input_reference、--durの部分は、実際に書いた項目の名前になります(metadata.duration、image、--rsなど)- 正しく書いたリクエストに Echo が足すのは、Seedance 2.0 の
metadata.execution_expires_after(提供元で待つ時間の上限)だけです。ほかの項目は書いたとおりに提供元に届きます
料金
動画の料金は、1 秒あたり(MiniMax-H3)または 100 万トークンあたり(Seedance 2.0)の単価で決まります。トークンは、提供元が動画の量を数える単位です。単価はモデル一覧の各モデルのページに載せます。
タスクの料金は、次の順に決まります。
- 申し込んだときに、見込みの料金を残高から差し引きます。見込みの料金は、リクエストの長さと解像度(MiniMax-H3 は参照画像の枚数と参照動画も)から計算します。残高かキーの利用上限が足りないときは、申し込めません(HTTP 403)
- 生成が終わると、提供元が報告した実際の量で料金を計算し直し、差額を返金するか、追加で差し引きます
- 生成に失敗したタスクと、24 時間たっても完了しないタスク(Seedance 2.0 は 23 時間)は、全額を返金します
| モデル | 計算し直すときに使う量 |
|---|---|
| Seedance 2.0 | 実際のトークン数。参照動画を付けたかどうかで、100 万トークンあたりの単価が変わります |
| MiniMax-H3 | 実際の長さ、参照画像の枚数、参照動画の秒数。参照動画は、申し込みのときは 15 秒として計算します |
- 申し込みの時点で断ったリクエスト(値の誤り、提供元が受け付けなかったものなど)に、料金はかかりません
- 追加で差し引く分は、残高が足りなくても差し引きます。残高がマイナスになった分は、次のチャージから差し引きます(料金とチャージ)
- コンソールの「呼び出し履歴」に、タスクごとの状態と金額を表示します(API キーと利用状況)
エラー
エラー本文は、ほかの OpenAI 形式のエンドポイントと同じ形式です(エラーと対処)。動画生成に特有のエラーは次のとおりです。
| 状況 | HTTP ステータスと error.code | message | 対処 |
|---|---|---|---|
| 長さ・解像度などの値が、そのモデルでは使えない | 400、invalid_request または空の文字列 | 理由を書いた英文(例:MiniMax-H3 duration must be an integer between 4 and 15 seconds) | 「モデルごとの指定」を見て直す |
受け付けない書き方をした(Seedance 2.0 で長さを duration に書いた、フォーム形式でファイルを付けた、動画のモデルを POST /v1/responses で呼んだなど) | 400、invalid_request | 正しい書き方を書いた英文(例:Write the video length in seconds, for example "seconds": 5. This model does not read duration) | 「受け付けない書き方」を見て直す |
| 提供元がリクエストを受け付けなかった | 400、upstream_error | The model service rejected the request, check the parameters and try again | 値と、画像などの URL を確かめる |
| タスクの ID が違う、または別のアカウントのタスク | 400(ファイルの受け取りでは 404)、task_not_found | Task not found | ID を確かめる |
| 完了する前にファイルを受け取ろうとした | 400、task_not_ready | The video is not ready yet | completed になってから受け取る |
| 失敗したタスクのファイルを受け取ろうとした | 400、task_failed | The video generation failed | もう一度申し込む |
| 提供元がファイルを残す期間を過ぎた | 410、artifact_gone | Artifact content is no longer available | 受け取れません。もう一度申し込みます |
| 残高が足りない | 403、insufficient_quota | Insufficient balance | チャージする |
| キーの利用上限が足りない | 403、insufficient_quota | This API key has reached its spending limit | 利用上限を増やす(上限とレート制限) |
| モデル ID が違う | 503、model_not_found | The model {モデル ID} does not exist or is not available | モデル ID を確かめる |
申し込みの時点で返したエラーに、料金はかかりません。
OpenAI の SDK を使う場合
- OpenAI の SDK(Python・Node.js)にも動画の関数(
videos.createなど)がありますが、SDK ではこれらに「Sora の API は 2026-09-24 に終了予定」という非推奨の表示が付いています。このページの例は、SDK を使わずに HTTP で呼び出します - SDK の
videos.createは、リクエストをフォーム形式(multipart/form-data)で送ります。この形式では、metadataを JSON の文字列にしないと、提供元に届きません(Python の例:extra_body={"metadata": json.dumps({"resolution": "720p"})})
確認した情報源
| 内容 | 情報源 | 確認日 |
|---|---|---|
3 つの手順と応答、状態と progress、ファイルの受け取り(HEAD・Range を含む)、エラー本文、料金の差し引き・計算し直し・返金、Seedance 2.0 の metadata.resolution と metadata.content(role)が提供元に届くこと、Seedance 2.0 がフォーム形式のファイルを受け付けないこと、フォーム形式での metadata、SDK の videos.create での metadata | Echo の検証環境での実測。本番と同じ中継設定で、提供元の API の代わりに試験用の応答を返すサーバーを使いました | 2026-10-02 |
| 進み具合を問い合わせる間隔(申し込みから最初の問い合わせまで 19〜36 秒、そのあと 30 秒ごと) | Echo の検証環境での実測(同上) | 2026-10-01 |
| 24 時間たっても完了しないタスクを失敗にして返金すること | Echo の中継サーバーの設定(2026-10-01 時点) | 2026-10-01 |
受け付けない書き方とエラー、Seedance 2.0 の metadata.execution_expires_after を Echo が 82800 にすること | Echo の検証環境での実測(同上) | 2026-10-02 |
Seedance 2.0 の metadata.execution_expires_after の範囲(3600〜259200 秒、省略時 172800 秒)、プロンプトの後ろに書く --dur などの指定 | https://www.volcengine.com/docs/82379/1520757 | 2026-10-02 |
| MiniMax-H3 の長さ・解像度・縦横比・入力の組み合わせとファイルの条件、ファイルの URL に期限があること | https://platform.minimax.io/docs/api-reference/video-generation-v2-create 、https://platform.minimax.io/docs/api-reference/video-generation-v2-query | 2026-10-01 |
Seedance 2.0 の長さ・解像度・縦横比・音声・role とファイルの条件、ファイルを 24 時間残すこと、実在の人物の顔を参照に使えないこと | https://www.volcengine.com/docs/82379/1520757 、https://www.volcengine.com/docs/82379/1521309 | 2026-10-01 |
| OpenAI の SDK の動画の関数が非推奨であること | https://github.com/openai/openai-python (3.23.0)、https://github.com/openai/openai-node (7.27.0) | 2026-10-02 |