
Generating an image from a text prompt with Grok Imagine is one API call plus a short poll: you POST a prompt to hiapi's unified task endpoint with the model id grok-imagine/text-to-image, wait for the task to reach success, and download the output URL. This guide walks through the exact request — a copy-paste curl version, a complete Python script, the parameters the model actually validates (including its unusually wide set of aspect ratios), and the errors you'll hit in practice. Every request and error message below was verified against the live API.
The flow is three steps, and it's the same task pattern hiapi uses for every generation model:
POST https://api.hiapi.ai/v1/tasks with model and input → you get back a taskId.GET https://api.hiapi.ai/v1/tasks/<taskId> until data.status is success (or fail).data.output[0].url — immediately, because the URL is signed and expires.You need exactly one thing: a hiapi API key. Grab it from the dashboard (API Keys section) — it looks like sk-... and goes in the Authorization: Bearer header. Use the bare model id grok-imagine/text-to-image; no vendor prefix, no version suffix.
Create the task:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine/text-to-image",
"input": {
"prompt": "A lighthouse on a rocky cliff at golden hour, waves crashing below, cinematic lighting, photorealistic",
"aspect_ratio": "16:9",
"resolution": "2k",
"output_format": "png"
}
}'
A successful create returns a task id:
{"code": 200, "data": {"taskId": "task_xxxxxxxxxxxx"}}
Then poll it:
curl -s https://api.hiapi.ai/v1/tasks/task_xxxxxxxxxxxx \
-H "Authorization: Bearer sk-<your-key>"
While the task is running you'll see a non-terminal status; keep polling every few seconds. When data.status flips to success, the response carries the result:
{
"code": 200,
"data": {
"taskId": "task_xxxxxxxxxxxx",
"status": "success",
"output": [
{"url": "https://.../image.png?...expireAt=..."}
]
}
}
Download data.output[0].url right away. The URL is time-limited (note the expireAt) — save the bytes to disk or your own storage, never hot-link it.
The input schema is strict: unknown fields are rejected with a 400, so what's listed here is the complete surface (verified July 2026).
| Field | Type | Required | Values |
|---|---|---|---|
prompt | string | ✅ | Your text prompt |
aspect_ratio | string | optional | 2:1, 20:9, 19.5:9, 16:9, 4:3, 3:2, 1:1, 2:3, 3:4, 9:16, 9:19.5, 9:20, 1:2 |
resolution | string | optional | 1k, 2k — lowercase only |
output_format | string | optional | jpeg, png, webp |
Two things stand out:
The ultra-wide ratios. Beyond the usual 16:9/1:1/9:16, Grok Imagine accepts 2:1 (ultra-wide), 20:9 (cinematic) and 19.5:9 (modern phone screens), plus their tall mirrors 1:2, 9:20 and 9:19.5. That makes it a direct fit for hero banners, letterboxed keyart and full-bleed phone wallpapers without outpainting or cropping. Note that 21:9 is not in the list — the validator rejects it; use 20:9 instead.
What's deliberately missing. There is no n (one image per task — fan out parallel tasks for batches), no seed, no negative_prompt, no size, and no style field. Sending any of them returns 400 INVALID_REQUEST: additional properties ... not allowed. Everything you want to steer — and everything you want to avoid — goes into the prompt text itself.
No SDK needed — just requests:
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
KEY = "sk-<your-key>"
HEADERS = {"Authorization": f"Bearer {KEY}", "Content-Type": "application/json"}
def create_task(prompt: str) -> str:
payload = {
"model": "grok-imagine/text-to-image",
"input": {
"prompt": prompt,
"aspect_ratio": "2:1", # ultra-wide banner
"resolution": "2k", # lowercase: "1k" or "2k"
"output_format": "png",
},
}
r = requests.post(API, headers=HEADERS, json=payload, timeout=60)
body = r.json()
task_id = (body.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"create failed: {body}")
return task_id
def wait_task(task_id: str, timeout_s: int = 300, poll_s: int = 5) -> dict:
deadline = time.time() + timeout_s
while time.time() < deadline:
r = requests.get(f"{API}/{task_id}",
headers={"Authorization": f"Bearer {KEY}"}, timeout=30)
task = r.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_s)
raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")
task_id = create_task(
"A minimalist developer workspace at dawn, warm window light, "
"shallow depth of field, photorealistic"
)
print(f"created {task_id}, polling...")
task = wait_task(task_id)
url = task["output"][0]["url"]
img = requests.get(url, timeout=120).content # download NOW - the URL expires
with open("grok-imagine.png", "wb") as f:
f.write(img)
print(f"saved grok-imagine.png ({len(img)} bytes)")
The script treats success and fail as the only terminal states and keeps polling on anything else — that's the robust way to consume the task API.
Callback instead of polling. For batch or server-side workloads, add a top-level callback object next to model/input and hiapi will POST the final task state to your endpoint instead of making you poll:
{
"model": "grok-imagine/text-to-image",
"input": {"prompt": "..."},
"callback": {"url": "https://your-app.com/hooks/hiapi", "when": "final"}
}
Only "final" delivery is supported — you get one notification at the terminal state, so make your handler idempotent on taskId (webhooks can be retried). Polling is simpler for scripts and one-offs; callbacks win once you're running dozens of concurrent tasks or paying for idle worker time.
Retry on the right side of the taskId. Creation is safe to retry on network errors or 5xx — you haven't been charged until a task is accepted. But once you hold a taskId, poll that id rather than re-submitting the prompt, or you'll pay for duplicate generations.
Error handling. The two failures you'll actually see:
400 INVALID_REQUEST at create time — the message is specific and names the offending field, e.g. invalid input: prompt: missing required field "prompt". Fix the payload; retrying unchanged will fail forever.401 with "code": "permission_denied" — the key is invalid or can't use this model ("This API key cannot use the selected model"). Check the key in the dashboard; this is not a transient error.| Symptom | Cause | Fix |
|---|---|---|
400 aspect_ratio: value must be one of '2:1', '20:9', ... | Ratio not in the enum (e.g. 21:9) | Use the closest supported value — 20:9 for cinematic wide |
400 resolution: value must be one of '1k', '2k' | Sent 1K, 2K or 4k | Lowercase 1k or 2k only |
400 additional properties 'size' not allowed | Reused another model's schema (size, n, seed, negative_prompt) | Strip extras; this model takes only the four fields above |
401 permission_denied | Bad key, or key lacks access to this model | Verify the key and model permissions in the dashboard |
| Image URL returns an error later | Signed output URL expired | Download immediately after success; store the bytes yourself |
How much does a grok-imagine text-to-image call cost?
It's priced per image, with 2k costing more than 1k. Current numbers are on the pricing page and on the model page itself.
Can I generate multiple images in one request?
No — the schema has no n parameter, so it's one image per task. For batches, create several tasks in parallel (each returns its own taskId) and collect results via polling or a callback.
Does it support a seed or negative prompt?
Neither. The validator rejects seed and negative_prompt as unknown fields. Describe what you don't want in the prompt itself ("no text, no watermark") and treat outputs as non-reproducible.
What's the largest / widest image I can get?
resolution: "2k" combined with any ratio in the enum. The widest shapes are 2:1, then 20:9 and 19.5:9; the tallest are 1:2, 9:20 and 9:19.5. There is no 4k tier and no 21:9.
Polling or callback — which should I use?
Polling for scripts, notebooks and low volume (the Python above is enough). Callbacks ("when": "final") once you run concurrent batches and don't want workers blocked on time.sleep.
Can Grok Imagine also edit images or make videos?
Yes — the same family exposes grok-imagine/image-to-image, grok-imagine/image-to-video and grok-imagine/text-to-video on the identical task API. The image-to-video walkthrough covers the video side, including duration and pricing differences.
Do I need an API key to try it?
Yes — every call is authenticated with Authorization: Bearer sk-.... Keys are issued in the dashboard; there is no unauthenticated endpoint.