HiAPI
Blog

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

Nov 3, 2026 10 min read
文章封面图:暖沙色底上阶梯状横向色带如气压图般依次下降,赤陶色与棕褐色平涂叠印。

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 →

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