MiniMax H3 API で自動化する Image-to-Video(R2V)パイプライン
対象モデル:
minimax-h3
推論エンドポイント:https://api.toapis.com/v1/videos/generations
関連記事: MiniMax H3 API ガイド · カメラワークのプロンプト · H3 と Turbo の選び方
1. クイックスタートと性能概要 (TL;DR)
- 目的: MiniMax H3 のフレームモードで静止画を短いクリップにし、送信とポーリングを無人実行できるワーカーに包む。
- 入力: 1 要素リストの
first_frame_image、任意の 1 要素リストlast_frame_image、そのアンカーから離れる/周る動きを書くプロンプト、ベースminimax-h3では整数 4–15 秒。 - モード: フレーム入力と参照メディアは排他。Turbo(
minimax-h3-max-turbo)は参照メディアを拒否する。参照フィールドを Turbo のペイロードへコピーしない。 - ワーカー: 到達可能なアセットをステージし、POST は一度だけ、タスク識別子を保存し、バックオフと厳しい期限でポーリングし、結果 URL を自前のシステムへ保存する。
- 範囲: 現行 ToAPIs フロントエンド契約の統合ガイドであり、レイテンシ、可用性、価格のベンチマークではない。
2. パイプラインの設計
無人の R2V ワーカーは、呼び出し元の HTTP リクエストと時間のかかるレンダリングを切り離すべきです。
- 受け取る: プロダクトからのソース静止画とモーションプロンプト。
- ステージする: 文書化されたアップロードフロー、または取得権限のある URL を使う。プライベートなディスクパスより、短命で到達可能なロケータを持つオブジェクトストレージを優先する。
- 送信する:
model、prompt、duration、first_frame_imageを付けたPOST /v1/videos/generationsを一度だけ送る。 - ポーリングする: 文書化されたタスク状態エンドポイントを、上限付き指数バックオフと全体期限で確認する。
- 届ける: 結果の動画 URL を自前の通知経路(キュー、メール、プロダクト webhook)で渡す。2 回目の課金ジョブを作る前に状態を確認する。

