HiAPI
ブログ

チュートリアル

PixVerse V6 テキスト→動画 API:実際に動作する curl と Python のサンプル

Oct 20, 2026
PixVerse V6 テキスト→動画 API:実際に動作する curl と Python のサンプル
モデル
pixverse-v6

pixverse-v6/text-to-video を使って hiapi で動画を生成するのは、要するに POST /v1/tasks を1回呼び出してポーリングを1ラウンド回すだけです。これはプラットフォーム上のすべての生成系モデルが使う非同期タスクパターンとまったく同じです。本記事では、そのままコピーできる curl と Python のサンプル、エンドポイントが実際に検証する入力フィールド、そして私が実際に1回生成を完走させたときに記録したタスクのライフサイクルとハマりどころを紹介します。

開始前に必要なもの

  • hiapi API key。コンソールで作成し、リクエストヘッダー Authorization: Bearer sk-<あなたの key> で付与します。ヘッダー形式は認証ドキュメントを参照してください。
  • model id は pixverse-v6/text-to-video です。途中のスラッシュを保持してください——これは id の一部であり、URL パスではありません。
  • curl は何もインストール不要です。Python のサンプルは標準ライブラリと requests だけを使います。

PixVerse V6 テキスト→動画は、テキストプロンプトから 1〜15 秒、360p〜1080p の動画クリップを生成します。統一された非同期タスクインターフェースを使います:タスクを送信 → 結果をポーリング → 出力 URL が期限切れになる前に動画をダウンロードします。

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

タスクを POST /v1/tasks に送信します:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<あなたの key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "pixverse-v6/text-to-video",
    "input": {
      "prompt": "朝日の光の中、赤いキツネが新雪を小走りで駆け抜ける、映画のような質感、スローモーション",
      "aspect_ratio": "16:9",
      "duration": 5,
      "resolution": "720p"
    }
  }'

レスポンスからタスク id を取得します:

{ "code": 200, "data": { "taskId": "tk-hiapi-...." }, "message": "success" }

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

curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-.... \
  -H "Authorization: Bearer sk-<あなたの key>"

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

