Tutorial
How to Use the grok-imagine-quality Text-to-Image API: curl, Python, and a Working Request
TL;DR
- What this is: a working recipe for the grok-imagine-quality/text-to-image API on hiapi — create a task on
POST /v1/tasks, pollGET /v1/tasks/<taskId>(or use a callback), download the image fromoutput[0].url. - The schema is strict and small:
prompt(required),aspect_ratio(13 ratios, default1:1),resolution(1k|2k, lowercase, default1k),output_format(jpeg|png|webp, defaultjpeg). Anything else is rejected with a 400. - "Quality" is the tier, not a knob. There is no
qualityorrich_detailparameter — the richer detail, materials, and lighting are what this model variant does by default. For cheap volume drafts, its standard-tier siblinggrok-imagine/text-to-imageexists on the same endpoint. - Output URLs carry an
expireAtdeadline — download promptly or store persistently.
What you're building and what you need
Goal: send a text prompt to grok-imagine-quality/text-to-image and get a finished, hero-grade image file back — first with curl, then as a small Python script you can drop into a job queue.
You need exactly one thing: a hiapi API key. Grab it from your hiapi dashboard and export it:
export HIAPI_API_KEY="sk-..."
Every request authenticates with a standard bearer header: Authorization: Bearer sk-<key>.
The minimal working request (curl)
Image generation on hiapi is async-only. You never wait on one long HTTP call; you create a task and fetch the result when it's done.
Step 1 — create the task:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine-quality/text-to-image",
"input": {
"prompt": "Product hero shot of a matte-black espresso machine on a slate counter, dramatic directional lighting, shallow depth of field, premium commercial finish",
"aspect_ratio": "16:9",
"resolution": "2k",
"output_format": "png"
}
}'
You get a taskId back immediately while the model works in the background:
{
"code": 200,
"message": "success",
"data": { "taskId": "tk-hiapi-01HZTQ8BX2N3GM3YFK4Z9D7VQR" }
}
Step 2 — poll until it reaches a terminal state:
curl https://api.hiapi.ai/v1/tasks/tk-hiapi-01HZTQ8BX2N3GM3YFK4Z9D7VQR \
-H "Authorization: Bearer $HIAPI_API_KEY"
A task moves through queued → handling → archiving and ends at success or fail. Only success carries output:
{
"code": 200,
"message": "success",
"data": {
"taskId": "tk-hiapi-01HZTQ8BX2N3GM3YFK4Z9D7VQR",
"model": "grok-imagine-quality/text-to-image",
"status": "success",
"created": 1783130400,
"completed": 1783130460,
"output": [
{
"url": "https://cdn.hiapi.ai/tasks/.../image.png",
"type": "image",
"expireAt": 1783735260
}
]
}
}
Step 3 — download it before expireAt:
curl -o hero.png "https://cdn.hiapi.ai/tasks/.../image.png"
The same flow in Python
A complete script — create, poll, save. Copy, set HIAPI_API_KEY, run.
import os
import time
import requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}
payload = {
"model": "grok-imagine-quality/text-to-image",
"input": {
"prompt": (
"Product hero shot of a matte-black espresso machine on a slate "
"counter, dramatic directional lighting, shallow depth of field, "
"premium commercial finish"
),
"aspect_ratio": "16:9",
"resolution": "2k", # lowercase! "2K" is rejected with a 400
"output_format": "png",
},
}
resp = requests.post(BASE, headers=HEADERS, json=payload, timeout=60)
resp.raise_for_status() # 4xx here = the request itself was rejected
task_id = resp.json()["data"]["taskId"]
print("task created:", task_id)
while True:
task = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
status = task["status"]
if status == "success":
image = task["output"][0]
with open("hero.png", "wb") as f:
f.write(requests.get(image["url"], timeout=120).content)
print("saved hero.png")
break
if status == "fail":
err = task["error"]
raise RuntimeError(f"task failed: {err['code']} {err['message']}")
time.sleep(5) # queued / handling / archiving — keep polling
Generation at the 2k tier typically lands within a minute or two; a 5-second poll interval is plenty.
Parameters that actually exist
The input schema is strict — unknown fields fail with 400 INVALID_REQUEST: additional properties not allowed rather than being silently ignored. That's good news: typos can't sneak into production. The full surface:
| Field | Required | Values | Default |
|---|---|---|---|
input.prompt |
yes | free text | — |
input.aspect_ratio |
no | 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 |
1:1 |
input.resolution |
no | 1k, 2k (lowercase only) |
1k |
input.output_format |
no | jpeg, png, webp |
jpeg |
Three things worth knowing before you build on it:
- The "quality" in the name is the tier, not a parameter. You may see this model described as having richer detail, materials, and lighting — that's the model variant itself. There is no
rich_detail,quality, orstylefield to toggle. 1kand2kare billed as separate tiers. A common pattern: iterate on prompts at1k, then re-run the winning prompt at2kfor the final asset. Current per-image rates are on the hiapi pricing page.- No
n, noseed, nonegative_prompt. One task produces one image. For variations, submit several tasks in parallel — they're independent and queue concurrently.
Production notes: callbacks, idempotency, and errors
Prefer a callback over polling in production. Pass callback at the top level of the request body (not inside input) and hiapi calls your service when the task reaches a terminal state:
{
"model": "grok-imagine-quality/text-to-image",
"input": { "prompt": "..." },
"callback": {
"url": "https://your-service.example.com/hiapi/callback",
"when": "final"
}
}
With when: "final" you're notified on both success and fail, so deduplicate by taskId on your side. Keep low-frequency polling as a fallback in case a callback is missed — the task detail endpoint is always the source of truth.
Make retries safe with Idempotency-Key. Task creation accepts an Idempotency-Key header (up to 255 bytes). Retrying with the same key never creates a duplicate task — replays return the original taskId:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Idempotency-Key: order-42-hero-image" \
-H "Content-Type: application/json" \
-d '{"model": "grok-imagine-quality/text-to-image", "input": {"prompt": "..."}}'
Handle the three failure shapes distinctly:
- Auth failure — HTTP
401with{"error": {"code": "permission_denied", "type": "hiapi_error", ...}}. Check the key and whether it's allowed to use this model; don't retry blindly. - Invalid input — HTTP
400with"error_code": "INVALID_REQUEST"and a message naming the exact field (e.g.resolution: value must be one of '1k', '2k'). Fix the payload; retrying the same body will fail the same way. - Task-level failure — the create call succeeded, but the task ends with
status: "fail"and adata.errorobject. Inspecterror.codebefore re-submitting.
Mind expireAt. Output URLs are temporary. Download the file as soon as the task succeeds, or pass storage: "persistent" at creation time to keep outputs long-term.
Related pages
- grok-imagine-quality/text-to-image model page — playground and per-tier pricing
- Full parameter reference in the docs
- Create Task API reference — headers, idempotency, callbacks
- How to use grok-imagine-quality image-to-image — same tier, editing existing images
- All image, video and music models
FAQ
How is grok-imagine-quality different from grok-imagine/text-to-image?
Same endpoint, same request shape, different tier. The quality tier targets hero shots and commercial assets with richer detail and lighting, priced by 1k/2k resolution tier; the standard grok-imagine/text-to-image is the faster, cheaper option for volume and ideation.
Why does "resolution": "2K" return a 400?
The enum is case-sensitive and lowercase: 1k or 2k. Uppercase values are rejected with INVALID_REQUEST.
Can I set exact pixel dimensions like 1920x1080?
No. You control shape with aspect_ratio (13 options from 2:1 ultra-wide to 9:20 extra-tall) and sharpness with the 1k/2k tier. There is no free-form size field on this model.
Can I generate multiple images in one request?
No — there's no n parameter. Submit multiple tasks in parallel instead; each returns its own taskId and they process concurrently.
Does grok-imagine-quality support image-to-image?
Yes, as a separate model id: grok-imagine-quality/image-to-image. See the i2i recipe for its schema — it differs from text-to-image.
How long do result URLs stay valid?
Each output[] entry has an expireAt Unix timestamp. Download before that deadline, or create the task with storage: "persistent" (or promote the output later) to keep it.
What does a queued-but-not-finished task look like?
GET /v1/tasks/<taskId> returns status of queued, handling, or archiving with no output yet. Only success includes downloadable output; fail includes data.error instead.
Related articles
View all articles →-
Tutorial
How to Call hailuo-2.3-fast/image-to-video via the HiAPI API: curl and Python
A first working request for the fast, low-cost image-to-video tier — from model ID to downloaded MP4
9 min read -
Tutorial
How to Use hailuo-2.3/text-to-video via the HiAPI API: curl, Python, and a Working Request
11 min read -
Tutorial
Kandinsky 6.0 Pro Text-to-Video on HiAPI: curl and Python Tutorial
A request-first walkthrough: build the prompt-to-clip call, submit it, poll for completion, and download the result
11 min read