HiAPI
Blog

Tutorial

How to Use flux-2-klein-4b/text-to-image via the hiapi API

Jul 30, 2026
How to Use flux-2-klein-4b/text-to-image via the hiapi API

slug: flux-2-klein-4b-text-to-image-api-guide locale: en title: How to Use flux-2-klein-4b/text-to-image via the hiapi API category: tutorial summary:

  • Minimal curl and Python examples for flux-2-klein-4b/text-to-image over hiapi's unified /v1/tasks endpoint.
  • 'Full parameter table: prompt, aspect_ratio enum, and seed — the strict schema rejects unknown fields.'
  • 'Production notes: callback.url vs polling, the Idempotency-Key header, and the two error envelope shapes.' takeaways:
  • Create with POST /v1/tasks, then poll GET /v1/tasks/{taskId} or use callback.url for the result.
  • aspect_ratio accepts 11 named ratios; there's no size or n field for this model.
  • Same Idempotency-Key header returns the same taskId on retry — safe to reuse on timeouts.
  • 400 errors use error_code, 401 auth errors use a nested error.code — check HTTP status first. meta_title: flux-2-klein-4b Text-to-Image API Guide meta_description: 'Call flux-2-klein-4b/text-to-image with curl and Python: create a task, poll for the image, and handle callbacks, idempotency, and errors in production.' keywords:
  • flux-2-klein-4b text-to-image api
  • flux-2-klein-4b api example
  • hiapi image generation api
  • flux api curl python tags:
  • api-guide
  • image-generation
  • flux author_name: hiapi is_published: false cover_image: https://static.hiapi.ai/blog/_default/recipe-cover.jpg

How to Use flux-2-klein-4b/text-to-image via the hiapi API

What you'll build

A script that sends a prompt to flux-2-klein-4b/text-to-image, waits for the image, and downloads it — plus the production details (callbacks, idempotency, error shapes) you need before this runs unattended.

Prerequisite: grab an API key from the hiapi dashboard. Every request below authenticates with Authorization: Bearer sk-<your-api-key>.

The minimal working example

hiapi generation models run behind one unified async endpoint: POST /v1/tasks creates a job and hands back a taskId immediately; you then poll GET /v1/tasks/{taskId} until it reaches a terminal state.

curl -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-<your-api-key>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-klein-4b/text-to-image",
    "input": {
      "prompt": "a red fox walking through fresh snow, golden hour light",
      "aspect_ratio": "16:9"
    }
  }'

That returns:

{"code": 200, "data": {"taskId": "tk-hiapi-01K..."}, "message": "success"}

Poll the same task until data.status flips from handling to success (it briefly passes through archiving in between):

curl https://api.hiapi.ai/v1/tasks/tk-hiapi-01K... \
  -H "Authorization: Bearer sk-<your-api-key>"
{
  "code": 200,
  "data": {
    "status": "success",
    "output": [
      {"type": "image", "url": "https://temp.hiapi.ai/.../01K...-0.jpg", "expireAt": 1785939579}
    ]
  },
  "message": "success"
}

data.output[0].url is the finished image. It's a temporary link — in testing it expired about 7 days after generation — so download the bytes and store them yourself rather than linking to it directly.

Same flow in Python, with polling

import time
import requests

API_KEY = "sk-<your-api-key>"
BASE = "https://api.hiapi.ai/v1"
headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

resp = requests.post(f"{BASE}/tasks", headers=headers, json={
    "model": "flux-2-klein-4b/text-to-image",
    "input": {
        "prompt": "a red fox walking through fresh snow, golden hour light",
        "aspect_ratio": "16:9",
    },
})
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]

while True:
    task = requests.get(f"{BASE}/tasks/{task_id}", headers=headers).json()["data"]
    if task["status"] == "success":
        image_url = task["output"][0]["url"]
        break
    if task["status"] == "failed":
        raise RuntimeError(f"generation failed: {task}")
    time.sleep(3)

image_bytes = requests.get(image_url).content
open("fox.jpg", "wb").write(image_bytes)

Parameters that matter

flux-2-klein-4b/text-to-image has a strict input schema — sending a field it doesn't recognize (size, n, negative_prompt, whatever another hiapi image model accepts) gets rejected outright, so don't copy params across models without checking the model page first.

Field Required Notes
prompt Yes String describing the image.
aspect_ratio No One of 1:1, 16:9, 9:16, 3:2, 2:3, 4:3, 3:4, 5:4, 4:5, 21:9, 9:21. Defaults to 1:1 if omitted.
seed No Integer. Reuse a seed to make results reproducible across calls.

Full parameter reference lives on the model page; current per-image pricing is on the pricing page — check there rather than hardcoding a number, since usage-based rates change.

Production write-up

Callbacks over polling. For anything beyond a quick script, skip the poll loop and add callback.url (plus "when": "final") to the task-creation body — hiapi POSTs the result to your endpoint once the task finishes, exactly the same payload shape you'd get from GET /v1/tasks/{taskId}. See Create Task for the callback field and signature-verification details.

{
  "model": "flux-2-klein-4b/text-to-image",
  "callback": {"url": "https://yourapp.com/hooks/hiapi", "when": "final"},
  "input": {"prompt": "a red fox walking through fresh snow, golden hour light"}
}

Idempotency. Set an Idempotency-Key header (up to 255 bytes) on your POST /v1/tasks call. Retrying the same request with the same key under the same account won't create a second task — you get the original taskId back. That's what makes it safe to retry a request that timed out on your side without double-billing.

Error handling. Two different failure shapes show up in practice, so check both:

  • A bad input (missing prompt, an out-of-range aspect_ratio, an unsupported field) returns HTTP 400 with {"error_code": "INVALID_REQUEST", "message": "..."}.
  • An invalid or unauthorized API key returns HTTP 401 with a different envelope: {"error": {"code": "permission_denied", "message": "...", "request_id": "..."}}.

Branch on the HTTP status first, then read whichever error field is present — don't assume one envelope shape for every failure.

Related resources

FAQ

Does flux-2-klein-4b/text-to-image support image-to-image? Not directly — that's a separate model, flux-2-klein-4b/image-to-image, with its own input schema.

What's the difference between flux-2-klein-4b and flux-2-klein-9b? Both are text-to-image endpoints in the same FLUX.2 [klein] family; 9b is the larger of the two. Check the 9b model page for its current pricing and parameters before switching.

Can I request multiple images in one call? No — the schema doesn't accept an n or count field. Send one request per image you need.

How long is the returned image URL valid? The output[0].url is a temporary link with its own expireAt timestamp; treat it as short-lived (roughly a week in testing) and download the bytes right after the task succeeds instead of storing the URL.

Why am I getting a 401 permission_denied error? Your key is missing, invalid, or doesn't have access to this model. Confirm you're sending Authorization: Bearer sk-... with a key from your dashboard, not a placeholder.

Do I need to run my own server to use this API? Only if you want callbacks. Polling GET /v1/tasks/{taskId} from a script, cron job, or serverless function works fine for low-volume use; switch to callback.url once you're generating at scale.

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