Tutorial
How to Call grok-imagine/image-to-image via the HiAPI API: curl and Python Guide
A working request walkthrough for image-to-image on HiAPI
What grok-imagine/image-to-image Does for Developers
grok-imagine/image-to-image is a transformation endpoint: you hand it a reference image plus a prompt, and it returns a new image that follows the prompt while staying visually anchored to the reference. Think of it as guided generation rather than generation from scratch. The model id you call on HiAPI is literally grok-imagine/image-to-image, and everything else in the request is about describing the change you want.
Choose this endpoint over a text-to-image call whenever the output must retain something from an existing asset — a product photo that needs a new background, a character sketch that needs rendering, a composition that needs a style shift. Text-to-image is the right tool when you have no source image and only a description; image-to-image is the right tool when the source image is part of the specification.
Because HiAPI exposes this as a single unified interface, your integration work is limited to building one request shape and handling one response shape. You do not need a separate SDK per model family, and you do not need to re-learn authentication for each endpoint.
Request Anatomy: Model, Reference Image, and Prompt
Every valid call has four conceptual parts. Getting each one right before you write code saves most of the debugging later.
Model id
The model field carries the string grok-imagine/image-to-image. Treat it as a constant in your client rather than a hardcoded literal scattered through the codebase — you will want one place to change it if you later experiment with other HiAPI models.
Reference image
The reference image is the anchor. How you supply it depends on the transport you choose: a URL the API can fetch, or inline base64 data when the image is generated on the fly or is not publicly reachable. Prefer URLs for assets you already host; prefer inline data for user uploads you have not persisted anywhere public yet. Whatever the transport, validate the image before sending: supported format, non-zero size, and dimensions large enough to be meaningful.
Prompt
The prompt describes the transformation, not the whole scene. If the reference image already contains a subject, describe what should change — style, lighting, background, materials — and leave the invariant parts implicit. Over-specifying what is already visible in the reference tends to fight the image conditioning rather than help it.
Aspect handling
The remaining piece is how output dimensions are decided, which is the subject of the next section. Keep these four parts separated in your request-building code so each can be validated and logged independently.
Using the Auto Aspect Option
The auto aspect option lets the API choose output dimensions for you instead of you pinning an explicit width and height. When it is on, the service derives an appropriate aspect ratio from the request context — most importantly the reference image — so the output is shaped sensibly relative to your input rather than forced into a default frame.
This matters more than it sounds. If you fix dimensions that disagree with the reference image's proportions, you either get letterboxing-like artifacts, awkward cropping of the subject, or a composition that ignores the source framing. Auto aspect avoids that class of mismatch by letting the geometry follow the input.
When to keep auto on
- The reference image comes from users and varies in shape.
- You are prototyping and do not yet know which dimensions suit the use case.
- The output feeds a pipeline that crops or resizes downstream anyway.
When to pin dimensions explicitly
- You have a fixed slot in a UI or a print target and need exact output geometry.
- You are generating a batch that must be visually consistent in size.
A practical pattern is to develop with auto aspect enabled, inspect the dimensions the API returns for your real inputs, and only then decide whether to lock dimensions for production. Log the returned image metadata alongside the request so this decision is based on evidence rather than guesswork.
A Working curl Request
The request below is complete except for the placeholders, which are marked in angle brackets. Replace them with your own values and it will run as-is.
curl -X POST "https://api.hiapi.ai/v1/images/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "grok-imagine/image-to-image",
"prompt": "<describe the transformation you want>",
"image": "<publicly reachable URL of your reference image>",
"aspect_ratio": "auto"
}'
Placeholders to replace
$HIAPI_API_KEY— read your key from an environment variable rather than pasting it into the command. If the variable is unset, the request fails with an authentication error and the key never lands in your shell history.<describe the transformation you want>— a short, specific instruction such as a style or background change.<publicly reachable URL of your reference image>— a URL the service can fetch without authentication. If your asset is private, switch to inline base64 data instead.
Reading the response
Pipe the output through a JSON formatter on first run so you can see the response shape clearly. The two things to look for are the image payload (a URL or encoded data, depending on the response mode) and any job identifier when the call is handled asynchronously. Keep the full raw response in a log during development — it is the fastest way to answer "what actually came back" when something looks wrong.
The Same Request in Python
The Python version should mirror the curl request field for field. The value of keeping them aligned is that a bug reproduced in one can be confirmed in the other without translation guesswork.
import os
import requests
API_URL = "https://api.hiapi.ai/v1/images/generations"
MODEL = "grok-imagine/image-to-image"
def generate_from_reference(prompt: str, image_url: str) -> dict:
payload = {
"model": MODEL,
"prompt": prompt,
"image": image_url,
"aspect_ratio": "auto",
}
response = requests.post(
API_URL,
headers={
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
},
json=payload,
timeout=120,
)
response.raise_for_status()
return response.json()
Where error handling belongs
Wrap the call, not the caller. response.raise_for_status() converts non-2xx responses into exceptions so a single try/except around generate_from_reference covers transport failures and API rejections together. Inspect response.status_code and the error body inside the function before raising if you want structured logging of the failure reason.
Keeping the client clean
Read the API key once at startup, set an explicit timeout, and return parsed JSON rather than the raw response object. Callers should not need to know about HTTP. In tests, point API_URL at a stub server so request-building logic is verified without spending real generation calls.
Sync vs Async Responses
Some image-to-image requests complete quickly enough to return the result in the same HTTP response. Others are handled as jobs: the initial call returns an identifier and the image becomes available later. Your client should not assume one or the other.
How to tell them apart
Inspect the response body after every call. If it contains the image payload directly, you are in the synchronous path — extract and return it. If it contains a job or task identifier instead, you are in the asynchronous path and must poll until the job reaches a terminal state.
Structuring for both
A small dispatch function keeps both paths out of your business logic:
def resolve_result(response_json: dict) -> dict:
if "image" in response_json or "data" in response_json:
return response_json
job_id = response_json.get("id") or response_json.get("job_id")
if job_id:
return poll_until_done(job_id)
raise RuntimeError(f"Unrecognized response shape: {response_json}")
Polling rules that avoid trouble
- Use exponential backoff with a cap instead of a tight loop.
- Set a maximum total wait time and fail cleanly when it is exceeded.
- Treat every non-terminal state as "keep waiting" and only two states as final: success and failure.
- Log the job id on every poll so a stuck job can be traced from logs alone.
The dispatch approach means switching between sync and async behavior never requires changes in the code that calls resolve_result.
Debugging Common Error Codes
Most failed calls on this endpoint fall into a small number of buckets. Work through this checklist in order — it goes from the most common causes to the least.
Authentication failures
If the response indicates an auth problem, the key is missing, malformed, or not being sent. Check that the environment variable is actually populated in the process making the call, and that the header is Authorization: Bearer <key> exactly. A key that works in your shell but not in your service usually means the service's environment differs from your shell's.
Validation errors on the reference image
Image-related rejections typically mean one of four things: the URL is not publicly fetchable, the format is unsupported, the payload is too large, or the image is too small or corrupt. Test the URL in a browser without credentials — if it does not load there, the API cannot fetch it either. For inline base64, verify the encoding is pure base64 with no data-URL prefix unless the parameter expects one.
Prompt and parameter errors
An empty or oversized prompt, or an unknown parameter value, produces a validation response. Log the exact payload you sent alongside the error — a surprising share of failures are typos in field names rather than problems with values.
Rate limiting
A rate-limit response means back off, not retry immediately. Honor the retry guidance in the response headers, add jitter, and cap the number of retries. Retrying without backoff turns a temporary limit into a sustained one.
Server-side errors
A 5xx response is on the service side. Retry a bounded number of times with backoff; if it persists, capture the request id from the response and the timestamp, and reduce concurrency while investigating.
Production Checklist Before You Ship
A working request is the beginning, not the end. Before this endpoint handles real traffic, confirm the following.
Validate inputs at the boundary
Check reference image format and size, prompt length, and parameter values before the request leaves your service. Rejecting bad input locally is faster and cheaper than a round trip, and it produces clearer error messages for your users.
Retry only what is safe to retry
Retry transport failures, rate limits, and 5xx responses with exponential backoff and jitter. Do not retry validation or authentication errors — they will fail identically and only add load.
Log enough to reconstruct a failure
Record the model id, a hash or truncated form of the prompt, the reference image identifier (not the full payload), the response status, the job id when present, and the request id. That set is usually enough to answer "what happened" without storing sensitive content.
Keep secrets out of code
Read the API key from the environment or a secrets manager, never from a literal in the source. Rotate keys on a schedule and revoke them immediately if a leak is suspected.
Watch cost behavior
Billing on this endpoint is driven by generation, so the levers that matter are request volume, retries, and polling frequency. Avoid retry storms, back off on polling, and cache results keyed by prompt and reference image where the same transform is requested repeatedly. Check the HiAPI pricing panel for current rates rather than hardcoding assumptions.
Test the unhappy paths
Write tests for an invalid image URL, a rate-limit response, and an asynchronous job that never completes. Those three cover the failures most likely to reach production unnoticed.
With request building, response dispatch, and error handling in place, grok-imagine/image-to-image becomes a routine part of your pipeline rather than a special case.
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