Skip to content
English

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.

  1. Submit a task

    POST /v1/tasks with model and input. You get a taskId right away while generation continues in the background.

  2. Get the result

    Poll GET /v1/tasks/:id until the task is terminal, or set callback.url at 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.

All requests use the same Base URL:

https://api.hiapi.ai
MethodPathPurpose
POST/v1/tasksCreate a task, returns taskId
GET/v1/tasksList tasks (paginated, newest first)
GET/v1/tasks/:idGet task detail: status, output, or failure reason

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.

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 is optional — the request body is always parsed as JSON. The rules in one table:

Content-Type you sendBehavior
Header omitted✅ Processed normally
application/json (parameters like charset are fine)✅ Processed normally
Anything else (text/plain, form types, …)415 UNSUPPORTED_MEDIA_TYPE

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.

ScenarioPlatform behavior
First submitCreates the task, returns taskId
Same key + same body replayedNo new task — returns the original taskId with the header Idempotent-Replay: true
Same key + different body422 IDEMPOTENCY_KEY_MISMATCH — fix your key construction, do not retry
Same key while the first request is still in flight409 IDEMPOTENCY_KEY_PROCESSING — retry after Retry-After (5 seconds)
More than 24 hours after the first submitKey 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.

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).

StatusMeaning
200Success (task detail returns 200 even when status=fail; the failure is in the body’s error)
400Invalid request — see error_code below
402Insufficient balance — the task is not created and nothing is charged; top up and retry
404Task does not exist or does not belong to the current account
409Idempotency key conflict: the first request with this key is still in flight; retry after Retry-After
415Content-Type is not application/json; switch to application/json or drop the header, then retry
422Idempotency key mismatch: same key with a different request body; fix your key construction, do not retry
503Platform temporarily unavailable; retry later with exponential backoff

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.

codeMeaningWhat to do
INVALID_REQUESTInvalid body (missing field / wrong type / bad callback.url / model rejects the input), or the idempotency key exceeds 255 bytes / is not valid UTF-8Fix the request; do not retry the same request
UNSUPPORTED_MEDIA_TYPEContent-Type carries a value other than application/json (HTTP 415, creation-only)Switch to application/json or drop the header, then retry
INSUFFICIENT_QUOTAInsufficient account balance (HTTP 402, creation-only) — the task is not created and nothing is chargedTop up and retry; you can set balance alerts in the dashboard
IDEMPOTENCY_KEY_PROCESSINGThe 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_MISMATCHSame Idempotency-Key with a different request body (HTTP 422, creation-only)Fix your key construction; do not retry
MODEL_UNAVAILABLEModel unavailable (disabled, no permission, temporarily unavailable)Retry shortly, or switch models
TASK_FAILEDTask failedRetry once; contact support if persistent
TASK_TIMEOUTTask timed outRetryable
STORAGE_UNAVAILABLEOutput storage errorRetryable; contact support if persistent

Failure responses look like:

{
"code": 400,
"message": "invalid request",
"data": null,
"error_code": "INVALID_REQUEST"
}
statusMeaningReturns output?
queuedEnqueued, not startedNo
handlingProcessingNo
archivingDone, output being preparedNo
successTerminal: complete, output availableYes
failTerminal: failedNo, 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.

Async tasks support two ways to get results:

  1. Polling — after creating a task, request GET /v1/tasks/:id at intervals until status is terminal.
  2. Callback (Webhook) — provide callback.url when creating the task, and HiAPI POSTs to that URL when the task reaches a terminal state (success or fail).

The callback request:

  • Method POST, Content-Type application/json
  • Body is identical to the data field of GET /v1/tasks/:id (the task detail object)
  • callback.when currently supports only final (both success and fail fire a callback)

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)
ItemBehavior
EnqueueOnce, when the task reaches success or fail
SuccessReceiver returns HTTP 2xx
RetryNon-2xx / timeout / network error retries at immediately → +1 min → +5 min → +20 min, up to 4 attempts
TerminalAfter 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.