{
  "code": 200,
  "data": {
    "status": "success",
    "storage": "temp",
    "output": [
      { "type": "video", "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1793036664 }
    ]
  },
  "message": "success"
}

この出力 URL は一時的なものです——expireAt タイムスタンプが付きます(実測では生成後 7 日間)。すぐに .mp4 をダウンロードして自分のオブジェクトストレージに保存してください。このアドレスを直接ホットリンクしないでください。

同じフロー(Python)

import time, requests

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

def create_task():
    payload = {
        "model": "pixverse-v6/text-to-video",
        "input": {
            "prompt": "朝日の光の中、赤いキツネが新雪を小走りで駆け抜ける、映画のような質感、スローモーション",
            "aspect_ratio": "16:9",
            "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"作成失敗: {data}")
    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)          # 1回のネットワーク揺らぎでポーリング全体を中止すべきではない
            continue
        status = task.get("status")
        if status == "success":
            return task["output"][0]["url"]
        if status == "fail":
            raise RuntimeError(f"タスク失敗: {task.get('error')}")
        time.sleep(5)              # まだキュー待ち/レンダリング中——同じ task_id でポーリングを続ける
    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("out.mp4 を保存しました")

ポーリングループは success と fail の2つの終端状態だけを判定し、それ以外の状態はすべて待ち続けます——これにより、レンダリング途中で handling と報告されても archiving と報告されても、コードが誤判定することはありません。重要な点:あるポーリングリクエスト自体がエラーになった場合は、少し待ってから保存済みの同じ task_id で再問い合わせし、タスクを再送信しないでください——再送信すると再度レンダリングされ、再度課金されます。

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

以下はエンドポイントが実際に受け付けるフィールドです。それぞれに不正な値を送って返ってくる検証エラーを読み、モデルドキュメントと突き合わせて確認しました:

フィールド 型 値 / 範囲 デフォルト値 説明
prompt string 1〜2048 バイト UTF-8(漢字1文字 = 3 バイト、約 682 文字) — 必須。
aspect_ratio enum 16:9、4:3、1:1、3:4、9:16、2:3、3:2、21:9 16:9 21:9(ウルトラワイド)と 2:3/3:2 をサポートしている点に注意。
duration integer 1〜15 5 単位は秒、必ず整数で、文字列は不可。
resolution enum 360p、540p、720p、1080p 720p 出力解像度。
generate_audio boolean true / false false BGM、効果音、セリフも同時に生成するかどうか。デフォルトはオフで、音声が必要なら明示的にオンにする。
negative_prompt string 最大 2048 バイト UTF-8 — オプション。避けたい内容。
seed integer 任意の整数 — オプション。同じ seed + 同じ prompt で同じ結果を再現できる。
style enum anime、3d_animation、clay、comic、cyberpunk なし オプションのスタイルプリセット。空のままにすると自然な画風を保つ。

ポーリングではなくコールバックを使う場合、input と同じ階層に callback オブジェクトを追加できます:url(HTTPS コールバックアドレス)+ when(現在は final のみ、つまりタスク終端状態でコールバック)。

本番環境での書き方

  • これはクローズドな schema です。 上表にないフィールドはすべて即座に拒否され、invalid input: <root>: additional properties '<フィールド>' not allowed が返ります。これはむしろ良いことです:タイポや想像上のフィールドは、黙って無視されるのではなく送信時に明確に失敗します。
  • duration は整数であり、プラットフォーム上の一部の動画モデルのように文字列("6")を受け取るのとは異なります。"5" を送ると invalid input: duration: got string, want integer が返ります。範囲外の値は境界を直接教えてくれます。例えば duration: maximum: got 999, want 15、duration: minimum: got 0, want 1。
  • エラーは一度に1フィールドだけ報告され、envelope はフラットです:{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}。報告されたフィールドを修正して再送すると、次の不正フィールド(あれば)が次の呼び出しで現れます。
  • タスク失敗時も HTTP は 200 のままです。 失敗情報はレスポンスボディの data.status: "fail" にあり、判定すべきはこの status フィールドであり、HTTP ステータスコードではありません。
  • ポーリングかコールバックか? 軽量なスクリプトにはポーリングが最も簡単です。スケールさせたい、ずっと接続を張り続けたくない場合は callback を使います。どちらでも、output[0].url を取得したらすぐにダウンロードしてください——URL には expireAt があり、期限切れ後は 404 になります。

実測記録:実際に1回実行した

本記事は読み取り専用のプローブだけではありません——実際のリクエストで完全なライフサイクルを1回走らせ、記録は以下の通りです:

  • 作成:上記の 720p / 5 秒 / 16:9 のリクエストを送ると、すぐに {"code":200,"data":{"taskId":"tk-hiapi-01M5AM..."},"message":"success"} が返りました。taskId は tk-hiapi- プレフィックスの文字列であり、UUID ではない点に注意。
  • ポーリング:GET /v1/tasks/<id> の data.status は handling → archiving → success と順に遷移し、5 秒の動画1本が作成から完了まで約 74 秒でした。
  • 出力:終端状態では data.output[0] は {"type":"video","url":"https://temp.hiapi.ai/....mp4","expireAt":...,"artifactId":"...","storage":"temp"} でした。expireAt から作成時刻を引くとちょうど 604800 秒、つまり 7 日間です。
  • 成果物:その出力 URL に HEAD を送ると、content-type: video/mp4、サイズ約 2.2 MB が返り、有効な mp4 ファイルであることを確認しました。

音声に関する1つの訂正は特筆に値します:私は不正な値でいくつかの隣接フィールド名をプローブしました——generate_audio は got string, want boolean を返し(つまりこれが有効なブールフィールドであることを示す)、一方 sound、audio はどちらも additional properties not allowed を返しました(存在しない)。つまり、音声は generate_audio というスイッチで制御され、デフォルトは false です。料金ページにも「Sound On / Sound Off」の2段階があります。今回の実測では generate_audio をオンにしなかったため、生成されたのは無音の動画でした。

私は画質について主観的な評価はしていません(今回はリクエスト契約、タスクライフサイクル、成果物が有効な mp4 であることだけを確認しました)。この部分はご自身のプロンプトで実際に生成して判断してください。

料金の計算方法

pixverse-v6/text-to-video は秒単位で課金されます(課金ファクターは duration)。長さが長いほど高くなります。解像度が高いほど、また generate_audio をオンにして「Sound On」段階にすると、1秒あたりの単価が高くなります。具体的な毎秒レートは料金ページのリアルタイムデータを基準にしてください。バッチ生成の前に一度確認しましょう。

関連リンク

よくある質問

duration は秒ですか、フレームですか? 秒です——1 から 15 までの任意の整数で、デフォルトは 5。

音声付きの動画を生成できますか? できます。generate_audio を true に設定すると、モデルは BGM、効果音、セリフも一緒に生成します。デフォルトは false(無音)です。音声を有効にするとより高い課金段階になり、詳細は料金ページを参照してください。

プロンプトはどのくらいの長さまで書けますか? 上限は 2048 バイト UTF-8 です。中国語の1文字は 3 バイトなので、約 682 文字が上限です。

画像→動画との違いは何ですか? このエンドポイント(pixverse-v6/text-to-video)はテキストプロンプトからのみ開始します。画像→動画は別の model id で、開始画像を受け取ってそれを動かします——既存の画面を動かしたい、ゼロから生成したくない場合はそれを使ってください。

なぜ私のリクエストは "additional properties not allowed" を返すのですか? schema にないフィールドを渡したからです。入力は prompt、aspect_ratio、duration、resolution、generate_audio、negative_prompt、seed、style のこれらのみを受け付けます。

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

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

APIドキュメントを読む