HiAPI
Blog

Tutorial

How to Use ideogram-v3-character via the HiAPI API: curl + Python Guide

A practical, request-first walkthrough for character-consistent image generation on HiAPI

Oct 31, 2026 10 min read
深棕底上由燕麦色与浓缩咖啡色宽织物带交错编织的扁平几何封面图,点缀细黄铜色横线。

What ideogram-v3-character Is and When to Reach for It

ideogram-v3-character is an image generation model on HiAPI that focuses on character consistency. Instead of treating every generation as an isolated prompt, it lets you supply a reference image of a character so that subsequent renders keep the same face, outfit, and overall identity.

Reach for it when the who matters as much as the what:

  • Storyboards and comics where the same character appears across multiple panels.
  • Game asset variations — different poses, expressions, or costumes for one hero character.
  • Brand mascots that must survive many different scenes and backdrops.
  • Iterative art direction where you refine a character over several rounds without losing resemblance.

If you only need a one-off illustration and don't care about matching a previous image, a general-purpose text-to-image model is simpler. The extra structure of a reference image is what makes ideogram-v3-character worth the additional request fields.

The model is exposed through the same unified HiAPI image generation endpoint as other models, so the request shape will feel familiar: you send a JSON payload, receive a job reference for asynchronous work, and poll until the result is ready. This tutorial focuses on getting that flow right.

Before You Send a Request: Setup and Authentication

You only need a few things in place before the first call.

1. An API key

Create an API key in your HiAPI account dashboard. Treat it as a secret — it authorizes every request you make and is billed to your account.

2. Environment-based credential handling

Never hard-code the key in source files or commit it to git. Use an environment variable instead:

export HIAPI_API_KEY="your_api_key_here"

In Python you can read it with:

import os
api_key = os.environ["HIAPI_API_KEY"]

If you're using a .env file for local development, add it to .gitignore before you do anything else.

3. A reference image URL

Because character consistency depends on a reference, prepare an image you can pass by URL. Make sure the URL is publicly reachable or otherwise accessible to the API — private links behind auth will fail. A square or portrait image with a clear view of the character's face works best.

4. A way to make HTTP requests

Either curl on the command line or a Python environment with requests installed is enough. The examples below assume one of those two.

With those four items ready, you're set to send the first request.

A Working curl Request, Line by Line

Here is a complete request that submits an ideogram-v3-character job to HiAPI. Replace the placeholders with your own values.

curl -X POST "https://api.hiapi.ai/v1/images/generations" \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3-character",
    "prompt": "A friendly robot mechanic standing in a sunlit workshop, holding a wrench, three-quarter view",
    "reference_images": [
      "https://your-bucket.example.com/character-ref.png"
    ],
    "aspect_ratio": "1:1",
    "num_images": 1
  }'

What each part does

  • POST /v1/images/generations — the unified HiAPI image generation endpoint. All models go through the same path.
  • Authorization: Bearer $HIAPI_API_KEY — authenticates the call. The shell expands the environment variable you set earlier.
  • Content-Type: application/json — you're sending a JSON body, so declare it.
  • model — selects ideogram-v3-character. Without this, the request won't know which model to route to.
  • prompt — the scene description. Describe pose, setting, lighting, and mood; leave character identity to the reference image.
  • reference_images — an array of image URLs. For a single character, one entry is typical.
  • aspect_ratio — output shape. Match the intended use (square, portrait, etc.).
  • num_images — how many variations to produce per job.

A successful submission returns a JSON body containing a job identifier. Note that value — you'll need it in the polling step. The response may also include a status field indicating the job is queued or processing. If the status is already terminal, the result may be embedded directly; otherwise, proceed to polling.

The Same Request in Python

Here's the identical call in Python. It reads the key from the environment, sends the request, and prints the job reference.

import os
import json
import requests

API_KEY = os.environ["HIAPI_API_KEY"]
ENDPOINT = "https://api.hiapi.ai/v1/images/generations"

payload = {
    "model": "ideogram-v3-character",
    "prompt": "A friendly robot mechanic standing in a sunlit workshop, holding a wrench, three-quarter view",
    "reference_images": [
        "https://your-bucket.example.com/character-ref.png"
    ],
    "aspect_ratio": "1:1",
    "num_images": 1,
}

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json",
}

response = requests.post(ENDPOINT, headers=headers, data=json.dumps(payload), timeout=60)
response.raise_for_status()

job = response.json()
print(json.dumps(job, indent=2))

job_id = job.get("id") or job.get("job_id")
print("Job id:", job_id)

Notes on the Python version

  • timeout=60 prevents the script from hanging indefinitely on a bad network.
  • raise_for_status() turns non-2xx responses into exceptions so you notice auth and validation problems immediately.
  • Job id extraction — HiAPI returns the job identifier in the response body. Depending on the response shape, it may be under id or job_id; the example checks both, but you should inspect one real response and then hard-code the correct field name for clarity.

