
Short-form is a volume game. TikTok, Reels, and Shorts all reward accounts that post daily, and the biggest production bottleneck is usually B-roll: the 3–8 second vertical clips that carry a hook, a product beat, or a satisfying loop. HappyHorse 1.1 text-to-video is unusually well suited to this because it generates native audio in the same call — no separate scoring or foley pass — and supports 9:16 vertical output directly, so nothing gets cropped in post.
This guide is the end-to-end workflow: prompt patterns tuned for short-form, the async task lifecycle, a batch-production script that renders a week of clips in one run, and the cost math per platform. Every clip embedded below was generated with the exact request shown next to it — audio on, straight from the API.
Prerequisites. You need a hiapi key (
Authorization: Bearer sk-…). If you haven't called/v1/tasksbefore, skim the async API create doc or the happyhorse-1.1 curl + Python tutorial first — this article builds on it and focuses on the short-form workflow.
Three properties matter for the format:
aspect_ratio accepts 9:16 (plus 16:9, 1:1, 4:5, 21:9, 9:21 and more), so you render vertical natively instead of cropping a landscape master and losing composition.duration takes any integer from 3 to 15 — exactly the short-form envelope. Hooks are 3s, product beats are 4–6s, and a full micro-story fits in 12–15s.The input schema is deliberately small. Only prompt is required; the useful knobs are:
| Field | Values | Short-form default |
|---|---|---|
prompt | string (required) | see patterns below |
aspect_ratio | 16:9, 9:16, 3:4, 4:3, 4:5, 5:4, 1:1, 9:21, 21:9 | 9:16 |
resolution | 720p, 1080p | 720p for drafts, 1080p for hero posts |
duration | integer 3–15 (seconds) | 3–5 |
Two things it does not accept, so you don't burn a request finding out: there is no audio toggle (audio is always on) and no seed. Sending either returns a 400 validation error.
These are the three formats that dominate short-form feeds, each generated in one API call. The prompts follow a repeatable pattern you can adapt: format tag → subject and action → framing → lighting → audio cue.
{
"model": "happyhorse-1.1/text-to-video",
"input": {
"prompt": "Vertical short-form test: a barista pours latte art in a bright cafe, phone-style vertical framing, natural audio of milk steaming and cafe chatter.",
"duration": 4,
"resolution": "720p",
"aspect_ratio": "9:16"
}
}
Note the audio cue at the end of the prompt ("milk steaming and cafe chatter"). Naming the sounds you want is the single highest-leverage trick with this model — unprompted, it still generates audio, but describing it gets you a usable ambient track.
{
"model": "happyhorse-1.1/text-to-video",
"input": {
"prompt": "Product-drop teaser, vertical 9:16: a chunky retro running sneaker in cream and burnt orange rotates slowly on a matte black turntable, hard rim lighting carving its silhouette, fine dust particles drifting in the beam, dark studio background with plenty of empty space above for a title overlay. Punchy, cinematic. Native audio: a low bass hum and one soft whoosh as the shoe completes its turn.",
"duration": 3,
"resolution": "720p",
"aspect_ratio": "9:16"
}
}
Two short-form-specific moves here. First, "plenty of empty space above for a title overlay" — you're going to put text on this clip in your editor, so ask the model to leave negative space instead of fighting your caption for the frame. Second, the audio is designed, not ambient: one bass hum plus one whoosh timed to the motion beat, which is exactly what product teasers use.
{
"model": "happyhorse-1.1/text-to-video",
"input": {
"prompt": "Oddly-satisfying macro, vertical 9:16: a sharp palette knife slices cleanly through a block of pastel mint kinetic sand on a white table, the cut face crumbling in slow motion, grains cascading, soft even studio light, extreme close-up filling the frame. Native audio: the dry granular crunch of the cut, no music.",
"duration": 3,
"resolution": "720p",
"aspect_ratio": "9:16"
}
}
"No music" matters: for ASMR-adjacent content the model should spend its audio budget on the foley (the granular crunch), and saying so explicitly keeps it from adding a generic score.
Distilled from the clips above and the runs behind them:
Native audio: <the 1–3 sounds you want>. Ambient beds ("cafe chatter"), foley ("dry granular crunch"), or designed one-shots ("a low bass hum and one soft whoosh") all work.Every generation is an async task: POST /v1/tasks returns a taskId immediately, you poll GET /v1/tasks/:id until status is success, then download output[0].url. A 4-second 720p clip typically renders in about 1–3 minutes.
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "happyhorse-1.1/text-to-video",
"input": {
"prompt": "Vertical short-form test: a barista pours latte art in a bright cafe, phone-style vertical framing, natural audio of milk steaming and cafe chatter.",
"duration": 4,
"resolution": "720p",
"aspect_ratio": "9:16"
}
}'
# → {"code":200,"data":{"taskId":"tk-hiapi-…"},"message":"success"}
One operational rule that bites people: the output URL expires. The response's output[0].url carries an expireAt — download the mp4 and put it in your own storage as soon as the task succeeds. Don't write the hot URL into a CMS or a scheduling tool.
The task API shines when you submit in parallel. Because create returns instantly, the right pattern for volume is submit everything first, then poll everything — five clips render in roughly the wall-clock time of one.
import os, time, requests
API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
BATCH = [
("mon-coffee", "Vertical short-form: pour-over coffee blooming in slow motion, steam curling, warm morning light. Native audio: water trickling, soft cafe ambience.", 4),
("tue-sneaker", "Product-drop teaser, vertical 9:16: a neon runner sneaker splashes down into shallow water, droplets frozen mid-air, dark background. Native audio: one deep splash.", 3),
("wed-sand", "Oddly-satisfying macro, vertical 9:16: a cube of lavender kinetic sand sliced by a thin wire, the face crumbling. Native audio: dry granular crunch, no music.", 3),
("thu-city", "Vertical short-form: rain-slicked neon street at night, umbrellas passing, reflections rippling. Native audio: rain and distant traffic.", 5),
("fri-dessert", "Vertical short-form macro: a spoon cracks the caramel crust of a crème brûlée, custard yielding underneath. Native audio: the crisp crack, then silence.", 3),
]
def submit(prompt, duration):
r = requests.post(API, headers=HEADERS, json={
"model": "happyhorse-1.1/text-to-video",
"input": {"prompt": prompt, "duration": duration,
"resolution": "720p", "aspect_ratio": "9:16"},
}, timeout=60)
return r.json()["data"]["taskId"]
# 1) submit everything up front
tasks = {key: submit(p, d) for key, p, d in BATCH}
# 2) poll until all terminal
while tasks:
time.sleep(10)
for key, tid in list(tasks.items()):
t = requests.get(f"{API}/{tid}", headers=HEADERS, timeout=30).json()["data"]
if t["status"] == "success":
url = t["output"][0]["url"] # expires — download now
open(f"{key}.mp4", "wb").write(requests.get(url, timeout=180).content)
print(f"done: {key}.mp4")
del tasks[key]
elif t["status"] == "fail":
print(f"FAILED {key}: {t.get('error')}")
del tasks[key]
Production notes from running this shape of script at volume:
{key, prompt, taskId, local_path} to a JSON file as you go, and on restart skip keys whose mp4 already exists. Batch jobs get interrupted; resumability is free if you plan for it.Billing is per second of output video (pricing page): $0.16/s at 720p, $0.21/s at 1080p, regardless of aspect ratio. Duration is the whole cost lever, which makes short-form the cheapest place to use the model:
| Clip | Spec | Cost |
|---|---|---|
| Hook / satisfying loop | 3s · 720p | $0.48 |
| Standard B-roll beat | 4s · 720p | $0.64 |
| Product teaser | 5s · 720p | $0.80 |
| Hero post | 5s · 1080p | $1.05 |
| Daily posting, 30 × 4s drafts/month | 720p | ~$19.20 |
A practical two-tier routine: iterate prompts at 3s/720p (about half a dollar per try), and re-render only the winners at 1080p for posting. The prompt transfers between resolutions cleanly, so you're not re-doing creative work — just paying for pixels once you know the clip earns them.
The model hands you a finished vertical clip with audio; what's left is packaging:
duration up to 15 covers a full micro-story in one call if you'd rather not edit.If your series is anchored on a brand asset — a real product shot, a mascot, a face — pair this workflow with happyhorse-1.1 image-to-video: generate or photograph the key frame once, then drive motion from it so the subject stays identical across every post.
The fastest path: grab a key, copy the barista request from this page, and you'll have your first vertical clip with audio in a couple of minutes. The happyhorse-1.1 text-to-video model page has the live parameter reference and pricing, and the quickstart covers auth if this is your first hiapi call. Render three drafts, keep the best one, and you've got tomorrow's post for less than the price of a coffee.