creatify-boreal is a video model on hiapi that returns a finished clip with speech and sound already mixed in. One model id covers three starting points: a prompt only, a prompt plus a reference image, or a prompt plus your own narration audio. This guide shows the request, the polling loop, and what a real generation looked like when I ran it.
You need an API key from the hiapi dashboard. Every call goes through the unified task endpoint, POST /v1/tasks.
Input fields
These were checked against the live model page and by sending deliberately invalid values to /v1/tasks, which return a 400 and are not billed.
| Field | Required | Accepted values |
|---|---|---|
prompt | yes | text, up to 5000 characters |
image_url | no | JPG/PNG/WebP, 10 MB; sets subject and composition |
audio_url | no | MP3/WAV/M4A, 15 MB; only the first duration seconds are used |
negative_prompt | no | up to 2000 characters |
resolution | no | 720p, 1080p, 2k |
aspect_ratio | no | auto, 16:9, 9:16, 1:1, 4:3, 3:4 |
duration | no | whole seconds, 1 to 20 |
The three modes are not separate model ids. Leave out image_url and audio_url for text-to-video, add image_url for image-to-video, and add audio_url (usually with an image) to have the presenter follow your narration.
Minimal working request
curl -X POST 'https://api.hiapi.ai/v1/tasks' \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{
"model": "creatify-boreal",
"input": {
"prompt": "Vertical selfie-style UGC video: a young woman in a bright bedroom holds up a pastel lip balm and says to camera: \"Okay, this is the only lip balm that survived my winter.\" Natural room tone.",
"resolution": "720p",
"aspect_ratio": "9:16",
"duration": 4
}
}'
The response gives you a task id:
{"code":200,"data":{"taskId":"tk-hiapi-01M5MJC8NG8E1E0XN9NEJRDBQH"},"message":"success"}
Python: submit and poll
import os, time, requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
def create(payload: dict) -> str:
r = requests.post(BASE, headers=HEADERS, json=payload, timeout=30)
r.raise_for_status()
return r.json()["data"]["taskId"]
def wait(task_id: str, every: int = 10, limit: int = 900) -> dict:
start = time.time()
while time.time() - start < limit:
try:
d = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
except (requests.RequestException, ValueError):
time.sleep(every) # transient network error: keep polling the same id
continue
if d["status"] == "success":
return d
if d["status"] == "fail":
raise RuntimeError(d.get("error"))
time.sleep(every)
raise TimeoutError(task_id)
task_id = create({
"model": "creatify-boreal",
"input": {
"prompt": "Vertical selfie-style UGC video: a young woman holds up a pastel lip balm and says to camera: \"Okay, this is the only lip balm that survived my winter.\" Natural room tone.",
"resolution": "720p",
"aspect_ratio": "9:16",
"duration": 4,
},
})
result = wait(task_id)
print(result["output"][0]["url"])
Status moves through handling, then archiving, then success. The video URL is in data.output[0].url.
Image and audio modes
Image-to-video adds one field:
{"model": "creatify-boreal",
"input": {"prompt": "The woman smiles and talks to the camera in her kitchen: \"I swapped my coffee for this oat latte mix.\" Natural kitchen ambience.",
"image_url": "https://your-cdn.example/presenter.jpg",
"resolution": "720p", "duration": 8}}
Audio-driven adds audio_url pointing at your narration file. The model page describes it as narration kept in the video with lips following it, and says only the first duration seconds of the audio are used, so set duration to the length of the clip you want. The model page's audio examples pair the audio with a reference image; I did not run an image-plus-audio generation myself, so treat that combination as documented rather than verified here.
What a real run looked like
I ran the request above (text-only, 720p, 9:16, 4 seconds).
- Generation time: the task was in
handlingfor about 283 seconds, thenarchivingfor roughly 10 seconds. Plan for minutes, not seconds, even for a 4-second clip. Poll every 10 seconds or use a callback rather than a short timeout. - Output file: an MP4 at 720x1280, H.264 video at 24 fps plus an AAC audio track, 4.04 seconds long. Audio was present although the request had no audio field, which fits the model's native-sound design.
- Temporary URL: the output URL is on
temp.hiapi.aiand carries anexpireAtabout 7 days out. Download the file and store it yourself instead of linking it from a page. - Cost shape: billing is per second and depends on
resolution(see the pricing page), so the cheapest way to iterate on a prompt is 720p with a shortduration, then re-render the keeper at 1080p or 2k.
Gotchas I hit
- Bad values fail fast and free. Sending
aspect_ratio: "7:5",duration: 25orresolution: "4k"each returned HTTP 400INVALID_REQUESTwith a message naming the allowed values ('auto', '16:9', '9:16', '1:1', '4:3', '3:4', a maximum of 20, and'720p', '1080p', '2k'). Use that to validate your own form before submitting. - Bad media URLs fail later, at poll time. I submitted
audio_url: "https://example.com/a.mp3"(not a real audio file). The create call returned HTTP 200 with a task id, and about 15 seconds later the task ended withstatus: "fail"anderror.code: "INVALID_REQUEST". So a 200 on create does not mean your media was usable; always check the terminal status and readdata.error. In that case the failure is surfaced inside an HTTP 200 poll response, not as an HTTP error. - Failure is
status: "fail", not an HTTP status. The poll request itself returns 200, so checkdata.status.
Related pages
- Creatify Boreal model page: Playground, live pricing and example clips
- hiapi pricing
- hiapi docs
- How to use the OmniHuman 1.5 API: another presenter-style video model
- Ray 3.2 image-to-video API
- Wan 3.0 video API guide
FAQ
Do I need separate model ids for text, image and audio input?
No. All three use creatify-boreal; the fields you include in input decide the mode.
How long can a clip be? Whole seconds from 1 to 20. A value of 25 is rejected with HTTP 400.
Does the output include sound? Yes. The 4-second test clip had an AAC audio track even though no audio input was supplied.
Which resolutions are available?
720p, 1080p and 2k. Billing differs by resolution; check the pricing page.
How long should I wait? My 4-second 720p test took about five minutes end to end. Use polling with a generous limit or a callback.