The payload is deliberately identical to the curl example. Copying the JSON body back and forth between the two is a good sanity check when debugging: if one works and the other doesn't, the problem is in the transport layer, not the model.

Handling Reference Images for Character Consistency

Reference images are what separate ideogram-v3-character from a plain text-to-image model. Getting them right is most of the battle.

How references are supplied

The reference_images field is an array of URLs. Each URL should point to an image the API can fetch directly. If you're storing user uploads, serve them from a bucket or CDN that allows unauthenticated GETs, or generate a signed URL that stays valid long enough for the job to run.

Tips for references that actually hold consistency

  • One character per reference. A group photo makes it ambiguous which face to preserve.
  • Clear, well-lit faces. Avoid heavy shadow, extreme angles, and occlusion.
  • Neutral or characteristic pose. Front or three-quarter views preserve identity best.
  • Consistent outfit in the reference if you want the outfit preserved — the model will echo what it sees.
  • Resolution matters, but don't overdo it. A reasonably sized image with a sharp face beats a huge, blurry one.

Keeping a character recognizable across generations

When you generate a second scene for the same character, reuse the same reference image rather than a previously generated output. Chaining generated images can accumulate small drift. If you need a new reference — say, a different costume — generate it once, inspect it, and then reuse that file as the new reference for subsequent jobs.

Verifying consistency

Generate two or three variations of the same character in different poses and compare them side by side. If the face or outfit drifts, the usual cause is a weak or ambiguous reference. Tighten the reference before touching the prompt.

Async Jobs: Submit, Poll, and Retrieve the Result

Image generation takes time, so HiAPI handles it asynchronously. The pattern is always the same: submit, capture the job id, poll until the job reaches a terminal state, then read the output URL.

The job lifecycle

  1. Submit — you send the request from the earlier examples.
  2. Queued — the job is accepted and waiting for capacity.
  3. Processing — the model is rendering.
  4. Completed or failed — a terminal state; the result (or error) is available.

Polling in Python

After capturing job_id, poll the job endpoint:

import time
import requests

def wait_for_job(job_id, api_key, interval=2, max_attempts=60):
    url = f"https://api.hiapi.ai/v1/jobs/{job_id}"
    headers = {"Authorization": f"Bearer {api_key}"}
    for attempt in range(max_attempts):
        resp = requests.get(url, headers=headers, timeout=30)
        resp.raise_for_status()
        data = resp.json()
        status = data.get("status")
        if status in ("completed", "succeeded"):
            return data
        if status in ("failed", "error", "canceled"):
            raise RuntimeError(f"Job failed: {data}")
        time.sleep(interval)
    raise TimeoutError(f"Job {job_id} did not finish in time")

Retrieving the result

When the job completes, the response body contains the output — typically an array of image URLs or a single URL, plus metadata. Download the image from that URL promptly; some URLs are time-limited. If you need long-term storage, copy the file to your own bucket as soon as the job succeeds.

Polling etiquette

  • Back off. A two-second interval is fine for short jobs; if you're polling many jobs, increase it or use jitter.
  • Cap your attempts. The max_attempts guard prevents infinite loops and gives your code a clear failure path.
  • Don't poll faster than you need to. Every poll is a request; hammering the endpoint won't make the render finish sooner.

Common Errors and How to Diagnose Them

When something goes wrong, the fastest path is usually to isolate whether the problem is your request, your reference, or the job itself.

Authentication failures

A 401 means the key is missing, malformed, or revoked. Check that the environment variable is actually set in the shell or process that runs the request. A common gotcha: setting the variable in one terminal and running the script in another.

Validation errors

A 400 almost always points at the payload. Verify:

  • The model field is exactly ideogram-v3-character.
  • reference_images is an array, not a string.
  • Every URL in the array is publicly accessible.
  • aspect_ratio uses a supported value.

If you're unsure, send the minimal payload — just model, prompt, and reference_images — and add fields back one at a time.

Jobs that never finish

If polling runs past your attempt cap, don't just retry blindly. Check the job status response for a message. Common causes are an unreachable reference URL or an overloaded queue. Re-submit once, and if it stalls again, simplify the prompt and the reference.

Reference images that are silently ignored

The job succeeds, but the character doesn't match. This is usually a reference problem rather than a code problem: the URL may be returning an error page, a PDF, or a placeholder. Fetch the URL yourself in a browser and confirm it returns the intended image with a correct content type.

Rate limiting

A 429 means you're sending requests too fast. Back off with exponential delay; if you're batching generations, stagger submissions rather than firing them all at once.

A quick checklist

  • Key set in the right environment?
  • Reference URL reachable without auth?
  • Payload fields spelled correctly?
  • Polling capped and backed off?
  • Output downloaded before its URL expires?

Work through that list in order and most failures resolve quickly. Once the first end-to-end run succeeds, keep it as a known-good example and diff any new request against it. That habit alone will save you time as you scale up to many characters and scenes.

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