HiAPI
ブログ

チュートリアル

PixVerse V6 画像から動画への API:すぐに実行できる curl と Python のサンプル

Oct 20, 2026
PixVerse V6 画像から動画への API:すぐに実行できる curl と Python のサンプル
モデル
pixverse-v6

hiapi 上で pixverse-v6/image-to-video を使って静止画像をアニメーション化するには、POST /v1/tasks の呼び出し 1 回とポーリング 1 回だけで済みます。これはプラットフォーム上のすべての生成モデルが使う非同期タスクのパターンと完全に同じです。テキストから動画へのエンドポイントとの違いは入力にあります。開始フレーム(image_url)と、それがどのように動くべきかを記述したプロンプトを提供する必要があります。本ガイドでは、そのままコピー&ペーストできる curl と Python のサンプル、このエンドポイントが実際に検証する入力フィールド、そしてテキストから動画へ移行してきた人がつまずく意外な点を紹介します。

必要なもの

  • hiapi の API キー。コンソールで作成し、Authorization: Bearer sk-<your-key> で送信します。ヘッダーの形式は認証ドキュメントを参照してください。
  • モデル ID は pixverse-v6/image-to-video です(スラッシュはそのまま残してください。これは ID の一部であり、URL パスではありません)。これは pixverse-v6/text-to-video とは異なるモデル ID です。
  • 最初のフレームとして公開アクセス可能な画像 URL。プラットフォームはサーバー側でこの画像を取得するため、localhost やプライベートバケットのリンクは使用できません。最初のフレームは API が GET でアクセスできる場所にホストしてください。
  • curl を使う場合は何もインストールする必要はありません。Python のサンプルでは、標準ライブラリと requests だけが必要です。

PixVerse V6 画像から動画へは、提供された静止画像を開始フレームとして、1~15 秒のクリップにアニメーション化します。これは統合された非同期タスク API を通じて動作します。タスクを送信し、結果をポーリングし、出力 URL が期限切れになる前にダウンロードします。

最小限の動作するリクエスト(curl)

タスクを POST /v1/tasks に送信します。image_url と prompt はどちらも必須です:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "pixverse-v6/image-to-video",
    "input": {
      "image_url": "https://cdn.example.com/your-first-frame.jpg",
      "prompt": "Slow push-in; the subject turns toward the camera and smiles, soft breeze in the hair",
      "duration": 5,
      "resolution": "720p"
    }
  }'

レスポンスはタスク ID を返します:

{ "code": 200, "data": { "taskId": "a1b2c3d4-...." } }

次に GET /v1/tasks/<taskId> を data.status が success になるまでポーリングします:

curl -s https://api.hiapi.ai/v1/tasks/a1b2c3d4-.... \
  -H "Authorization: Bearer sk-<your-key>"

成功時、完了した動画の URL は data.output[0].url にあります:

