Sora2U 動画生成オープン API
この API を使えば、どの Sora2U ユーザーも自分の API キーを使って、自分のプログラム / スクリプト / サーバーサイドからサイトの動画生成機能を呼び出せます。生成のたびに、そのユーザーの積分(GP)残高から通常どおり課金され、 課金ルールはウェブ版とまったく同じです。
- Base URL:
https://sora2u.com - プロトコル:HTTPS、リクエスト / レスポンスはいずれも JSON(タスク作成時の参照画像は base64 でインライン)
- 認証:API キー(
Authorization: Bearer <key>) - スタイル:タスクは非同期——作成後にまずタスク ID を返し、その後ポーリングして結果を取得
機械可読なインターフェース定義は同じディレクトリの
openapi.yamlを参照してください。Postman / Swagger UI / openapi-generator にそのままインポートできます。
目次
- クイックスタート(5 分で動かす)
- API キーの取得と管理
- 認証方式
- 動画を 1 本生成する
- タスクの状態を照会する
- その他のインターフェース
- 課金と積分の差し引き
- タスク状態マシン
- エラーコード
- ベストプラクティス
- 完全な例(Node.js / Python)
- メンテナー向け:リリース手順
クイックスタート(5 分で動かす)
# 0. まずウェブ版にログインしてキーを 1 つ作成し(次節を参照)、sk_sora_xxx の形式の平文キーを取得する
export SORA_KEY="sk_sora_あなたのキー"
# 1. 残高を照会し、積分があることを確認する
curl -s https://sora2u.com/api/v1/credits \
-H "Authorization: Bearer $SORA_KEY"
# 2. テキストから動画を生成するタスクを 1 つ作成する
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"コーギーが海辺を駆ける、映画のような質感、夕暮れの光","model":"seedance-2.0","duration":5}'
# => { "success": true, "task": { "id": "ckxxx", "status": "pending", ... } }
# 3. 前のステップで返ってきた task.id で結果をポーリングする(5 秒ごとに 1 回)
curl -s https://sora2u.com/api/v1/videos/ckxxx \
-H "Authorization: Bearer $SORA_KEY"
# status = "completed" になったとき、video_url が完成した動画のアドレスAPI キーの取得と管理
API キーはあなたのアカウントに紐づき、あなた本人を代表してインターフェースを呼び出し、あなたの積分を消費します。パスワードと同じように大切に保管してください。
キーの作成 / 一覧 / 失効はウェブ版のログイン状態(Cookie セッション)で行い、通常はコンソールページから呼び出されます:
キーを作成 · POST /api/api-keys
リクエストボディ(いずれも任意):
| フィールド | 型 | 説明 |
|---|---|---|
name | string | キーのメモ名。用途を区別しやすくする。最長 60 文字、デフォルトは「デフォルトキー」 |
expires_in_days | number | 有効日数(1–3650)。指定しなければ無期限 |
レスポンス(201)——平文キーはこの 1 回だけ返されます。すぐに保存してください:
{
"success": true,
"api_key": "sk_sora_AbC1d2Ef...完全な平文...",
"key": {
"id": "ckkey123",
"name": "私のスクリプト",
"key_prefix": "sk_sora_AbC1…",
"expires_at": null,
"created_at": "2026-06-17T12:00:00.000Z"
},
"warning": "このキーは大切に保管してください。表示されるのはこの 1 回だけで、再度確認することはできません。"
}キーを一覧 · GET /api/api-keys
返るのは接頭辞と状態のみで、平文は決して返りません:
{
"success": true,
"keys": [
{
"id": "ckkey123",
"name": "私のスクリプト",
"key_prefix": "sk_sora_AbC1…",
"status": "active",
"last_used_at": "2026-06-17T12:30:00.000Z",
"expires_at": null,
"revoked_at": null,
"created_at": "2026-06-17T12:00:00.000Z"
}
]
}status の値:active(有効)、expired(期限切れ)、revoked(失効済み)。
キーを失効 · DELETE /api/api-keys/{id}
即座に無効化され、操作は冪等です(重複して失効させても成功を返します)。漏洩した場合は、ただちに失効させて再作成してください。
1 アカウントにつき有効なキーは最大 20 把まで保持できます。超える場合はまず古いキーを失効させる必要があります。
認証方式
すべての /api/v1/* インターフェースはリクエストヘッダーにキーを付与する必要があり、2 つの書き方をサポートします(1 つ目を推奨):
Authorization: Bearer sk_sora_あなたのキーx-api-key: sk_sora_あなたのキー認証に失敗すると一律 401 を返します:
{ "error": { "code": "unauthorized", "message": "API キーが欠落しているか無効です..." } }サーバーはキーの SHA-256 ハッシュのみを保存し、平文は保存しません。そのため、一度失うと再作成するしかなく、復元はできません。
クロスオリジン呼び出し(CORS)
/api/v1/* はすでに CORS が有効で、任意のウェブオリジンからブラウザ内で直接呼び出せます(OpenAI 互換クライアントの「Base URL + API Key」直結モード):
- すべてのレスポンスに
Access-Control-Allow-Origin: *が付きます。 - ブラウザは
Authorizationヘッダー付き、またはPOST/DELETEを使う前にまずOPTIONSプリフライトを送りますが、本 API は正しく応答します(204+Access-Control-Allow-*)。 - 認証には
Authorization: Bearer/x-api-key(Cookie ではない)を使うため、任意のオリジンを許可し、credentialsは不要です。
注意:キーはあなた本人の課金を意味します。純粋なフロントエンド(ブラウザ)で使う場合、キーはエンドユーザーに露出します——信頼できる場面(ユーザーが自分のキーを入力するなど)でのみこのように使ってください。一般公開向けのページでは、あなた自身のバックエンドでプロキシ転送するように変更し、キーをフロントエンドのコードに書かないでください。
動画を 1 本生成する
POST /api/v1/videos
リクエストボディ(JSON):
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
prompt | string | ✅ | 動画の説明、最低 10 文字。`< |
model | string | ❌ | モデル名、デフォルトは seedance-2.0(GET /api/v1/models を参照) |
duration | number | ❌ | 長さ(秒)。モデルのサポート範囲に応じて自動的に丸めてクランプされる |
aspect_ratio | string | ❌ | 画面比率、例:9:16、16:9(モデルのサポートに依存) |
resolution | string | ❌ | 解像度、例:720p |
mute / disable_audio | boolean | ❌ | 静音生成:true のときエンジンに自動 BGM を付けない / 音声トラックを出力しないよう要求し、Seedance 2.0 の自動 BGM が output_audio_copyright(著作権 / センシティブ)で失敗するのを回避。既定は false |
reference | string | ❌ | インライン参照素材(画像 / 動画 / 音声)の base64。data:<mime>;base64, 接頭辞を付けてもよい。リクエストボディ ~4.5MB の上限に制約され、画像や小さめのファイルに適する。詳しくは後述の「参照素材のアップロード」節を参照 |
reference_url | string | ❌ | 参照素材の公開 https 直リンク。サーバーがダウンロードしてエンジンに引き渡す。大きめの動画 / 音声にはこれを使う(リクエストボディのサイズ制限を回避)。reference と同時に渡した場合は両方とも参照素材としてまとめて送信されます(同じ上限で合算カウント) |
references | string[] | ❌ | 複数の参照素材の base64 配列(画像 / 動画 / 音声を混在可能:画像は最大 9、動画と音声は 1 つの 3 スロット枠を共用(合計 ≤ 3)、総数は最大 12)。各要素のルールは reference と同じ。「参照素材のアップロード · 複数参照」を参照 |
reference_urls | string[] | ❌ | 複数の参照素材の公開 https 直リンク配列(上限は references と同じで、両者は合算してカウント)。各要素のルールは reference_url と同じ。references と混在可能 |
image / image_base64 | string | ❌ | reference の後方互換エイリアス(画像のケース) |
レスポンス(202 Accepted)——タスクは作成済みで、すでに積分が予約差し引きされ、バックグラウンド生成を開始します:
{
"success": true,
"task": {
"id": "ckxxx",
"status": "pending",
"model": "seedance-2.0",
"model_name": "Seedance 2.0",
"mode": "image-to-video",
"duration": 5,
"estimated_credits": 100,
"estimated_time": "2〜6分",
"created_at": "2026-06-17T12:00:00.000Z"
},
"links": { "self": "/api/v1/videos/ckxxx" }
}注意:
estimated_creditsは予約差し引きの金額で、最終的にはタスク完了時の実際のコストで精算されます(過不足は返金・追加差し引き、課金を参照)。
例(画像から動画、image フィールド・裸の base64 に対応):
B64=$(base64 -i ./ref.png | tr -d '\n')
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d "{\"prompt\":\"画面の中のキャラクターをゆっくり振り向かせて微笑ませる\",\"model\":\"seedance-2.0\",\"image\":\"$B64\"}"スマートなモデル選択(参照素材がないとき自動で「テキストから動画」)
動画モデルには 2 つの動作形態があります:画像から動画 / 動画から動画 / 音声駆動(参照素材が必要)と、テキストから動画(純粋なテキスト、素材不要)。内部のテキストから動画モデルを気にする必要も、個別に指定することもできません——バックエンドが「参照素材があるかどうか」で自動的に判断します:
- 参照素材を提供した場合(
reference/reference_url/references/reference_urlsのいずれか)→ 選んだモデルで画像から動画 / 動画から動画 / 音声駆動を行う; - 参照素材を一切提供しなかった場合 → 同系列の「テキストから動画」形態に自動で切り替え、
promptから直接動画を生成する。
つまり、純粋なテキストから動画を生成したいときは、参照フィールドを一切渡さなければよいだけです(model は seedance-2.0、または省略してデフォルト)。課金・長さ・画面比率はすべて実際に有効になった形態で精算されます。GET /api/v1/models で supports_text_only: true のモデルが「素材なしでも生成できる」ものです。
レスポンスに何が返るか。 自動切り替えが起きても起きなくても、レスポンスの
model/model_nameは常にあなたが選んだ可視モデル(例:seedance-2.0)であり、内部 / 非公開のフォールバックモデル名が見えることは決してありません。レスポンスにはさらにmodeフィールドが付き、今回の実際の形態を示します:text-to-video(参照なし、自動でテキストから動画)、image-to-video(画像 / 動画 / 音声の参照を渡した)、image-generation(画像モデル)。つまり参照を渡さなかったときにtext-to-videoが返るのは想定どおりの挙動で、アップロードに対応していないという意味ではありません——参照をアップロードすればimage-to-videoになります。modeフィールドは作成レスポンスとタスク照会レスポンスの両方に含まれます。
# テキストから動画:参照フィールドを一切付けないだけ。バックエンドが自動でテキストから動画に進む
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"サイバーパンクの夜の街、ネオンに照らされた雨の路地、カメラがゆっくり前進","model":"seedance-2.0","duration":5}'モデル能力一覧
正確な情報は GET /api/v1/models を参照してください。下表は主要モデルの参照素材対応の早見表です:
モデル (model) | 出力 | 文生成 | 画像参照 | 動画参照 | 音声参照 |
|---|---|---|---|---|---|
seedance-2.0 | 動画 | ✅ | ✅ | ✅ | ✅ |
seedance-2.0-character | 動画 | ✅ | ✅ | ✅ | ✅ |
seedance-1.5 | 動画 | ✅ | ✅ | ❌ | ❌ |
gemini-image / kontext-image | 画像 | ✅ | ✅ | ❌ | ❌ |
- 全モーダル(
seedance-2.0/seedance-2.0-character):文 / 画像 / 動画 / 音声の参照すべてに対応。 - 画像のみ(
seedance-1.5):画像参照のみ。動画 / 音声参照を渡すと作成時に400 unsupported_reference。 - 画像生成(
gemini-image/kontext-image):画像参照のみ(最大 4 枚)、動画 / 音声は非対応。
参照素材のアップロード(画像 / 動画 / 音声)
POST /api/v1/videos は 3 種類の参照素材をサポートします:画像(画像から動画)、動画(動画から動画)、音声(音声駆動)。
素材をインターフェースに渡す方法は 2 つあり、ファイルサイズに応じて 2 択です:
| 方式 | フィールド | 適する対象 | 上限 | 説明 |
|---|---|---|---|---|
| インライン base64 | reference | 画像、小さめの短い動画 / 音声 | 1 回のリクエストボディ ~4.5MB(プラットフォームの硬性制限) | base64 を JSON に直接入れる。簡単だが、大きなファイルは 413 FUNCTION_PAYLOAD_TOO_LARGE を引き起こす |
| リモート直リンク | reference_url | 大きめの動画 / 音声 | 画像 10MB、動画 100MB、音声 50MB | ファイルを公開 https アドレスに置き、サーバーがダウンロードしてエンジンに引き渡し、リクエストボディの上限を回避する |
共通ルール:
- 対応する種類はモデルが決める:
GET /api/v1/modelsのsupports_image/supports_video/supports_audioが、各モデルがどの参照種類をサポートするかを示します。seedance-2.0(Seedance 2.0)は画像 / 動画 / 音声をサポートし、seedance-1.5(Seedance 1.5)は画像のみサポートします。モデルが対応しない種類の参照を渡すと、作成時に400 unsupported_referenceを返します(例:seedance-1.5に動画 / 音声参照を渡す)——レンダリング段階まで待たずに失敗します。 - ⚠️ 画像参照は必ず実写の・内容のある写真を使ってください。 単色ブロック、プレースホルダー画像、明らかに合成 / AI 生成の画像で「上限を試す」ことはしないでください。こうした情報量の少ない画像はエンジンの低品質コンテンツ審査に引っかかり、エラーコード
10001305(多くは「コミュニティガイドライン」と表示される)で失敗します——これは実際のコンテンツ違反ではありません。同じ枚数でも実写の写真なら問題なく通ります。プレースホルダー画像でのテストは 100% 失敗し、真の上限について誤解を招きます。 - 動画参照は幅 300px 以上・長さ 15 秒未満(音声も 15 秒未満):
- 幅 300px 未満:MP4 / MOV は作成時に事前判定し
400 invalid_referenceを返します(messageは「参考视频宽度须 ≥ 300px(当前约 200px)」のような形式)。事前解析できないコンテナ(WebM など)はエンジンがレンダリング段階で担保します。 - 長さ 15 秒超:
reference_urlの場合は作成時に同期的に400 invalid_reference_urlを返します(messageはVideo is 18.0s — reference must be under 15s.のような形式)。reference(base64) の場合はバックエンド処理段階で失敗し、errorに理由が入り、予約クレジットは自動返却されます。
- 幅 300px 未満:MP4 / MOV は作成時に事前判定し
- base64 で動画 / 音声を渡すときは必ず data URL を使う:裸の base64 は種類情報がないため画像として扱われます。つまり
referenceはdata:video/mp4;base64,...、data:audio/mpeg;base64,...のように書く必要があります。 referenceとreference_urlを同時に提供した場合は、両方とも参照として一括で送信されます(references/reference_urlsと 1 組にまとめられ、同じ数量上限で合算してカウントされます)。- 複数参照(重ね合わせ):
references(base64 配列)/reference_urls(直リンク配列)で一度に複数の素材を渡すと、エンジンはそれらをまとめて参照入力として扱います。動画生成(seedance-2.0など)は混合参照に対応:画像 ≤ 9(重ね合わせ可)+ 動画と音声が 1 つの 3 スロット枠を共用(合計 ≤ 3)+ 総数 ≤ 12(例:画像 9 + 動画 3 = 12、または 画像 7 + 動画 2 + 音声 1 = 10)。画像生成モデルは画像参照のみで最大 4 枚。上限を超えると400 too_many_referencesを返します。単数・複数のフィールドは混在でき、reference_urls → referencesの順で 1 組にまとめられます。
サポートする一般的なフォーマット:画像 png/jpg/jpeg/webp、動画 mp4/mov/webm、音声 mp3/wav/m4a(Content-Type が優先)。
⚠️ 参照素材のよくある落とし穴チートシート
- 画像参照は実写の写真を使い、単色/プレースホルダー/合成画像は使わない(低品質審査
10001305が発火し、「コミュニティガイドライン」と誤表示される)。- base64 の動画/音声は必ず接頭辞
data:video/mp4;base64,/data:audio/mpeg;base64,を付ける(付けないと画像扱い)。- 動画参照は幅 ≥ 300px・長さ < 15 秒、音声は長さ < 15 秒。
- 数量:画像 ≤ 9、動画 + 音声は 1 つの 3 スロット枠を共用(合計 ≤ 3)、総数 ≤ 12。
202は受理を意味するだけで成功ではない——status = completedかつvideo_urlが非空になるまでポーリングが必須。失敗時はerror/error_code/retryableを読む(「エラーコード」参照)。
A. 画像(base64、最もよく使う)
B64=$(base64 -i ./ref.png | tr -d '\n')
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d "{\"prompt\":\"画面の中のキャラクターをゆっくり振り向かせて微笑ませる\",\"model\":\"seedance-2.0\",\"reference\":\"data:image/png;base64,$B64\"}"B. 動画 / 音声(大きなファイル、reference_url を使う、推奨)
# まず 15 秒未満の参照動画を任意の公開 https アドレス(あなたの OSS / S3 / CDN など)に置く
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "参照動画の運鏡を引き継ぎ、カメラをさらに前進させる",
"model": "seedance-2.0",
"reference_url": "https://your-cdn.com/clips/ref-12s.mp4"
}'# 音声駆動も同様
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt":"人物がこの音声のリズムに合わせて話す","model":"seedance-2.0","reference_url":"https://your-cdn.com/clips/voice-10s.mp3"}'C. 動画 / 音声(小さなファイル、インライン base64)
B64=$(base64 -i ./ref.mp4 | tr -d '\n') # デコード後は ~3MB 未満である必要がある。そうでなければ reference_url に切り替えること
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d "{\"prompt\":\"参照動画の運鏡を引き継ぐ\",\"model\":\"seedance-2.0\",\"reference\":\"data:video/mp4;base64,$B64\"}"D. 複数の参照画像(重ね合わせ、最大 9 枚)
references(base64 配列)で一度に複数枚の画像を渡します。reference_urls で複数の直リンクを渡すことも、両者を混在させることもできます(画像は最大 9 枚。動画 / 音声も混在可能で、動画と音声は 1 つの 3 スロット枠を共用(合計 ≤ 3))。
A=$(base64 -i ./char.png | tr -d '\n') # キャラクター参照
B=$(base64 -i ./scene.png | tr -d '\n') # シーン参照
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d "{\"prompt\":\"このキャラクターをこのシーンに登場させ、自然に歩かせる\",\"model\":\"seedance-2.0\",\"references\":[\"data:image/png;base64,$A\",\"data:image/png;base64,$B\"]}"# 複数の公開直リンクを使う(大きめの画像に適する)。references と混在可能
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "この 2 枚の参照画像を 1 つの連続した運鏡に融合する",
"model": "seedance-2.0",
"reference_urls": ["https://your-cdn.com/a.jpg", "https://your-cdn.com/b.jpg"]
}'
reference_urlのダウンロード挙動と制限:httpsのみを受け付け、内部ネットワーク / ループバックアドレスに解決されるドメインは拒否し、301/302/307 などいかなるリダイレクトにも従いません——直接アクセス可能でリダイレクトのない直リンクを提供してください。素材 1 件あたりのダウンロードタイムアウトは 120 秒です(最大 100MB の動画参照を考慮した値)。サーバーはUser-Agent: Sora2U-Reference-Fetcher/1.0でダウンロードを行うため、配信元で UA によるブロックはしないでください。配信元がapplication/octet-streamを返す、またはContent-Typeが欠落している場合は、ファイル先頭のマジックバイトから種類を自動判別します(判別できない場合のみ拒否します)。query パラメータ付きの一時署名 URL は利用可能ですが、有効期限が生成プロセス全体をカバーするようにしてください(≥ 1 時間を推奨)——生成エンジンはレンダリング段階で素材を再取得することがあり、その時点で署名が期限切れだとタスクはreference_download_failedで失敗します。素材ごとのエラー帰属:ダウンロード / 検証 / アップロードに失敗した場合は
400 invalid_reference_urlを返し(base64 のサイズ超過は413 reference_too_large)、エラーボディにfailed_referenceフィールドが付きます:{ "index": <0 始まりの添字:本エンドポイントでは同一ソース(url / base64)配列内、火山互換の /v1/contents/generations/tasks では content 配列内の位置>, "source": "url" | "base64", "url_host": "<配信元の host のみ。完全な署名付き URL は返しません>", "http_status": <配信元が返した HTTP ステータスコード。ダウンロード失敗時のみ>, "reason": <機械可読な失敗カテゴリ。ダウンロード系失敗時のみ:network / timeout / http / invalid_url / unsafe_url / unsupported_type / too_large> }。どの素材で何が起きたかを特定するのに利用できます。
E. プロンプト内で参照素材の位置を指定する(<|media:N|> トークン)
デフォルト(プロンプトにトークンを書かない)では、エンジンが各参照素材の作用位置を自動的に決めます——たとえば音声参照は自動的に文末へ連結されます。ほとんどの用途はこれで十分です。
素材を文中の正確な位置に固定したい場合(例:「彼女がこの音声を話し終えてから振り向く。背景はこの画像を維持」)、prompt に位置指定トークン <|media:N|> を埋め込みます:
- N は今回のリクエストで送信した参照リスト内の 0 始まりの添字——「送信順 = N」が唯一のハード制約です。
- サーバーとエンジンは
<|media:N|>をそのまま透過し、書き換えません。トークンを書かなかった素材は従来どおりエンジンが自動配置します。 - フィールド混用時の合成順序を暗算しないで済むよう、参照はひとつの配列フィールドにまとめることを推奨します(すべて
reference_urls、またはすべてreferences)——その場合 N は配列の添字そのものです。混用時の合成順序は:URL 系が先(reference_url→reference_urls)、base64 系が後(reference→references)。 - 参照素材が 1 件だけの場合、それが
<|media:0|>です。
# 画像(添字0) + 音声(添字1):人物が音声の内容を話し、画面は参照画像を維持
curl -s -X POST https://sora2u.com/api/v1/videos \
-H "Authorization: Bearer $SORA_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": "彼女は <|media:1|> と話してから振り向く。人物と背景は <|media:0|> の見た目を維持",
"model": "seedance-2.0",
"reference_urls": ["https://your-cdn.com/char.png", "https://your-cdn.com/voice-10s.mp3"]
}'タスクの状態を照会する
GET /api/v1/videos/{id}
照会できるのは本人のタスクのみです。タスクが pending/processing の状態にあるとき、このインターフェースはついでに 1 回の照合をトリガーし、
最新の進捗を取得します。
{
"success": true,
"task": {
"id": "ckxxx",
"status": "completed",
"progress": 100,
"progress_text": "生成完了",
"prompt": "コーギーが海辺を駆ける...",
"model": "seedance-2.0",
"mode": "text-to-video",
"image_url": null,
"video_url": "https://.../result.mp4",
"error": null,
"error_code": null,
"retryable": null,
"estimated_credits": 100,
"reserved_credits": 0,
"credits_charged": 96,
"created_at": "2026-06-17T12:00:00.000Z",
"updated_at": "2026-06-17T12:04:10.000Z",
"completed_at": "2026-06-17T12:04:10.000Z"
}
}失敗タスクの例(error は脱敏済みの安全な文言。error_code / retryable で分岐する。「エラーコード · タスク失敗のエラーコード」を参照):
{
"success": true,
"task": {
"id": "ckxxx",
"status": "failed",
"video_url": null,
"error": "コンテンツ審査に不合格。単色/合成/プレースホルダーの参照画像で低品質検知に触れるケースが多いです。実写の画像に変更して再試行してください。",
"error_code": "video_audit_rejected",
"retryable": true
}
}202≠ 成功:作成の202は受理を意味するだけ。status = completedかつvideo_url非空までポーリングが必須。status = completed→video_urlから成果物を取得。status = failed→error(安全な文言)/error_code(安定コード)/retryableを読む。予約クレジットは返却済み。- すべてのフィールドは
task配下(トップレベルではない)。video_urlは脱敏済みで内部セッションのパラメータを含まない。
video_url の有効期間
- 通常ケース(大多数):タスク完了時、プラットフォームは成果物を自前のオブジェクトストレージへ転送保存します。このとき
video_urlはhttps://.../api/files/videos/<id>.mp4?token=...の形式で、長期間有効です(token はそのファイルへの恒久的な署名で、期限切れになりません)。 - フォールバックケース(まれ):転送保存が一時的に失敗すると、
video_urlは一時的にhttps://.../api/video/<id>形式のエンジン中継アドレスにフォールバックします。このアドレスは上流の一時キャッシュに依存し、通常は数時間しか有効ではありません。プラットフォームは完了後 48 時間、転送保存を自動リトライし、成功すると同じタスクのvideo_urlは永続アドレスに更新されます(古い中継アドレスも自動的に新アドレスへ 302 リダイレクトされます)。 - 転送保存が成功する前に中継アドレスが期限切れになると、アクセスは
410とエラーコードvideo_expired(上流のメッセージはVideo expired (could not be cached in time))を返します。この時点で成果物は取得不能となり、再生成するしかありません。 - 推奨:完了後は**できるだけ早く(24 時間以内に)**成果物をダウンロードするか、自分のストレージへ転送してください。
video_urlを恒久的な CDN 直リンクとして扱わないでください。
タスクを取り消す · DELETE /api/v1/videos/{id}
pending / processing のみ取り消し可能で、取り消し後は予約差し引きの積分を返金します:
{ "success": true, "refunded": true, "message": "タスクを取り消しました。積分は返金されました。" }その他のインターフェース
最近のタスクを一覧 · GET /api/v1/videos?limit=20
本人の最近のタスク一覧を返します。limit の範囲は 1–50、デフォルトは 20。
{ "success": true, "count": 2, "data": [ { "id": "...", "status": "completed", ... } ] }モデルと課金ルール · GET /api/v1/models
レスポンスは OpenAI 互換のリストラッパーに従います:トップレベルの object: "list" + data 配列、各モデルは object: "model" で、
その id が公開モデル名(タスク作成時の model 入力パラメータとして使用)であり、内部エンジン id は含みません。さらに default_model
と credit_rule を添えて、コンテキストを一度に取得できるようにしています。
{
"object": "list",
"data": [
{
"id": "seedance-1.5",
"object": "model",
"created": 1735689600,
"owned_by": "sora2u",
"name": "Seedance 1.5",
"pricing_unit": "second",
"credit_cost_per_second": 10,
"credit_cost": 10,
"durations": [5, 8, 10, 12],
"default_duration": 5,
"aspect_ratios": ["9:16"],
"default_aspect_ratio": "9:16",
"resolutions": ["720p"],
"default_resolution": "720p",
"max_prompt_length": 2000,
"supports_image": true,
"supports_video": false,
"supports_audio": false,
"reference_max_seconds": 15,
"estimated_time": "2〜6分"
},
{
"id": "seedance-2.0",
"object": "model",
"created": 1735689600,
"owned_by": "sora2u",
"name": "Seedance 2.0",
"credit_cost_per_second": 20,
"supports_image": true,
"supports_video": true,
"supports_audio": true,
"reference_max_seconds": 15,
"...": "..."
}
],
"default_model": "seedance-2.0",
"credit_rule": {
"currency": "GP",
"gp_per_video_second": 10,
"min_charge_gp": 1,
"note": "予約差し引き = credit_cost_per_second × duration;タスク完了後は実際のコストで精算し、過不足は返金・追加差し引き。"
}
}残高を照会 · GET /api/v1/credits
{
"success": true,
"balance": 1280,
"currency": "GP",
"daily_free_video": { "eligible": false, "remaining_today": 0, "note": "..." }
}課金と積分の差し引き
動画生成は GP 積分を消費し、全プロセスがウェブ版と一致します:
- 予約差し引き(タスク作成時):
予約差し引き積分 = モデルの毎秒積分 × 長さ(秒)に従って残高をアトミックに差し引きます。 残高不足の場合は直接402 insufficient_creditsを返し、タスクは作成されません。 複数のタスクを同時に作成する場合でも差し引きはアトミックで、残高をマイナスに差し引くことはありません。 - 精算(タスク完了時):上流エンジンの実際のコストを積分に換算し、予約差し引きとの差額を取ります——
実際の方が高ければ追加差し引き、安ければ差額を返金します。最終的な課金はタスクの
credits_chargedに反映されます。 - 返金(タスク失敗 / 取り消し時):予約差し引きした積分を全額返金します。
毎日の無料枠について:ウェブ版の過去の有料ユーザーには毎日 1 本の無料動画枠があります。 スクリプトのバッチ呼び出しがこの枠をひそかに食いつぶすのを避けるため、オープン API はデフォルトで無料枠を使用せず、常に積分で課金します。
積分のチャージはウェブ版の購入ページで行ってください(オープン API は支払いに関与しません)。
タスク状態マシン
pending ──▶ processing ──▶ completed
│ │
└─────────────┴────────▶ failed (予約差し引きの積分は自動返金)
│
└──(DELETE)──────────────▶ 取り消し (予約差し引きの積分は自動返金)| 状態 | 意味 | 次のステップ |
|---|---|---|
pending | 作成済み、キュー待ち | ポーリング |
processing | 生成中 | ポーリング、progress を読める |
completed | 完了 | video_url を取得 |
failed | 失敗 | error を読む、積分は返金済み |
progressは段階のマイルストーンであり、線形のパーセンテージではありません:5 = 作成済み、20 = 参照素材のアップロード、35 = 生成エンジンへ送信中、55 = エンジン受理済み、70 = レンダリング中、100 = 完了。70 はタスクが終端状態に落ちるまで維持され、レンダリング中に数分間変化しないのは正常です。失敗タスクのprogressは失敗が発生した段階で止まります:35 ≈ 送信段階での失敗、70 ≈ レンダリング段階での失敗。これを利用して失敗を段階別に集計できます。⚠️
pending/processing状態で返されるvideo_urlは、送信時に事前に書き込まれたプロキシアドレスであり、成果物ではなく、ダウンロードもできません。成功を判定する唯一の基準はstatus === "completed"です(failed状態ではvideo_urlは常にnullです)。
エラーコード
エラーは一律 { "error": { "code", "message", ... } } の形式です。
| HTTP | code | 説明 |
|---|---|---|
| 400 | invalid_json | リクエストボディが正当な JSON ではない |
| 400 | invalid_prompt | prompt が欠落、または 10 文字に満たない |
| 400 | invalid_model | モデル名が存在しない |
| 400 | invalid_param | パラメータが不正(duration が数値でない等) |
| 400 | invalid_reference | reference が正当な base64 でない |
| 400 | invalid_reference_url | reference_url が不正 / 非 https / 内部ネットワークを指す / ダウンロード不可(タイムアウト・サイズ超過を含む)/ 種類が一致しない / 動画・音声が 15 秒超。エラーボディに failed_reference 帰属情報(index / url_host / http_status / reason)を付与 |
| 400 | unsupported_media | 参照ファイルの種類が非対応(image / video / audio のみ) |
| 400 | unsupported_reference | 選択したモデルがその種類の参照素材に対応していない(例:seedance-1.5 に動画/音声参照を渡す) |
| 400 | too_many_references | 参照素材が数量上限を超過(動画生成:画像は最大 9、動画 + 音声は 1 つの 3 スロット枠を共用(合計 ≤ 3)、総数は最大 12;画像生成:画像最大 4 枚) |
| 401 | unauthorized | キーの欠落 / 無効 / 失効済み / 期限切れ |
| 402 | insufficient_credits | 残高不足、current_balance、required_credits を付与 |
| 404 | not_found | タスクが存在しない、または本人のものでない |
| 409 | invalid_status | タスクの状態が変化し、取り消せない |
| 413 | reference_too_large | base64 参照がサイズ上限を超過(画像 10MB / 動画 100MB / 音声 50MB、プラットフォーム側の制限)。URL 参照のサイズ超過は 400 invalid_reference_url を返す。いずれも failed_reference 帰属情報を付与 |
| 500 | internal_error | サーバーエラー、リトライ可能 |
上の表は、作成 / 照会リクエストが同期的に返すエラー({ "error": { "code", "message" } })です。
タスク失敗のエラーコード(task.error_code)
タスクが受理(202)された後、生成の途中で失敗した場合、GET /api/v1/videos/{id} は status = "failed" を返し、失敗の原因を安定したフィールドに正規化します:error(安全な文言)、error_code(下表)、retryable(そのままの再試行に意味があるか)。上流エンジンの生のエラー文字列は脱敏され、内部の詳細が漏れることは決してありません。
error_code | 意味 | retryable |
|---|---|---|
video_audit_rejected | コンテンツ審査に不合格。多くは単色/合成/プレースホルダー参照画像による低品質検知(エラーコード 10001305「コミュニティガイドライン」)で、実際の違反ではない。実写の画像で再試行 | ✅ はい |
input_image_real_person | 参照画像に実在の人物が含まれている疑いがあり、モデルのプライバシー保護によりブロックされました。同じ画像での再試行も拒否されます——実在の人物以外 / カートゥーン / AI 合成の参照画像に差し替えるか、seedance-2.0-character(顔をスケッチとして匿名化)に切り替えてください | ❌ いいえ |
output_audio_copyright | 生成結果の BGM が著作権/センシティブ検知に触れた可能性(自動 BGM で多発)。再試行するか、プロンプトで特定の音楽を避ける | ✅ はい |
content_policy | プロンプトまたは参照素材がコンテンツポリシーに抵触。修正して再試行 | ❌ いいえ |
too_many_references | 参照素材の数が上限超過。数を減らす | ❌ いいえ |
invalid_reference | 参照素材が不正(動画は幅 ≥300px・長さ <15 秒・実在する有効ファイルが必要)。差し替える | ❌ いいえ |
reference_download_failed | 生成エンジンがレンダリング段階で参照素材の URL を取得できませんでした。リンクが公開アクセス可能で期限切れでないこと(署名 URL は有効期限 ≥ 1 時間を推奨)を確認してから再試行してください | ✅ はい |
reference_upload_failed | 参照素材の生成エンジンへのアップロードに失敗しました(プラットフォーム ↔ エンジン間の経路の問題)。タスクを再送信すれば解決します | ✅ はい |
engine_retry_exhausted | 生成エンジン内部で複数回(通常 3 回)試行しても失敗しました。多くは上流の一時的な揺らぎです。しばらくしてから再試行し、失敗が続く場合はプラットフォームへお問い合わせください | ✅ はい |
platform_timeout | プラットフォーム側でタスクがタイムアウトしました(キュー待ち / 処理が長時間進展しない)。自動的に取り消され、予約クレジットは返却済みです。そのまま再試行できます。頻発する場合はプラットフォームへお問い合わせください | ✅ はい |
settlement_failed | 生成は完了しましたが、実際の費用が見積もりを上回り、残高が追加差し引きに不足していました。チャージしてから再度実行してください | ❌ いいえ |
task_cancelled | タスクは呼び出し側によって取り消され、予約クレジットは返却済みです。続行する場合は新しいタスクを作成してください | — |
engine_error | その他の未分類のエンジン処理失敗(フォールバックコード) | ✅ はい |
リトライの指針:
retryable = trueは同一リクエストの再試行で成功が見込める(審査の抜き取り、エンジンの揺らぎ、自動 BGM の著作権など偶発要因)ことを示し、指数バックオフで 2〜3 回再試行を推奨。retryable = falseはリクエストの修正が必要(実写の参照画像に変更、数を減らす、プロンプト調整)。失敗タスクの予約クレジットは全額自動返却される。
ベストプラクティス
- ポーリングのリズム:5〜10 秒ごとに 1 回状態を照会し、終端状態(completed / failed / cancelled)までポーリングを続け、時間の予算として少なくとも 30 分を確保することを推奨します——複雑なタスクは完了まで 20 分を超えることがあるため、固定の 10 分ウィンドウで早めに失敗と判定しないでください(早期に放棄しても、タスクが最終的に完了すれば通常どおり課金されます)。放棄する場合は、まず
DELETE /api/v1/videos/{id}での取り消しを試してください(現時点ではキュー待ち / レンダリング未送信のタスクのみ対応。成功すると予約クレジットが返却されます)。GET /api/v1/videos/{id}はついでに照合をトリガーします。 - 成果物は早めに取得:
status = completedになったらできるだけ早く(24 時間以内に)video_urlをダウンロードし、自分のストレージへ転送してください。詳細は「タスク状態の照会 ·video_urlの有効期間」を参照。 - 先に残高を照会:バッチ生成の前にまず
GET /api/v1/creditsし、途中での402を避けてください。 - キーのセキュリティ:サーバーの環境変数の中だけに置き、絶対にフロントエンドのコード / リポジトリ / ログに書かないでください。用途ごとに複数のキーを分け、漏洩したらすぐ失効させてください。
- 有効期限を設定:一時的なスクリプトには
expires_in_daysで短期キーを作成し、漏洩リスクを下げてください。 - エラーリトライ:
5xxに対してのみ指数バックオフでリトライしてください。4xxは呼び出し側の問題なので、まずパラメータを直してから再試行してください。 - レート制限:積分の仕組み自体が乱用を制限します(積分がなければ生成できません)。高頻度のシステムと連携する必要がある場合は、運用担当に連絡してクォータを相談してください。
完全な例
Node.js(18+、ネイティブ fetch)
const BASE = "https://sora2u.com";
const KEY = process.env.SORA_KEY;
const headers = {
Authorization: `Bearer ${KEY}`,
"Content-Type": "application/json",
};
async function generate(prompt) {
const res = await fetch(`${BASE}/api/v1/videos`, {
method: "POST",
headers,
body: JSON.stringify({ prompt, model: "seedance-2.0", duration: 5 }),
});
if (!res.ok) throw new Error(`作成失敗: ${JSON.stringify(await res.json())}`);
const { task } = await res.json();
// 完了するまでポーリング
for (let i = 0; i < 120; i++) {
await new Promise((r) => setTimeout(r, 5000));
const s = await (
await fetch(`${BASE}/api/v1/videos/${task.id}`, { headers })
).json();
if (s.task.status === "completed") return s.task.video_url;
if (s.task.status === "failed") throw new Error(s.task.error);
}
throw new Error("タイムアウト");
}
generate("コーギーが海辺を駆ける、映画のような質感").then(console.log);Python(requests)
import os, time, requests
BASE = "https://sora2u.com"
H = {"Authorization": f"Bearer {os.environ['SORA_KEY']}"}
def generate(prompt: str) -> str:
r = requests.post(f"{BASE}/api/v1/videos", headers=H,
json={"prompt": prompt, "model": "seedance-2.0", "duration": 5})
r.raise_for_status()
task_id = r.json()["task"]["id"]
for _ in range(120):
time.sleep(5)
t = requests.get(f"{BASE}/api/v1/videos/{task_id}", headers=H).json()["task"]
if t["status"] == "completed":
return t["video_url"]
if t["status"] == "failed":
raise RuntimeError(t["error"])
raise TimeoutError()
print(generate("コーギーが海辺を駆ける、映画のような質感"))AI 向け:MCP とスキル
各種の AI(Claude、Cursor、ChatGPT など)が本 API を直接呼び出せるよう、リポジトリには 2 つのすぐ使える連携を内蔵しています:
- MCP Server:
mcp/sora2u-video-mcp/。stdio の MCP サーバーで、本 API をツールとして公開します:create_video(ローカルの画像 / 動画 / 音声を参照に使える)、get_video、list_videos、cancel_video、list_models、get_credits。Claude Desktop、Cursor、Cline などの MCP クライアントに対応し、設定はそのディレクトリの README を参照してください。 - スキル(Skill):
skills/sora2u-video/SKILL.md。Claude の「スキル」/ カスタム Agent 向けの説明書で、完全な呼び出しフローと参照素材のアップロード手引きを含みます。 - OpenAPI:このディレクトリの
openapi.yamlが機械可読な仕様で、ChatGPT の「Actions」/ カスタム GPT、Apifox、Postman に関数 / ツール定義としてそのままインポートできます。
3 つとも、画像 / 動画 / 音声の参照素材のアップロードの詳細(base64 と reference_url の 2 つの方式)をカバーしています。
メンテナー向け:リリース手順
今回、ApiKey データテーブルと一連の /api/v1/*、/api/api-keys インターフェースを新規追加しました。デプロイ前に必要なこと:
# 1. 依存をインストールし、Prisma Client を生成する(新しい ApiKey モデルを含む)
npm install
npx prisma generate
# 2. データベースマイグレーションを適用する(ApiKey テーブルを新規追加)
npx prisma migrate deploy # 本番
# またはローカル:npx prisma migrate dev
# 3. 通常どおりビルドして起動する
npm run build && npm start関係するコード:
- データモデル:
prisma/schema.prisma(ApiKey)+ マイグレーションprisma/migrations/20260617120000_add_api_keys - キーユーティリティ:
lib/auth/api-key.ts(生成 / ハッシュ / 認証) - 生成サービス:
lib/ai/video-generation-service.ts(サイト内とオープン API で共用する課金経路) - オープンインターフェース:
app/api/v1/{videos,videos/[id],models,credits}/route.ts - キー管理:
app/api/api-keys/route.ts、app/api/api-keys/[id]/route.ts - レスポンスユーティリティ:
lib/api/public-api.ts
認証に必要な環境変数は既存の動画生成と同じ(
DATABASE_URL、動画エンジン関連の設定など)で、オープン API は新しい必須の環境変数を導入していません。
