
Grok Imagine is xAI's video generation model, and HiAPI exposes its text-to-video variant through the same unified async endpoint as every other generative model on the platform: POST /v1/tasks. You send a prompt (plus optional duration, mode, aspect ratio, and resolution), get a taskId back immediately, and collect an .mp4 URL when the task finishes.
This guide is the shortest path to a working request: the exact input schema (verified against the live API, including the 400s you'll hit if you guess field names), a copy-paste curl flow, a small Python client with polling, and the callback pattern you'd use in production.
Goal: turn a text prompt into a 6–30 second video clip via grok-imagine/text-to-video, entirely over HTTP.
You need exactly one thing: a HiAPI API key. Create one in the HiAPI dashboard — a single key works across all models, so if you've already called an image model on HiAPI, the same key works here. Requests authenticate with a standard bearer header:
Authorization: Bearer sk-<your-key>
The task API validates input strictly per model — unknown fields are rejected with a 400, not silently ignored. Here is the full schema for grok-imagine/text-to-video:
| Field | Type | Required | Values | Default |
|---|---|---|---|---|
prompt | string | yes | up to 5000 chars, English works best | — |
duration | integer | no | 6–30 (seconds) | 6 |
mode | enum | no | fun, normal | normal |
aspect_ratio | enum | no | 2:3, 3:2, 1:1, 16:9, 9:16 | 2:3 |
resolution | enum | no | 480p, 720p | 480p |
Three things worth knowing up front:
mode is the "motion mode" knob. normal is balanced; fun produces more creative, exaggerated motion. If you've seen Grok Imagine's modes described elsewhere under other names, the API parameter is just mode — sending something like motion_mode gets you 400 additional properties 'motion_mode' not allowed.duration drives cost linearly. Grok Imagine bills per second of output, so a 30-second clip costs 5× a 6-second one. Current per-second rates are on the HiAPI pricing page.2:3 (portrait). If you want widescreen, pass 16:9 explicitly — this catches people migrating from models that default to landscape.Out-of-range values fail fast with a descriptive message, e.g. duration: 31 returns:
{"code":400,"data":null,"error_code":"INVALID_REQUEST","message":"invalid input: duration: maximum: got 31, want 30"}
Two calls: create the task, then poll it.
1. Create the task:
export HIAPI_API_KEY="sk-..."
curl -sS -X POST "https://api.hiapi.ai/v1/tasks" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine/text-to-video",
"input": {
"prompt": "A red fox trotting through fresh snow at dawn, low golden light, cinematic tracking shot",
"duration": 6,
"mode": "normal",
"aspect_ratio": "16:9",
"resolution": "720p"
}
}'
# => {"code":200,"data":{"taskId":"tk-hiapi-..."},"message":"success"}
Note the model id is the bare string grok-imagine/text-to-video — no provider prefix, no version suffix.
2. Poll until terminal:
TASK_ID="tk-hiapi-..."
curl -sS "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer $HIAPI_API_KEY"
# while .data.status is "handling", sleep a few seconds and retry.
# On success:
# {
# "code": 200,
# "data": {
# "status": "success",
# "model": "grok-imagine/text-to-video",
# "output": [
# {"type": "video", "url": "https://temp.hiapi.ai/.../...-0.mp4", "expireAt": 1783300000}
# ],
# ...
# }
# }
The .mp4 URL is temporary — expireAt is a Unix timestamp roughly a week out. Download the bytes as soon as the task succeeds and persist them yourself; don't hotlink temp.hiapi.ai URLs from anything user-facing. (If you've ever hit a dead output link, this is why — see hiapi output URL expired: download before it expires.)
The same flow as a reusable script — create, poll with a deadline, download:
# pip install requests
import os
import time
import requests
API_BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
}
def create_task(prompt: str, duration: int = 6, mode: str = "normal",
aspect_ratio: str = "16:9", resolution: str = "720p") -> str:
resp = requests.post(API_BASE, headers=HEADERS, json={
"model": "grok-imagine/text-to-video",
"input": {
"prompt": prompt,
"duration": duration, # 6-30, billed per second
"mode": mode, # "normal" | "fun"
"aspect_ratio": aspect_ratio, # "2:3" | "3:2" | "1:1" | "16:9" | "9:16"
"resolution": resolution, # "480p" | "720p"
},
}, timeout=60)
data = resp.json()
task_id = (data.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"create failed: {data}")
return task_id
def wait_task(task_id: str, timeout_s: int = 900, poll_interval: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
resp = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30)
task = resp.json().get("data") or {}
status = task.get("status")
if status == "success":
return task
if status == "fail":
err = task.get("error") or {}
raise RuntimeError(f"task failed: {err.get('code')} {err.get('message')}")
time.sleep(poll_interval)
raise TimeoutError(f"task {task_id} not done after {timeout_s}s")
if __name__ == "__main__":
task_id = create_task(
"A red fox trotting through fresh snow at dawn, low golden light, "
"cinematic tracking shot",
duration=6,
)
print("task:", task_id)
task = wait_task(task_id)
url = task["output"][0]["url"]
video = requests.get(url, timeout=120).content # expires — persist now
with open("fox.mp4", "wb") as f:
f.write(video)
print(f"saved fox.mp4 ({len(video)} bytes)")
A 6-second clip typically finishes well within the 15-minute deadline above; longer durations take proportionally longer, so keep the generous timeout for 30-second jobs.
Callback instead of polling. For anything beyond a script, pass a top-level callback object at create time and HiAPI will POST the terminal task state to your endpoint — no polling loop to babysit:
{
"model": "grok-imagine/text-to-video",
"input": {"prompt": "...", "duration": 12},
"callback": {"url": "https://your-domain.com/hiapi/callback", "when": "final"}
}
when only accepts "final" (you get one POST when the task reaches success or fail, not incremental progress). Rule of thumb: polling is fine for CLIs, batch jobs, and anything short-lived; callbacks win for web backends where you'd otherwise hold worker capacity hostage to a multi-minute render. If your callback endpoint doesn't seem to receive anything, work through why your hiapi task callback isn't firing.
Idempotency. Task creation is not idempotent — retrying a timed-out create can produce two billed tasks. Log the taskId the moment you get it, and on ambiguous failures (network timeout on create) check your task history before re-submitting. Since duration is billed per second, a duplicate 30-second task is the expensive kind of duplicate.
Error handling. The two families you'll actually see:
error_code: "INVALID_REQUEST") — wrong field name, out-of-range duration, invalid enum value. These are deterministic; fix the request, don't retry.401 with "code": "permission_denied" and the message "This API key cannot use the selected model." Check the key in your dashboard and confirm the model is enabled for it.status: "fail" with an error object (content policy, upstream capacity). These are worth one retry with backoff. If a task seems stuck in handling, see diagnosing hung or timed-out /v1/tasks jobs.What is the Grok Imagine API and how do I access it?
Grok Imagine is xAI's video generation model. Through HiAPI you call it as grok-imagine/text-to-video on the unified POST /v1/tasks endpoint with a single HiAPI key — no separate xAI account or SDK required.
How long can a Grok Imagine video be?
duration accepts integers from 6 to 30 seconds (default 6). Values outside that range are rejected at create time with a 400, and billing scales per second of output.
What's the difference between fun and normal mode?
normal (the default) gives balanced, realistic motion; fun skews more creative and exaggerated. It's the only motion-style knob the API exposes — pick per request, not per account.
Does grok-imagine/text-to-video support 1080p?
Not currently — resolution accepts 480p (default) or 720p. If you need higher output resolution, upscale downstream or compare other video models on the models page.
Can I animate an existing image with Grok Imagine?
Not with this model — it's text-only. There's a separate grok-imagine/image-to-video model on the same task endpoint that takes an image input; the async lifecycle (create → poll/callback → download) is identical.
Is there a Grok Imagine API free tier? Generation bills per second of video against your HiAPI balance — there's no keyless free endpoint. See the pricing page for current rates; for what "free" realistically looks like in this space, this free text-to-video API comparison covers the options.