Tutorial
How to Use grok-imagine Image-to-Image via the hiapi API: curl, Python, and a Working Request
grok-imagine/image-to-image takes one or more reference images plus a text prompt and returns an edited image — restyle a product photo, swap a background, or blend up to three references into one output. On hiapi it runs through the unified task API: create a task, poll (or get a callback), download the result. This guide walks through the exact request shape, with copy-paste curl and Python that work as written.
What you'll build + prerequisites
Goal: submit a reference image and a prompt, get back an edited image URL, and download it — first interactively with polling, then the production version with callbacks.
You need one thing: a hiapi API key. Grab it from your dashboard — it looks like sk-... and goes in the Authorization: Bearer header on every call.
Your reference images must be publicly reachable URLs (the model fetches them server-side), so host them on your CDN or object storage first.
Minimal working example (curl)
Create the task:
curl -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<your-key>" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine/image-to-image",
"input": {
"prompt": "Turn this product photo into a clean studio shot on a seamless white background with soft shadows",
"image_urls": ["https://your-cdn.com/product.jpg"]
}
}'
Two fields are required — prompt and image_urls — and that's a complete request. The response includes a task ID under data.taskId:
{
"data": {
"taskId": "<task-id>"
}
}
Poll for the result:
curl https://api.hiapi.ai/v1/tasks/<task-id> \
-H "Authorization: Bearer sk-<your-key>"
While the task is running, data.status reports progress. When it flips to success, the image URL is at data.output[0].url. If it's fail, data.error has the code and message.
One important detail: output URLs are signed and expire (the payload carries an expireAt). Download the file as soon as the task succeeds — never store or hotlink the raw output URL.
curl -o result.png "<data.output[0].url>"
The same in Python
import time
import requests
API = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<your-key>"}
payload = {
"model": "grok-imagine/image-to-image",
"input": {
"prompt": (
"Turn this product photo into a clean studio shot "
"on a seamless white background with soft shadows"
),
"image_urls": ["https://your-cdn.com/product.jpg"],
"aspect_ratio": "auto",
"resolution": "1k",
"output_format": "png",
},
}
# 1. Create the task
resp = requests.post(API, json=payload, headers=HEADERS, timeout=60)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
print("task:", task_id)
# 2. Poll until it reaches a terminal state
while True:
task = requests.get(f"{API}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
if task["status"] == "success":
image_url = task["output"][0]["url"]
break
if task["status"] == "fail":
raise RuntimeError(f"task failed: {task.get('error')}")
time.sleep(5)
# 3. Download immediately — output URLs expire
with open("result.png", "wb") as f:
f.write(requests.get(image_url, timeout=120).content)
print("saved result.png")
The full input schema
| Field | Required | Type | Notes |
|---|---|---|---|
prompt |
✅ | string | What to change / the target look |
image_urls |
✅ | array of URLs | 1–3 reference images, must be publicly reachable |
aspect_ratio |
optional | enum | auto, 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 |
optional | enum | 1k or 2k — lowercase |
output_format |
optional | enum | jpeg, png, or webp |
The schema is strict: any field it doesn't know is rejected with a 400. There is no size, no seed, no n — if you're porting code from a model that takes pixel dimensions (like size: "1024x1024"), switch to aspect_ratio + resolution here. Each task returns one image; for variations, submit multiple tasks.
Multi-Reference: up to 3 input images
image_urls accepts up to three references, and the model blends them — for example, a product shot plus a background plate plus a style reference. Send more than three and the API rejects the request outright:
invalid input: image_urls: maxItems: got 4, want 3
Put the image that matters most (usually the subject) first, and use the prompt to say what each reference contributes.
Auto Aspect
aspect_ratio: "auto" lets the model derive the output ratio from your reference image instead of forcing a fixed frame — the right default for product photos and edits where you want the composition preserved. Set an explicit ratio only when the destination demands it (e.g. 9:16 for a story placement, 16:9 for a hero banner).
Production notes
Callbacks instead of polling
For batch or server-side workloads, skip the polling loop — register a callback when you create the task and hiapi POSTs the terminal result to your endpoint:
{
"model": "grok-imagine/image-to-image",
"input": {
"prompt": "...",
"image_urls": ["https://your-cdn.com/product.jpg"]
},
"callback": {
"url": "https://your-server.com/hooks/hiapi",
"when": "final"
}
}
when supports only "final" — you get one call when the task reaches success or fail, not intermediate progress events.
Rule of thumb: poll for interactive tools (a user is watching; a 5-second sleep loop is fine), use callbacks for pipelines (dozens of tasks in flight; you don't want a poller per task). Your callback handler should still download the output immediately — the URL it receives expires like any other.
Idempotency and retries
The task API separates "submit" from "result", which makes safe retries straightforward:
- Persist
taskIdthe moment create returns. If your process crashes afterwards, resume by polling the stored ID — don't re-create. - Only retry the create call when it failed without returning a
taskId(network error, 5xx). Re-submitting a request that already returned an ID produces a second, separately billed task. - Treat
status: "fail"as terminal. Fix the input (or route to a fallback) and submit a new task; the failed one won't restart.
Common errors
| What you see | Meaning | Fix |
|---|---|---|
401 — permission_denied |
Bad key, or key lacks access to this model | Check the key in your dashboard |
400 INVALID_REQUEST — missing required field "prompt" / "image_urls" |
Required input missing | Both fields are mandatory |
400 INVALID_REQUEST — additional properties '...' not allowed |
Unknown field (e.g. size, seed, n) |
Strict schema — use only the fields in the table above |
400 INVALID_REQUEST — image_urls: maxItems |
More than 3 references | Trim to 3 |
404 — task not found |
Wrong or foreign taskId on GET |
Check the stored ID |
status: "fail" on poll |
Generation failed after acceptance | Read data.error, adjust input, submit fresh |
Note the auth failure is a 401 with "code": "permission_denied" in the error body — worth matching on explicitly, since it also covers keys that exist but aren't allowed on this model.
Where to go next
- Model details and live playground: grok-imagine/image-to-image
- Need higher fidelity? The quality tier uses the same request shape: grok-imagine-quality/image-to-image
- Starting from a prompt only (no reference image): grok-imagine text-to-image
- Per-image cost for both tiers: pricing
- Full task API reference: docs
FAQ
How many reference images can I pass?
Up to 3 in image_urls. The API hard-rejects more (maxItems: got N, want 3).
Can I set the output size in pixels?
No. There's no size field — you control shape with aspect_ratio (14 enum values) and sharpness with resolution (1k or 2k, lowercase). Anything else is a 400.
What does aspect_ratio: "auto" do?
It lets the model follow your reference image's proportions instead of forcing a fixed frame — the usual choice for edits where composition should survive.
How long are result URLs valid?
They're signed URLs with an expiry (expireAt in the output payload). Download the bytes as soon as the task succeeds; don't hotlink them.
Should I poll or use a callback?
Polling every ~5s is fine for interactive use. For batch pipelines, pass callback: {"url": ..., "when": "final"} and handle one POST per task — "final" is the only supported trigger.
Can I get multiple variations in one call?
No — there's no n parameter. Submit one task per variation; they run in parallel anyway.
What's the difference from grok-imagine-quality/image-to-image? Same request shape, higher-fidelity (and higher-cost) rendering tier. Prototype on the standard tier, re-run keepers on quality; compare per-image cost on the pricing page.
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