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:
| Field | Type | Values / range | Notes |
|---|---|---|---|
prompt | string | — | Required. |
aspect_ratio | string | 16:9, 4:3, 1:1, 3:4, 9:16, 2:3, 3:2, 21:9 | Note it accepts 21:9 (ultrawide) and 2:3/3:2. |
duration | integer | 1–15, default 5 | Seconds. Must be an integer, not a string. |
resolution | string | 360p, 540p, 720p, 1080p | Output resolution. |
negative_prompt | string | — | Optional; what to steer away from. |
seed | integer | — | Optional; reuse for reproducibility. |
style | string | anime, 3d_animation, clay, comic, cyberpunk | Optional 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. durationis an integer, unlike some other video models on the platform that take a string ("6"). Sending"5"returnsinvalid 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/audioinput field —soundis 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, orprompt_optimizerfield either — all rejected as additional properties. If you are porting a prompt from PixVerse's own app, drop those knobs; the hiapi task input isprompt+ 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.
Related
- PixVerse V6 Text to Video — model page
- PixVerse V6 Text to Video — API docs
- Create Task and Get Task Detail reference
- Quick Start and Authentication
- Pricing
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.





