Search

Search HiAPI models, tools, and resources.

Back to blog
Tutorial

How to Use wan3.0-video via the hiapi API: curl, Python, and a Working Request

hiapivideo-generationwanapi-tutorialhiapi

wan3.0-video runs through hiapi's shared async task endpoint, the same POST /v1/tasks / GET /v1/tasks/{taskId} pair used by every image and video model on the platform. This guide is a minimal, verified path from an API key to a downloadable .mp4: a working curl request, a poll loop, a Python version, the full input schema (with real error responses), and the production details you need before you wire this into a pipeline.

What you need

  • A hiapi account and an API key from the dashboard.
  • Nothing model-specific to install — wan3.0-video uses the same unified task API as every other model.
  • Just a text prompt. hiapi's pricing table files wan3.0-video under "reference-to-video," but that's a billing category, not a requirement — a plain prompt with no reference image or video works standalone. Reference media (reference_image_urls / reference_video_urls, covered below) is optional, for when you want to steer the output from an existing image or clip.

Minimal working example

1. Create the task

curl -s https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan3.0-video",
    "input": {
      "prompt": "A steaming cup of coffee on a wooden table, soft morning light, gentle steam rising",
      "duration": 2,
      "resolution": "480P"
    }
  }'

You get a taskId back immediately; generation keeps running in the background:

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

2. Poll for the result

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

Keep polling every few seconds until data.status is success or fail. Here's the actual terminal response from the request above — wan3.0-video moves through handling, briefly archiving, then success; this particular 2-second 480P clip took about 4.5 minutes end to end:

{
  "code": 200,
  "message": "success",
  "data": {
    "taskId": "tk-hiapi-01M1QP6MVQ4DKWEKH6Q65RG5SQ",
    "status": "success",
    "model": "wan3.0-video",
    "storage": "temp",
    "created": 1788575175,
    "completed": 1788575455,
    "output": [
      {
        "type": "video",
        "url": "https://temp.hiapi.ai/7c6ttvrbpt/01M1QP6MVQ4DKWEKH6Q65RG5SQ-0.mp4",
        "artifactId": "116211",
        "expireAt": 1789180255
      }
    ]
  }
}

data.output[0].url is your video. With the default storage: "temp", that URL expires roughly 7 days after creation (expireAt is a Unix timestamp) — download it or set "storage": "persistent" on creation if you need it to stick around longer.

3. Python version

import time
import requests

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

resp = requests.post(f"{BASE}/tasks", headers=headers, json={
    "model": "wan3.0-video",
    "input": {
        "prompt": "A steaming cup of coffee on a wooden table, soft morning light, gentle steam rising",
        "duration": 2,
        "resolution": "480P",
    },
})
task_id = resp.json()["data"]["taskId"]

while True:
    detail = requests.get(f"{BASE}/tasks/{task_id}", headers=headers).json()["data"]
    if detail["status"] in ("success", "fail"):
        break
    time.sleep(5)

if detail["status"] == "success":
    print(detail["output"][0]["url"])
else:
    print("generation failed:", detail)

Full input schema

FieldTypeRequiredNotes
promptstringyesText description of the video.
durationintegernoSeconds, 2–30.
aspect_ratioenumnoadaptive, 16:9, 4:3, 1:1, 3:4, 9:16.
resolutionenumno480P, 720P, 1080P.
audiobooleannoGenerate synchronized audio alongside the video.
reference_image_urlsarray of URL stringsnoSwitches to image-to-video / reference-image mode.
reference_video_urlsarray of URL stringsnoSwitches to video-to-video / reference mode.

A field named image_urls does not exist on this model — if you're porting code from another hiapi video model, double-check the field name; wan3.0-video rejects it as an unknown property (see below).

Three real 400 responses from probing this schema directly, so you can recognize them if you hit them yourself:

Missing prompt:

{"code":400,"data":null,"error_code":"INVALID_REQUEST","message":"invalid input: prompt: missing required field \"prompt\""}

Invalid resolution value:

{"code":400,"data":null,"error_code":"INVALID_REQUEST","message":"invalid input: resolution: value must be one of '480P', '720P', '1080P'"}

Unknown field (e.g. a negative_prompt this model doesn't accept):

{"code":400,"data":null,"error_code":"INVALID_REQUEST","message":"invalid input: <root>: additional properties 'negative_prompt' not allowed"}

Pricing is per second of output and scales with resolution (higher resolution costs more per second); check current rates on pricing before estimating a batch run.

Production notes

  • Callbacks instead of polling. Add a top-level callback object to skip the poll loop entirely: "callback": {"url": "https://your-app.com/hiapi/callback", "when": "final"}. hiapi POSTs to that URL once the task reaches success or fail — when currently only supports final. Don't put callback inside input; it's rejected there.
  • Idempotency. Pass an Idempotency-Key header (up to 255 bytes) on creation. A retried request with the same key under the same account returns the original taskId instead of creating a second (and separately billed) task — useful when a client-side timeout makes you unsure whether your first request actually landed.
  • Storage and expiry. Outputs default to "storage": "temp" (~7 days). Set "storage": "persistent" on creation, or promote an existing output afterward, if you need the file to outlive that window — see the async task docs for both options.
  • Error handling. A bad or missing API key fails synchronously with 401 before any task is created:
    {"error":{"code":"permission_denied","message":"This API key is invalid. Check that it is correct or use another API key and try again. If the issue persists, contact support with request ID: ...","type":"hiapi_error","request_id":"..."}}
    
    Malformed input fails synchronously with 400 (examples above); insufficient balance fails with 402. Once a task is handling, failures show up as status: "fail" on the polled/callback response rather than as an HTTP error — always check data.status, not just the HTTP code.

FAQ

Does wan3.0-video need a reference image or video? No. It's priced under a "reference-to-video" category, but a text-only prompt generates a video on its own. Reference media is optional.

What's the correct field for image-to-video with this model? reference_image_urls, an array of publicly reachable image URLs. image_urls is not a valid field on wan3.0-video and will 400 with an "additional properties" error.

How long does generation take? Expect roughly a few minutes for a short clip at 480P; longer durations and higher resolutions take longer. Poll every few seconds, or use a callback to avoid polling entirely.

Can I get 9:16 output for short-form video? Yes — set aspect_ratio to 9:16. The enum also covers 16:9, 4:3, 1:1, 3:4, and adaptive.

How do I keep the output file longer than 7 days? Set "storage": "persistent" when you create the task, or promote the temp output afterward — see the storage section in the async task docs.

What happens if my API key is wrong? The request fails immediately with HTTP 401 and error.code: "permission_denied" — no task is created and nothing is billed.

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