図 1: 静止画をステージし、ToAPIs の generations ゲートウェイへ一度だけ送り、終端状態までポーリングしてから、自前のサービスが完成クリップを出します。
多くの 400 は、送信前の次の確認で防げます。
- アカウントで有効な正確なモデル ID を使う(
minimax-h3、minimax-h3-max、またはminimax-h3-max-turbo。別名を作らない)。 - duration は整数。ベース H3 は 4–15 秒、Max 系は 5–15 秒。
first_frame_imageとlast_frame_imageはそれぞれ最大 1 枚のリスト。- 同じリクエストで
reference_images、reference_videos、reference_audioを送らない。 - 現行フロントエンドはフレームモードで
ratioをadaptiveに固定する。静止画の形を意図したキャンバスに合わせる(ワイドなら 1920×1080、縦なら 1080×1920)と、予期しないクロップを減らせる。 - 契約上のフィールド名は
ratioであり、aspect_ratioではない。
フレームモードでもカメラ文言は使えます。カメラワークのプロンプトガイド を参照し、ブラケットタグはプロンプト補助として扱ってください。
3. 本番実装: cURL と Python
ステップ 1: cURL のファーストフレームリクエスト
curl -X POST "https://api.toapis.com/v1/videos/generations" \
-H "Authorization: Bearer $TOAPIS_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "minimax-h3",
"prompt": "[Dolly Forward] Rain falling onto neon asphalt, steam rising from grates, cinematic reflections",
"duration": 6,
"ratio": "16:9",
"first_frame_image": ["https://example.com/starting-frame.jpg"]
}'
プレースホルダ URL は、文書化されたアップロードフローのアセット識別子または URL に置き換えてください。公開済みの H3 契約では first_frame_image は配列であり、単独の文字列ではありません。
終了フレームも案内する場合は、同じフレームモードリクエストに "last_frame_image": ["https://example.com/ending-frame.jpg"] を追加します。これは標準のフレームモードであり、Turbo 専用の実験フラグではありません。
ステップ 2: 期限付きポーリングの Python ワーカー
出荷前に task_id、status、video_url をアカウント向けレスポンススキーマと照合してください。
import os
import time
import requests
from typing import Any
API_KEY = os.environ["TOAPIS_API_KEY"]
BASE_URL = "https://api.toapis.com/v1"
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
}
class MiniMaxR2VPipeline:
def trigger_r2v(
self,
image_ref: str,
prompt: str,
duration: int = 6,
last_frame_ref: str | None = None,
) -> str:
if not 4 <= duration <= 15:
raise ValueError("Base minimax-h3 accepts integer durations of 4-15 seconds")
payload: dict[str, Any] = {
"model": "minimax-h3",
"prompt": prompt,
"duration": duration,
"ratio": "16:9",
"first_frame_image": [image_ref],
}
if last_frame_ref:
payload["last_frame_image"] = [last_frame_ref]
res = requests.post(
f"{BASE_URL}/videos/generations",
headers=HEADERS,
json=payload,
timeout=30,
)
res.raise_for_status()
data = res.json()
task_id = data.get("task_id") or data.get("id")
if not task_id:
raise RuntimeError(f"Unexpected submission envelope: {data}")
return task_id
def poll_until_complete(self, task_id: str, max_timeout: int = 180) -> dict[str, Any]:
start = time.time()
interval = 3.0
poll_url = f"{BASE_URL}/videos/tasks/{task_id}"
while time.time() - start < max_timeout:
res = requests.get(poll_url, headers=HEADERS, timeout=15)
res.raise_for_status()
data = res.json()
status = data.get("status")
if status in {"succeeded", "success"}:
return {
"status": "success",
"task_id": task_id,
"video_url": data.get("video_url"),
"elapsed_seconds": round(time.time() - start, 2),
}
if status in {"failed", "error"}:
return {
"status": "error",
"task_id": task_id,
"error": data.get("error", "Generation failed"),
}
time.sleep(interval)
interval = min(interval * 1.1, 6.0)
return {
"status": "timeout",
"task_id": task_id,
"error": f"Exceeded {max_timeout}s; check task status before retrying",
}
if __name__ == "__main__":
pipeline = MiniMaxR2VPipeline()
# Replace with an uploaded asset identifier or a URL you are authorized to fetch.
image_ref = "https://example.com/starting-frame.jpg"
prompt = "[Dolly Forward] Rain falling onto neon asphalt, steam rising from grates, cinematic reflections"
task_id = pipeline.trigger_r2v(image_ref, prompt)
print("Task:", task_id)
print("Result:", pipeline.poll_until_complete(task_id))
タイムアウトは確定失敗ではありません。タスク識別子を記録し(API キーやプライベートなメディア URL は記録しない)、状態を見てから再送信を判断してください。
4. エラー処理とステータスマトリクス
以下の分類は診断の出発点であり、ToAPIs の正確なエラーコードを保証するものではありません。
| HTTP ステータス | よくある分類 | 推奨対応 |
|---|---|---|
400 | 無効なフィールド、到達不能または未対応のメディア、フレーム/参照モードの混在 | モデル ID、duration、1 要素リストの first_frame_image を検証し、参照フィールドが無いことを確認する |
401 | API キー欠落または無効 | ToAPIs ダッシュボードでキーをローテーションする |
429 | レートまたは同時実行の上限 | ジッター付きバックオフし、ローカルでキューする |
5xx またはネットワークタイムアウト | ゲートウェイまたは上流の一時障害 | 新しいジョブを作る前にタスク状態を再読する |
アップロード失敗はハードストップです。有効なアセット識別子が無いまま生成リクエストを送らないでください。
5. 料金と FinOps ROI
- 日付付きのアカウント見積を使う。 計画草案の秒単価や SLA パーセントを本番予測に貼らないでください。料金と失敗タスクの課金はモデルやルートで異なることがあります。
- 公式ベンダー契約 にはコミットや前払い下限が付くことがあります。ToAPIs アカウントが純粋な従量課金か、上流失敗がどう課金されるかを確認してください。
- パイプラインの規律 が実務上の FinOps レバーです。ショットごとに送信は一度、タイムアウト時は状態確認してから再試行、プロンプトテンプレートをタスクと一緒に保存し、duration は必要な最短クリップに抑える。
- 1080P が必要なら、正確な canonical
minimax-h3-maxID が有効かを確認します。Turbo が必要ならminimax-h3-max-turboを使い、参照メディアフィールドは省きます。詳細は 選定ガイド を参照してください。
6. よくある質問
構造化 FAQ は frontmatter を参照してください。要約: 静止画を意図したキャンバスに合わせる、終了フレーム案内は標準のフレームモード(各最大 1 枚)、プライベートパスではなく文書化されたアップロードフローを使う、本ガイドは ToAPIs webhook を前提にせずポーリングする。
7. アクションチェックリスト
- ToAPIs Developer Portal でキーを発行する。
- 文書化されたアップロードフローで静止画を 1 枚ステージし、cURL のファーストフレームリクエストをスモークテストする。
- 180 秒のポーリング期限と、タイムアウト時の重複送信禁止を備えた Python ワーカーを組み込む。
- バッチ実行の前に H3 リクエスト契約 と カメラワークのプロンプトガイド を見直す。







