Search

Search HiAPI models, tools, and resources.

Back to blog
Tutorial

PixVerse V6 Text to Video API: a Working curl & Python Example

hiapipixverse-v6Video APITutorialTask API

Generating a clip with pixverse-v6/text-to-video on hiapi is one POST /v1/tasks call plus a poll — the same async task pattern every generation model on the platform uses. This guide is a copy-paste curl and Python example, the exact input fields the endpoint validates, and the sharp edges I hit while probing the live schema.

What you need

  • A hiapi API key. Create one in the dashboard and send it as Authorization: Bearer sk-<your-key>. See Authentication for the header format.
  • The model id is pixverse-v6/text-to-video (keep the slash — it is part of the id, not a URL path).
  • Nothing to install for curl. For the Python example, only the standard library plus requests.

PixVerse V6 text-to-video turns a text prompt into a 1–15 second clip at 360p–1080p. It runs through the unified task API — you submit a job, poll for the result, then download the output URL before it expires.

The minimal working request (curl)

Submit the job to POST /v1/tasks:

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/text-to-video",
    "input": {
      "prompt": "A neon-lit drummer playing on a rooftop at night, rain, cinematic",
      "aspect_ratio": "16:9",
      "duration": 5,
      "resolution": "720p"
    }
  }'

The response hands you a task id:

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

Then poll GET /v1/tasks/<taskId> until data.status is success:

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

On success the finished video URL is at data.output[0].url:

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

That output URL is temporary — it carries an expireAt timestamp. Download the .mp4 and store it on your own bucket right away; do not hotlink it.

The same flow in 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/text-to-video",
        "input": {
            "prompt": "A neon-lit drummer playing on a rooftop at night, rain, cinematic",
            "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"create failed: {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)          # 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")

Note the poll loop checks for success and fail explicitly and keeps waiting on anything else — that way it is robust to whatever intermediate status label the job reports while rendering. If a single poll request errors out, sleep and re-poll the same saved task_id rather than resubmitting (resubmitting bills a second render).

Parameters pixverse-v6/text-to-video actually validates

These are the fields the live endpoint accepts. I confirmed each by sending an invalid value and reading the validation error, then cross-checked against the model docs:

FieldTypeValues / rangeNotes
promptstring—Required.
aspect_ratiostring16:9, 4:3, 1:1, 3:4, 9:16, 2:3, 3:2, 21:9Note it accepts 21:9 (ultrawide) and 2:3/3:2.
durationinteger1–15, default 5Seconds. Must be an integer, not a string.
resolutionstring360p, 540p, 720p, 1080pOutput resolution.
negative_promptstring—Optional; what to steer away from.
seedinteger—Optional; reuse for reproducibility.
stylestringanime, 3d_animation, clay, comic, cyberpunkOptional preset look.

Production notes

  • The schema is closed. Any field that is not in the table above is rejected with invalid input: <root>: additional properties '<field>' not allowed. That is a feature: a typo'd or guessed field fails loudly at submit time instead of being silently ignored.
  • duration is an integer, unlike some other video models on the platform that take a string ("6"). Sending "5" returns invalid input: duration: got string, want integer. Out-of-range values report the bound directly, e.g. duration: maximum: got 999, want 15.
  • Errors come back one field at a time, in a flat envelope: {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}. Fix the reported field and resubmit; the next invalid field (if any) surfaces on the following call.
  • A failed job still returns HTTP 200. The failure lives in the body as data.status: "fail" — check the status field, not just the HTTP code.
  • Pricing is per second and scales with resolution and duration, so a 1080p/15s clip costs much more than a 540p/3s one. Check the current rate on the pricing page before you batch-generate.

What I verified (and what I didn't)

I mapped the input contract by sending deliberately invalid values to the live /v1/tasks endpoint and reading the API's own validation responses — a read-only schema probe, no callback attached, no render billed. Concrete findings worth keeping:

  • There is no sound / audio input field — sound is rejected as an unknown property. PixVerse V6 produces audio natively on some clips, but you cannot toggle or configure it from the request.
  • There is no motion_mode, camera_movement, quality, mode, fast, or prompt_optimizer field either — all rejected as additional properties. If you are porting a prompt from PixVerse's own app, drop those knobs; the hiapi task input is prompt + the seven fields above.

I did not render a clip as part of this probe, so this guide makes no claim about output quality — it documents the exact request contract the endpoint enforces.

FAQ

Is duration in seconds or frames? Seconds — any integer from 1 to 15, default 5.

Can I get audio? The model can produce audio natively on some generations, but the API exposes no audio parameter, so it is not something you request or configure.

What's the difference between this and the image-to-video endpoint? This endpoint (pixverse-v6/text-to-video) starts from a text prompt only. The image-to-video variant is a separate model id that takes a starting image; use it when you want to animate an existing frame instead of generating from scratch.

Why did my request fail with "additional properties not allowed"? You sent a field that is not in the schema. The input accepts only prompt, aspect_ratio, duration, resolution, negative_prompt, seed, and style.

Generate it with HiAPI

Choose a model, enter your prompt, and see the result.

HiAPI Blog

Related articles

HiAPI

Generate it with HiAPI

Start generating