{
  "code": 200,
  "data": {
    "status": "success",
    "output": [{ "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1760000000 }]
  }
}

この出力 URL は一時的なものです。expireAt タイムスタンプが付いています。すぐに .mp4 をダウンロードして自分のバケットに保存してください。直接ホットリンクしないでください。

Python での同じ流れ

import time, requests

BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<your-key>", "Content-Type": "application/json"}

def create_task():
    payload = {
        "model": "pixverse-v6/image-to-video",
        "input": {
            "image_url": "https://cdn.example.com/your-first-frame.jpg",
            "prompt": "Slow push-in; the subject turns toward the camera and smiles",
            "duration": 5,
            "resolution": "720p",
        },
    }
    r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
    r.raise_for_status()
    data = r.json()
    task_id = (data.get("data") or {}).get("taskId")
    if not task_id:
        raise RuntimeError(f"create failed: {data}")  # 400s echo the exact bad field
    return task_id

def wait_for(task_id, timeout_s=600):
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        try:
            r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
            task = (r.json().get("data") or {})
        except requests.RequestException:
            time.sleep(5)          # one transient network blip should not abort the whole poll
            continue
        status = task.get("status")
        if status == "success":
            return task["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"task failed: {task.get('error')}")
        time.sleep(5)              # still pending — keep the SAME task_id, re-poll
    raise TimeoutError(task_id)

task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("saved out.mp4")

ポーリングループは success と fail を明示的にチェックし、それ以外のステータスでは待機を続けるため、タスクがレンダリング中に報告する中間ステータスのラベルが何であっても堅牢に処理できます。あるポーリングリクエストがエラーになった場合は、再送信せずに、保存した同じ task_id でスリープ後に再ポーリングしてください。再送信すると 2 回目のレンダリング費用が発生します。

pixverse-v6/image-to-video が実際に検証するパラメータ

以下は本番エンドポイントが実際に受け付けるフィールドです。無効な値を送って検証エラーを読み取り、1 つずつ確認したうえで、モデルドキュメントと照合しました:

フィールド 型 値 / 範囲 説明
image_url string 公開画像 URL 必須。最初のフレーム。単一の URL 文字列で、配列ではありません。
prompt string — 必須。そのフレームに加える動きを記述します。
duration integer 1–15、デフォルト 5 単位は秒。整数である必要があり、文字列は不可。
resolution string 360p、540p、720p、1080p 出力解像度。
negative_prompt string — 任意。避けたい内容。
seed integer — 任意。再現可能な結果を得るために再利用します。
style string anime、3d_animation、clay、comic、cyberpunk 任意のプリセットスタイル。
generate_audio boolean true / false、デフォルト false 任意。生成される音声トラック / 環境音のオン・オフ。

ここには aspect_ratio フィールドはありません。これは、目にしたことがあるかもしれないテキストから動画へのリクエストとの唯一の実質的な違いであり、覚えておく価値があります(下記参照)。

本番運用の注意点

  • aspect_ratio はありません——出力の形状は入力画像に従います。テキストから動画へのエンドポイントは aspect_ratio の列挙値を受け付けますが、このエンドポイントはそれを拒否します。最初のフレームを提供するため、クリップはそのフレームのサイズを継承します。9:16 の縦向きクリップが必要な場合は、送信前に image_url を 9:16 にトリミングまたはパディングしてください。比率を上書きするつまみはありません。
  • リクエスト構造は閉じています。上表以外のフィールドはすべて拒否され、invalid input: <root>: additional properties '<field>' not allowed というエラーになります。タイプミスや推測したフィールドは、黙って無視されるのではなく、送信時に明確に失敗します。first_frame、image、input_image、motion_mode、camera_movement などのフィールドはすべて拒否されます。開始画像は image_url に入れ、カメラの動きは prompt テキストに書きます。
  • duration は整数です。プラットフォーム上の一部の動画モデルは文字列("6")を受け付けますが、それとは異なります。"5" を送ると invalid input: duration: got string, want integer が返ります。範囲外の値は境界を直接報告します。例えば duration: maximum: got 999, want 15 です。
  • エラーは一度に 1 フィールドずつ返され、フラットなエンベロープ形式をとります:{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: image_url: missing required field \"image_url\""}。報告されたフィールドを修正して再送信してください。次の無効なフィールド(あれば)は次の呼び出しで明らかになります。
  • タスクの失敗でも HTTP 200 が返ります。失敗の情報はレスポンスボディ内に data.status: "fail" の形で含まれます。HTTP ステータスコードだけでなく、ステータスフィールドを確認してください。プラットフォームが取得できない画像 URL はよくある原因なので、まず最初のフレームが公開されていることを確認してください。
  • 秒単位で課金され、解像度と長さに応じて増加するため、1080p/15 秒のクリップは 540p/3 秒のクリップよりはるかに高価です。大量生成の前に料金ページで現在のレートを確認してください。

検証したこと(および検証していないこと)

pixverse-v6/image-to-video の本番 /v1/tasks エンドポイントに意図的に無効な値を送り、API 自身の検証レスポンスを読むことで入力契約を明らかにしました。これは読み取り専用のスキーマ探索であり、コールバックも設定せず、レンダリング費用も発生させていません。覚えておく価値のある具体的な発見:

  • image_url は必須の最初のフレームフィールドで、単一の文字列であり配列ではありません。数値を送ると image_url: got number, want string が返ります。省略すると missing required field "image_url" が返ります。推測されがちな代替フィールド(first_frame、image、input_image)はすべて未知の属性として拒否されます。
  • このエンドポイントは aspect_ratio を拒否します(additional properties 'aspect_ratio' not allowed)。ただし pixverse-v6/text-to-video では有効です。これが画像から動画へのリクエストがテキストから動画へのリクエストと異なって見える具体的な理由です。出力の形状はパラメータではなく、あなたのフレームによって決まります。
  • generate_audio は真のブールスイッチです(デフォルト false)。文字列を送ると generate_audio: got string, want boolean が返ります。音声が必要なら true に設定してください。強制的にオンまたはオフにされることはありません。

この探索ではクリップをレンダリングしていないため、本ガイドはモーションの品質や、モデルが入力フレームをどの程度忠実に保持するかについては主張しません。記録しているのは、このエンドポイントが強制する正確なリクエスト契約のみです。

関連コンテンツ

よくある質問

画像から動画へに aspect_ratio がないのはなぜですか?クリップは image_url のフレームで始まり、そのサイズを継承するためです。出力比率を制御するには、送信前に入力画像のサイズ変更やトリミングを行ってください。このエンドポイントは aspect_ratio を未知のフィールドとして拒否します。

image_url は複数の画像を受け付けますか?いいえ。このエンドポイントでは単一の URL 文字列であり、配列を渡すと検証エラーになります。最初のフレームのみを設定します。

duration の単位は秒ですか、フレームですか?秒です。1 から 15 までの任意の整数で、デフォルトは 5 です。整数である必要があり、文字列の "5" は拒否されます。

これはテキストから動画へのエンドポイントとどう違いますか?pixverse-v6/image-to-video は提供されたフレームをアニメーション化します(image_url + prompt、aspect_ratio なし)。pixverse-v6/text-to-video は別のモデル ID で、プロンプトのみから生成し、aspect_ratio を確かに受け付けます。動かしたい正確な開始スチル画像がすでにある場合は、画像から動画へを使用してください。

なぜ私のリクエストは「additional properties not allowed」で失敗するのですか?スキーマに存在しないフィールドを送信しています。入力は image_url、prompt、duration、resolution、negative_prompt、seed、style、generate_audio のみを受け付けます。

永続的なAIアーティファクトで開発を始める

APIキーを取得して、タスクベースの1つのAPIで画像・動画・音声モデルを呼び出せます。

APIドキュメントを読む