日本語のSeedance 2 API解説では、BytePlusの国際経路、Volcengineの中国経路、各社gatewayのAPIキーやモデル名が同じページに並びがちです。しかし、これらは置き換え可能な別名ではありません。ホスト、APIキーの適用範囲、モデルID、create/status pathを同じ提供元でそろえることが、実装の出発点です。
createが成功して返すのは完成動画ではなくtask IDです。送信前にローカル台帳を作り、task IDを保存し、コールバックとポーリングの両方で同じ台帳を更新します。以下では、設定票、契約差分、最小実装、運用runbook、症状別の切り分けという順に確認します。
実装前に設定票を1枚だけ作る
日本語の第三者記事からコード片を集める前に、選んだ経路を次の形で固定してください。値を一つだけ別ページから移植しないことが重要です。
yamlseedance_route: owner: byteplus-ap base_url: https://ark.ap-southeast.bytepluses.com/api/v3 secret_name: BYTEPLUS_ARK_API_KEY model_id: dreamina-seedance-2-0-260128 create_path: /contents/generations/tasks status_path: /contents/generations/tasks/{id} delivery: callback-and-repair-polling
secret_nameには秘密そのものではなく、サーバー側の環境変数名を置きます。レビュー時には次の問いに一行ずつ答えます。
- APIキーを発行した提供元とresource projectはどこか。
- そのキーを送ってよいホストとregionはどこか。
- モデルIDは
dreamina-*かdoubao-*か。 - createが返すtask IDを、どのstatus pathで照会するか。
- コールバックが欠落したとき、同じtask IDをどう回収するか。
BytePlusの一次資料はcreate API、Seedance 2.0 series tutorial、APIキー管理です。VolcengineはArk API reference、laozhang.aiは現行のSeedance relay docsだけを各経路の一次情報の所有元として扱います。日本語で読みやすくても、第三者ページのhost、alias、callback bodyを別経路へ持ち込みません。
経路ごとの契約差分を確認する
| 経路 | ホスト・キーの適用範囲 | 現在確認したモデルID | 非同期API |
|---|---|---|---|
| BytePlus ModelArk(国際AP) | https://ark.ap-southeast.bytepluses.com/api/v3、ModelArk resource projectのBearer key | Standard dreamina-seedance-2-0-260128、Fast dreamina-seedance-2-0-fast-260128、Mini dreamina-seedance-2-0-mini-260615 | POST /contents/generations/tasks、GET /contents/generations/tasks/{id} |
| Volcengine Ark(中国) | https://ark.cn-beijing.volces.com/api/v3、中 国regionのArk projectで発行したBearer key | Standard doubao-seedance-2-0-260128、Fast doubao-seedance-2-0-fast-260128 | 同じ相対create/status pathを中国ホストで使用 |
| laozhang.ai gateway | https://api.laozhang.ai/seedance/api/v3、SeeDance2 groupへ割り当てたBearer token | doubao-seedance-2-0-260128 または doubao-seedance-2-0-fast-260128 | Ark型create/status、互換downloadは GET https://api.laozhang.ai/v1/videos/{id}/content |
BytePlusではAPIキーをresource project内で作成し、model/custom endpointやIP allowlistで制限できます。キーはブラウザ、モバイルアプリ、URL、公開repositoryへ入れず、サーバー側で保持します。ドキュメントにモデルIDが載っていても、対象アカウントのregion、resource package、activationが整っている証明にはなりません。
Standardは品質優先、Fastは速度と費用のバランス、Miniは費用対効果を重視する選択肢です。これはBytePlus内の分類です。VolcengineのMini suffixをBytePlusの命名から推測してはいけません。対象アカウントの現在のmodel listに表示された値だけを使います。価格は更新の主体が異なるため、Seedance 2料金ガイドへ分けています。
経路選択にも停止条件があります。国際アカウントの公式所有、Standard/Fast/Mini catalog、endpoint単位の制御が必要ならBytePlus direct、中国infrastructureとdoubao-* contractが前提ならVolcengine directが候補です。単一gatewayで運用をまとめたい場合はlaozhang.ai relayを検討できますが、必要なregion、variant、account control、機能がdocsにない時点で公式の直接経路へ戻ります。現行relay docsでは実在人物の顔を使うworkflowは未対応です。この用途は実在人物入力のルールで別途確認してください。
BytePlus APの最小実装を組む
次の例は設定票がbyteplus-apの場合だけ有効です。別経路へ移るときは、ホストだけでなくキー、モデルID、APIパスを一式で切り替えます。
bashexport ARK_API_KEY="replace-with-server-side-secret" curl -X POST \ "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks" \ -H "Authorization: Bearer $ARK_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "dreamina-seedance-2-0-260128", "content": [{ "type": "text", "text": "A ceramic cup on a wooden desk, one slow camera move, soft morning light" }], "ratio": "16:9", "duration": 5, "generate_audio": false, "priority": 3, "callback_url": "https://example.com/webhooks/seedance" }'
priorityはSeedance 2.0のendpoint-based online inferenceで0から9まで指定できます。大きい値は同じendpointで待機中の低priority taskより前へ移すだけです。実行中のtaskを中断せず、別endpointのqueueをまたがず、offline flex inferenceには適用されません。生成処理そのものが速くなる保証でもありません。
送信前に台帳を作り、レスポンスのtask IDを同じレコードへ書き込みます。ここではコールバック側が使うlastEventKeyまでスキーマに含めます。
tstype SeedanceLedger = { jobId: string; route: "byteplus-ap" | "volcengine-cn" | "laozhang-relay"; requestHash: string; providerTaskId?: string; state: "submitting" | "queued" | "running" | "succeeded" | "failed" | "expired"; lastEventKey?: string; lastRawEvent?: unknown; storedResult?: string; };
requestHashには経路、モデルID、正規化したprompt、asset ID、出力条件を含めます。これは提供元の重複排除機能を主張するものではなく、自分のアプリで同じ操作から二重createを出さないための鍵です。
コールバックとポーリングを運用runbookへ落とす
現在のModelArk contractではcallback_urlは任意です。payloadはretrieve-task responseと同じ形で、状態はqueued、running、succeeded、failed、expiredです。terminalのsucceededまたはfailedを配信できず、5秒以内に成功確認が得られない場合、ドキュメントは3回の再配信を示しています。これはexactly-once deliveryの保証ではありません。また、公開referenceから断定できるwebhook signatureは確認できないため、架空の署名headerを実装しません。
運用手順は次のとおりです。
- submit前:
requestHashを持つ台帳をsubmittingで作る。 - create受理後:
providerTaskIdを同じ台帳へ原子的に保存する。ここは動画完成ではない。 - callback受信時: HTTPS、content type、body size、既知task ID、許可したstate transitionを確認し、重いdownloadより先に2xxを返す。
- 通知欠落時: 非terminal recordだけを定期的にpollingし、callbackと同じstate reducerへ渡す。
- terminal時:
succeededならworkerでoutputを取得し、自分のobject storageへコピーしてstoredResultを更新する。 - create timeout時:
create_unknown相当で隔離し、既存taskとの照合が終わるまで再送しない。
コールバックの適用は、event keyの保存と状態更新を同じtransactionに入れます。
tstype ProviderTask = { id: string; status: "queued" | "running" | "succeeded" | "failed" | "expired"; }; const stateRank = { queued: 0, running: 1, succeeded: 2, failed: 2, expired: 2 } as const; const terminalStates = new Set(["succeeded", "failed", "expired"]); function canAdvance(current: SeedanceLedger["state"], next: ProviderTask["status"]) { if (terminalStates.has(current)) return false; const currentRank = current === "submitting" ? -1 : stateRank[current]; return stateRank[next] >= currentRank; } async function reconcileCallback(event: ProviderTask) { const job = await ledger.findByProviderTaskId(event.id); if (!job) return new Response(null, { status: 404 }); const eventKey = `${event.id}:${event.status}`; const applied = await ledger.transaction(job.jobId, async (current) => { if (current.lastEventKey === eventKey) return false; if (!canAdvance(current.state, event.status)) { await events.recordIgnored(current.jobId, event); return false; } await ledger.apply(current.jobId, { state: event.status, lastEventKey: eventKey, lastRawEvent: event, }); return true; }); if (applied && event.status === "succeeded") { await resultQueue.add(job.jobId); } return new Response(null, { status: 204 }); }
修復用の照会は、保存済みtask IDと同じ経路のキーを使います。
bashcurl -X GET \ "https://ark.ap-southeast.bytepluses.com/api/v3/contents/generations/tasks/$TASK_ID" \ -H "Authorization: Bearer $ARK_API_KEY"
create timeoutは通信結果が不明という意味であり、providerがtaskを作っていない証明ではありません。requestHashで台帳を探し、別workerがtask IDを保存していないか確認し、提供元にlist/reconciliation手段があれば既存taskを照合します。不在を確認できない場合はoperator判断へ送り、自動で二つ目の有料taskを作りません。
output URLの固定保存期間は今回再確認できていません。succeeded後はdownload responseのstatusとmedia typeを確認し、速やかに自分のstorageへ保存します。provider URLを恒久リンクとして扱いません。
症状別に修正レイヤーを切り分ける
2026年7月18日、実際のAPIキーを使わずbody {}で経路境界をprobeしました。BytePlus AP、Volcengine CN、正しいlaozhang.ai relay pathはJSONのHTTP 401、/seedanceを欠くlaozhang.aiの/api/v3/...はJSON 404、古い/seedance/v3/...はHTML 200でした。これは経路と認証境界の確認に限られ、model access、quota、成功生成、日本からのavailabilityを証明しません。
| 症状 | 疑うレイヤー | 確認する項目 | 停止条件 |
|---|---|---|---|
JSON 401 | 認証・region | ホスト、project、Bearer header、key scope。gatewayはSeeDance2 group | promptを変える前に認証設定を直す |
JSON 404 | base URL・path | /seedance/api/v3など提供元固有prefix | BytePlusのpathを別gateway rootへ足さない |
HTML 200 | 接続先の種類 | Content-TypeとJSON body | status codeだけで成功扱いしない |
| model not found / not enabled | モデルnamespace・activation | dreamina-*かdoubao-*か、同じprojectで有効か | Mini suffixを推測しない |
| callback重複 | イベント配送 | lastEventKeyと単調なstate transition | 新規生成へ変換しない |
| callback欠落 | 通知・deploy | 保存済みtask IDのpolling | createを再送しない |
| generation failed | model/input | provider error code、message、request hash | 原因分類前に再実行しない |
このrunでは認証済みcallや有料generationを行っていないため、成功率、latency、品質、quotaは主張しません。provider選定の比較はSeedance 2 APIプロバイダー比較、入力設計はSeedance 2プロンプトガイドへ分けます。
production前には設定票を再度開き、ホスト、key project/group、model namespace、API pathが同じ経路か、task IDとlastEventKeyが同じ台帳へ保存されるか、ポーリングが通知欠落を修復するか、timeout後にblind resubmitしないか、outputを自分のstorageへ移したかを確認してください。前半の契約がそろっていなければ、有料taskを送る前に止めるのが正解です。
