HiAPI
Blog

Tutorial

How to Use grok-imagine Image-to-Image via the hiapi API: curl, Python, and a Working Request

Jul 11, 2026
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 taskId the 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

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 →

Start building with persistent AI artifacts

Get your API key and call image, video and audio models through one task-based API.

Read the API docs