Unified Async API Introduction
/v1/tasks is the single entry point for every async generation model — image, video, and audio. One request format, one state machine, one callback contract. Switching models only means changing model and input.
-
Submit a task
POST /v1/taskswithmodelandinput. You get ataskIdright away while generation continues in the background. -
Get the result
Poll
GET /v1/tasks/:iduntil the task is terminal, or setcallback.urlat creation time and HiAPI pushes the result to you.
The fields of input are defined per model — see the relevant model page. Shared parameters such as model / route / callback are fully documented on Create a task.
Endpoints
Section titled “Endpoints”All requests use the same Base URL:
https://api.hiapi.ai| Method | Path | Purpose |
|---|---|---|
POST | /v1/tasks | Create a task, returns taskId |
GET | /v1/tasks | List tasks (paginated, newest first) |
GET | /v1/tasks/:id | Get task detail: status, output, or failure reason |
Request headers
Section titled “Request headers”The three endpoints share the following headers; Content-Type and Idempotency-Key apply only to POST /v1/tasks.
Authorization Bearer YOUR_API_KEY required Account API key. Required on every request.
Content-Type application/json optional Optional. The body is always parsed as JSON; if sent, only application/json is accepted.
Idempotency-Key order-42-submit optional Optional. Idempotency key — retries with the same key create the task only once.
Authentication
Section titled “Authentication”Carry your account API key in the Authorization header as Bearer YOUR_API_KEY. Keys are created and managed in the console — see Authentication.
Content type
Section titled “Content type”Content-Type is optional — the request body is always parsed as JSON. The rules in one table:
| Content-Type you send | Behavior |
|---|---|
| Header omitted | ✅ Processed normally |
application/json (parameters like charset are fine) | ✅ Processed normally |
Anything else (text/plain, form types, …) | ❌ 415 UNSUPPORTED_MEDIA_TYPE |
Idempotency key
Section titled “Idempotency key”Add an Idempotency-Key header to POST /v1/tasks (any UTF-8 string, up to 255 bytes) and network timeouts or client auto-retries can no longer create duplicate tasks or duplicate charges. Idempotency is scoped to the account that owns the API key — rotating keys mid-way doesn’t affect it.
| Scenario | Platform behavior |
|---|---|
| First submit | Creates the task, returns taskId |
| Same key + same body replayed | No new task — returns the original taskId with the header Idempotent-Replay: true |
| Same key + different body | 422 IDEMPOTENCY_KEY_MISMATCH — fix your key construction, do not retry |
| Same key while the first request is still in flight | 409 IDEMPOTENCY_KEY_PROCESSING — retry after Retry-After (5 seconds) |
| More than 24 hours after the first submit | Key expired — treated as a new request |
This covers idempotency in the submit direction (you retry; the platform creates the task only once). Idempotency of callback delivery (HiAPI may deliver twice; you deduplicate by taskId) is described in the Callbacks section below — the two are independent.
Status information
Section titled “Status information”Read the result of a call in three layers: the HTTP status (was this request accepted), the business error code (why it was rejected or failed), and the task status (how far the async generation has progressed).
HTTP status codes
Section titled “HTTP status codes”| Status | Meaning |
|---|---|
200 | Success (task detail returns 200 even when status=fail; the failure is in the body’s error) |
400 | Invalid request — see error_code below |
402 | Insufficient balance — the task is not created and nothing is charged; top up and retry |
404 | Task does not exist or does not belong to the current account |
409 | Idempotency key conflict: the first request with this key is still in flight; retry after Retry-After |
415 | Content-Type is not application/json; switch to application/json or drop the header, then retry |
422 | Idempotency key mismatch: same key with a different request body; fix your key construction, do not retry |
503 | Platform temporarily unavailable; retry later with exponential backoff |
Business error codes
Section titled “Business error codes”The synchronous failure response of POST /v1/tasks (error_code) and a terminal task’s error.code share this enum; codes marked “creation-only” appear only in synchronous responses, never in a terminal task’s error.code.
| code | Meaning | What to do |
|---|---|---|
INVALID_REQUEST | Invalid body (missing field / wrong type / bad callback.url / model rejects the input), or the idempotency key exceeds 255 bytes / is not valid UTF-8 | Fix the request; do not retry the same request |
UNSUPPORTED_MEDIA_TYPE | Content-Type carries a value other than application/json (HTTP 415, creation-only) | Switch to application/json or drop the header, then retry |
INSUFFICIENT_QUOTA | Insufficient account balance (HTTP 402, creation-only) — the task is not created and nothing is charged | Top up and retry; you can set balance alerts in the dashboard |
IDEMPOTENCY_KEY_PROCESSING | The first request with this Idempotency-Key is still in flight (HTTP 409, creation-only) | Retry after Retry-After (5 seconds) — see Idempotency key |
IDEMPOTENCY_KEY_MISMATCH | Same Idempotency-Key with a different request body (HTTP 422, creation-only) | Fix your key construction; do not retry |
MODEL_UNAVAILABLE | Model unavailable (disabled, no permission, temporarily unavailable) | Retry shortly, or switch models |
TASK_FAILED | Task failed | Retry once; contact support if persistent |
TASK_TIMEOUT | Task timed out | Retryable |
STORAGE_UNAVAILABLE | Output storage error | Retryable; contact support if persistent |
Failure responses look like:
{ "code": 400, "message": "invalid request", "data": null, "error_code": "INVALID_REQUEST"}Task status enum
Section titled “Task status enum”| status | Meaning | Returns output? |
|---|---|---|
queued | Enqueued, not started | No |
handling | Processing | No |
archiving | Done, output being prepared | No |
success | Terminal: complete, output available | Yes |
fail | Terminal: failed | No, returns error |
POST /v1/tasks ──► queued ──► handling ──► archiving ──► success (terminal) (200 / taskId) │ │ ▼ ▼ fail fail (terminal)
success / fail triggers the callback (if callback.url was set)The only terminal states are success / fail; they never convert to each other, and a taskId’s result is fixed once terminal.
Callbacks
Section titled “Callbacks”Async tasks support two ways to get results:
- Polling — after creating a task, request
GET /v1/tasks/:idat intervals untilstatusis terminal. - Callback (Webhook) — provide
callback.urlwhen creating the task, and HiAPIPOSTs to that URL when the task reaches a terminal state (successorfail).
The callback request:
- Method
POST, Content-Typeapplication/json - Body is identical to the
datafield ofGET /v1/tasks/:id(the task detail object) callback.whencurrently supports onlyfinal(bothsuccessandfailfire a callback)
Signature (optional, recommended)
Section titled “Signature (optional, recommended)”Set a “Webhook signing key” on the account settings page in the HiAPI console (shared secret, 16–256 chars; empty means no signing).
- Not set: callback requests carry no signature header.
- Set: each callback carries
X-HiAPI-Timestamp: Unix seconds (string)X-HiAPI-Signature:hex( HMAC_SHA256(secret, timestamp + "." + body) )
Receiver verification (Python pseudocode):
import hmac, hashlib
ts = request.headers["X-HiAPI-Timestamp"]sig = request.headers["X-HiAPI-Signature"]body = request.raw_body # raw bytes, not JSON-parsed
expected = hmac.new( secret.encode(), (ts + "." + body).encode(), hashlib.sha256,).hexdigest()
assert hmac.compare_digest(expected, sig), "bad signature"# Recommended: reject requests where abs(now - int(ts)) > 5 minutes (replay protection)Delivery retries and idempotency
Section titled “Delivery retries and idempotency”| Item | Behavior |
|---|---|
| Enqueue | Once, when the task reaches success or fail |
| Success | Receiver returns HTTP 2xx |
| Retry | Non-2xx / timeout / network error retries at immediately → +1 min → +5 min → +20 min, up to 4 attempts |
| Terminal | After 4 failed attempts no more retries; does not affect the task’s own state |
Terminal callbacks are delivered “at least once”, not “exactly once”. Deduplicate by taskId on your side.
This covers callback delivery idempotency (HiAPI may deliver twice; you deduplicate by taskId). Idempotency in the submit direction (you retry a request; the platform creates the task only once) is handled by the Idempotency-Key header — the two are independent.