Choose a model, enter your prompt, and see the result.
HiAPI Blog
HiAPI
Generate it with HiAPI
gpt-image-2.5-flare is a single model on hiapi that handles both text-to-image generation and image editing through one unified endpoint — you don't need separate "generate" and "edit" model IDs. This guide gets you from zero to a working image in a few minutes using hiapi's async task API, with a full Node.js example, plus the production patterns (callbacks, idempotency, retries) you'll want before shipping.
sk-... and go in an Authorization: Bearer header.fetch), but the same three calls work from curl, Python, or anything that can POST JSON.hiapi exposes gpt-image-2.5-flare through one asynchronous endpoint family: you submit a task, then either poll for the result or receive a webhook callback when it's done. There's no synchronous "wait for the image in the response body" call — generation takes several seconds, so the API is task-based from the start.
This creates a task, polls until it finishes, and prints the resulting image URL.
const API_KEY = process.env.HIAPI_API_KEY; // sk-...
const BASE = "https://api.hiapi.ai/v1/tasks";
async function createTask(prompt) {
const res = await fetch(BASE, {
method: "POST",
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-image-2.5-flare",
input: {
prompt,
aspect_ratio: "16:9",
quality: "high",
},
}),
});
if (!res.ok) {
const err = await res.json();
throw new Error(`create task failed (${res.status}): ${JSON.stringify(err)}`);
}
const { data } = await res.json();
return data.taskId; // e.g. "tk-hiapi-..."
}
async function waitForTask(taskId, { timeoutMs = 120_000, intervalMs = 3_000 } = {}) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const res = await fetch(`${BASE}/${taskId}`, {
headers: { "Authorization": `Bearer ${API_KEY}` },
});
const { data: task } = await res.json();
if (task.status === "success") return task;
if (task.status === "fail") {
throw new Error(`task failed: ${task.error?.code} ${task.error?.message}`);
}
await new Promise((r) => setTimeout(r, intervalMs));
}
throw new Error(`task ${taskId} timed out`);
}
const taskId = await createTask("a minimalist poster of a lighthouse at dawn, flat color");
const task = await waitForTask(taskId);
console.log(task.output[0].url); // download this — it expires, so save it promptly
Run it with HIAPI_API_KEY=sk-... node generate.js. The response's data.output array only appears once status is "success"; each entry has a temporary url (it carries an expireAt), so download or re-upload it immediately rather than storing the link.
To edit an existing image instead of generating from scratch, add input.image_urls (an array of publicly reachable URLs, 1–16 images) and describe what to do with each one in the prompt — same model, same endpoint, no separate "edit" model ID:
body: JSON.stringify({
model: "gpt-image-2.5-flare",
input: {
prompt: "replace the background with a studio gradient, keep the subject unchanged",
image_urls: ["https://example.com/product-photo.jpg"],
},
}),
Other useful input fields: background (auto / transparent / opaque, default auto) and output_format (png / jpeg / webp, default webp). There's no resolution field for this model — size is controlled entirely through aspect_ratio (which also accepts explicit pixel dimensions like 1536x1024 if you need an exact size rather than a ratio).
Use a callback instead of polling in production. Polling is fine for scripts, but for a real backend, register a webhook so hiapi notifies you the moment the task finishes instead of you hammering GET /v1/tasks/<id> on a timer:
body: JSON.stringify({
model: "gpt-image-2.5-flare",
input: { prompt: "..." },
callback: {
url: "https://yourapp.com/webhooks/hiapi",
when: "final", // the only supported value — fires once, on success or fail
},
}),
Your webhook handler receives the same task object you'd get from polling GET /v1/tasks/<id> — check status and branch on success vs fail there.
Make retries idempotent. If your job runner retries a failed HTTP call (timeout, 5xx, network blip) and you're not careful, you can accidentally submit the same generation twice and pay for both. Pass a stable Idempotency-Key header — up to 255 bytes, typically your own job/request ID — and a retried request with the same key returns the original task instead of creating a new one:
headers: {
"Authorization": `Bearer ${API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": jobId, // reuse the same value across retries of the same logical request
},
Handle the specific failure modes. A few status codes you should branch on explicitly rather than treating everything as "retry":
| Status | Meaning | What to do |
|---|---|---|
401 with error.code: "permission_denied" | Bad or missing API key | Don't retry — check the Authorization header |
402 | Insufficient balance | Don't retry — top up first |
400 | Invalid request body (bad field, wrong type) | Don't retry blindly — fix the payload |
503 | Temporarily unavailable | Safe to retry with backoff |
task status: "fail" | The task itself failed after being accepted (e.g. unreachable image_urls) | Inspect error.code / error.message, don't loop forever |
The 401 error body looks like this — the same shape across every hiapi model, so it's worth checking for once in a shared error handler:
{
"error": {
"code": "permission_denied",
"message": "...",
"request_id": "...",
"type": "hiapi_error"
}
}
Authorization header work across all hiapi endpoints.gpt-image-2, or want the Sunburst-specific editing walkthrough? See the GPT Image 2.5 API guide for that migration path.Is gpt-image-2.5-flare one model or two (generate + edit)? One. Whether it generates from scratch or edits depends entirely on whether you include input.image_urls — there's no separate model ID to switch to.
Why isn't there an image in my response right away? hiapi's image models are all async — POST /v1/tasks only returns a taskId. You get the actual output array by polling GET /v1/tasks/<id> until status is success, or by registering a callback.
How long does a task take? Typically single-digit seconds, occasionally longer under load. Use a generous poll timeout (60–120s) rather than assuming it always finishes instantly.
Can I pass more than one reference image for editing? Yes, image_urls accepts up to 16 images — reference each one's role in your prompt (e.g. "use the first image's pose with the second image's outfit") since the array order matters.
What happens if my callback URL is down when the task finishes? hiapi calls it once when the task reaches a final state (when: "final"). If your endpoint is unreachable, you won't get notified — for anything you can't afford to miss, poll as a fallback or reconcile periodically against GET /v1/tasks/<id> using task IDs you've logged.
Do I need to store the output URL myself? Yes — the url in output[0] is temporary and expires. Download or re-upload it to your own storage as soon as the task succeeds.