> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Image Generation

> Generate images synchronously or asynchronously with the native AIHubMix image protocol, query tasks, and download results.

> [!NOTE]
>
> [Model Schema API](https://docs.aihubmix.com/en/api/async-tasks.md#model-schema)

## Quickstart

The native image endpoint is synchronous by default. Set the Boolean field `async` to `true` to create a background task. This example uses `qwen-image-2.0`.

```bash Create task theme={null}
curl -X POST https://aihubmix.com/ai/v1/images/generations \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "prompt": "A flower shop with delicate windows, warm sunlight streaming in",
    "n": 1,
    "size": "1024x1024",
    "async": true
  }'
```

```json Create response theme={null}
{
  "id": "task_01K0ABCDEF",
  "object": "image",
  "model": "qwen-image-2.0",
  "status": "in_progress",
  "output": [],
  "error": null,
  "created_at": 1784707200,
  "completed_at": null,
  "expires_at": null
}
```

```bash Query task theme={null}
curl https://aihubmix.com/ai/v1/images/{id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

```bash Download result theme={null}
curl "{content_url}" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  --output result.png
```

## How Do You Discover Async Media Models and Get Their Schemas?

The discovery flow has two steps. First, retrieve text-to-image or text-to-video models that support the async APIs from the public model catalog. Then use a model's `model_id` to retrieve the request Schema for its endpoints.

### List Models That Support the Async APIs

The model catalog uses the same data source as Playground. Use `type=image_generation` for text-to-image models and `type=video` for text-to-video models. Adding `schema_checked=true` limits the list to models with a published and reviewed request Schema.

```bash theme={null}
# Text-to-image models
curl "https://aihubmix.com/api/v1/models?type=image_generation&schema_checked=true&sort_by=order"

# Text-to-video models
curl "https://aihubmix.com/api/v1/models?type=video&schema_checked=true&sort_by=order"
```

Both requests use the same endpoint. The `type` filter currently accepts one value, so request each model type separately.

The response has the shape `{success, message, data}`. The following fields in `data` are relevant to async media integrations.

| Field | Description |
| - | - |
| `data[].model_id` | Model ID used in generation requests and subsequent Schema requests |
| `data[].model_name` | Model display name |
| `data[].types` | Comma-separated model types; a model may include both `image_generation` and `llm` |
| `data[].input_modalities` | Comma-separated input modalities |
| `data[].schema_checked` | `true` when the request Schema has been published and reviewed |

```json theme={null}
{
  "success": true,
  "message": "",
  "data": [
    {
      "model_id": "qwen-image-2.0",
      "model_name": "Qwen Image 2.0",
      "types": "image_generation",
      "input_modalities": "text,image",
      "schema_checked": true
    }
  ]
}
```

### Get the Request Schema for One Model

Supported fields, enumerations, and numeric ranges can vary by model. Before submitting an image or video request, use the public endpoint below to retrieve the available endpoints and request JSON Schemas for the selected model.

```bash theme={null}
# Text-to-image model
curl "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints"

# Text-to-video model
curl "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints"
```

The response has a `modality` of `image` or `video`. Each item in the `endpoints` array describes one available calling protocol.

| Field | Description |
| - | - |
| `default_endpoint` | Default endpoint identifier for the model |
| `endpoints[].endpoint` | Endpoint identifier |
| `endpoints[].method` | HTTP method, such as `POST` |
| `endpoints[].path` | Request path |
| `endpoints[].content_types` | Content types accepted by the endpoint |
| `endpoints[].lifecycle` | Sync or async mode, polling path, and status values |
| `endpoints[].request.schema` | Complete request JSON Schema for this model and endpoint, including required fields and value constraints |

A model may return both `/ai/v1` endpoints and OpenAI-compatible `/v1` endpoints. OpenAI-compatible endpoints may not yet support the latest models, so prefer the `/ai/v1` endpoints. For async task APIs, select the item whose `path` is `/ai/v1/images/generations` or `/ai/v1/videos`, then use its `request.schema`. Do not depend on the position of an item in the `endpoints` array.

The following commands extract the request Schema for each async task endpoint.

```bash theme={null}
# Text-to-image
curl -s "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/images/generations") | .request.schema'

# Text-to-video
curl -s "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/videos") | .request.schema'
```

The endpoint returns `404 model_not_found` when the model does not exist or has no discoverable endpoints. It returns `500 endpoints_unavailable` when endpoint data is temporarily unavailable.

***

## How Do You Create Image Tasks?

### Synchronous Images

When `async` is omitted or set to `false`, the endpoint waits for generation to finish and returns a task object:

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/images/generations \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "prompt": "A flower shop with delicate windows, warm sunlight streaming in",
    "n": 1,
    "size": "1024x1024",
    "response_format": "url"
  }'
```

Synchronous image tasks also save a task record. If the client connection is interrupted or the creation response is lost, use `GET /ai/v1/images` to find the corresponding task.

### Asynchronous Images

When `async` is set to the Boolean value `true`, the endpoint returns a task object immediately and generation continues in the background:

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/images/generations \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "prompt": "A flower shop with delicate windows, warm sunlight streaming in",
    "n": 2,
    "size": "1024x1024",
    "async": true
  }'
```

Use `GET /ai/v1/images/{id}` to query an asynchronous image task. After completion, request the `content_url` from each `output` item directly. The URL already contains the corresponding image `result_id`.

> [!NOTE]
>
> `async` in an image request must be a Boolean. `webhook_url` and
> `webhook_events_filter` can only be used with `async: true`.

### Standard Image Fields

| Field | Type | Required | Description |
| - | - | - | - |
| `model` | string | Yes | Model name |
| `prompt` | string | Yes | Image description; must not be empty |
| `n` | integer/null | No | Number of images, minimum `1`, default `1` |
| `size` | string/null | No | `{width}x{height}`, for example `1024x1024` |
| `aspect_ratio` | string/null | No | Aspect ratio; mutually exclusive with `size` |
| `seed` | integer/null | No | Random seed |
| `negative_prompt` | string/null | No | Negative prompt |
| `image` | string/object | No | One input image as a URL, Data URI, Base64 value, or `{url}` object |
| `images` | array/null | No | Multiple input images |
| `mask` | string/object | No | Image-editing mask |
| `output_format` | string/null | No | `png`, `jpeg`, or `webp`; default `png` |
| `response_format` | string/null | No | `url` or `b64_json`; default `url` |
| `async` | boolean | No | Set to `true` for asynchronous execution |
| `webhook_url` | string | No | HTTPS callback URL, up to 512 characters |
| `webhook_events_filter` | string\[] | No | A non-empty subset of `completed`, `failed`, and `cancelled` |
| `extra` | object/null | No | Model-specific extension parameters |

***

## Media Task Object

Image and video endpoints return the following structure:

```json theme={null}
{
  "id": "task_01K0ABCDEF",
  "object": "image",
  "model": "qwen-image-2.0",
  "status": "completed",
  "output": [
    {
      "index": 0,
      "type": "file",
      "b64_json": null,
      "content_url": "https://aihubmix.com/ai/v1/images/task_01K0ABCDEF/content/result_01K0XYZ"
    }
  ],
  "error": null,
  "created_at": 1784707200,
  "completed_at": 1784707320,
  "expires_at": null
}
```

| Field | Type | Description |
| - | - | - |
| `id` | string | Platform task ID |
| `object` | string | `image` or `video` |
| `model` | string | Model name |
| `status` | string | Current task status |
| `output` | array | Generated results; an empty array when no result is available |
| `error` | object/null | Failure details, which may contain `code`, `message`, and `upstream_detail` |
| `created_at` | integer | Creation time in Unix seconds |
| `completed_at` | integer/null | Final-status time in Unix seconds |
| `expires_at` | null | Media-specific endpoints currently return `null` |

Media `output` item:

| Field | Type | Description |
| - | - | - |
| `index` | integer | Result order, starting from `0` |
| `type` | string | Currently `file` |
| `content_url` | string/null | Result download URL |
| `b64_json` | string/null | Base64-encoded image result |

### Status Reference

| Status | Final | Description |
| - | - | - |
| `pending` | No | The platform has accepted the task and it is waiting to run |
| `in_progress` | No | The task is running |
| `completed` | Yes | The task is complete and `output` is available |
| `failed` | Yes | The task failed; see `error` for the reason |
| `cancelled` | Yes | The task was cancelled |

Clients can query every 15 seconds until the status becomes `completed`, `failed`, or `cancelled`. The 15-second interval is a client polling recommendation, not a server protocol limit.

***

## How Do You Query Media Tasks?

### Get Media Details

```bash theme={null}
# Image
curl https://aihubmix.com/ai/v1/images/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"

# Video
curl https://aihubmix.com/ai/v1/images/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

Media detail endpoints can return an updated task status, so use the corresponding image or video detail endpoint for media polling.

### List Media Tasks

If the creation response is lost, use the corresponding media list to recover the task ID:

```bash theme={null}
curl "https://aihubmix.com/ai/v1/images?limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| Parameter | Type | Default | Description |
| - | - | - | - |
| `after` | string | - | Pagination cursor; use `next_after` from the previous page |
| `limit` | integer | `20` | Number of items per page, maximum `100` |
| `order` | string | `desc` | `asc` for ascending order; all other values are treated as `desc` |

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "task_01K0ABCDEF",
      "object": "image",
      "model": "qwen-image-2.0",
      "status": "in_progress",
      "output": [],
      "error": null,
      "created_at": 1784707200,
      "completed_at": null,
      "expires_at": null
    }
  ],
  "has_more": true,
  "next_after": "task_01K0ABCDEF"
}
```

Media lists return task snapshots at query time and do not actively update task status.

***

## How Do You Use the Unified Task API?

The unified task API supports the following filters:

```bash theme={null}
curl "https://aihubmix.com/ai/v1/tasks?object=image&status=in_progress&limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| Parameter | Type | Default | Description |
| - | - | - | - |
| `object` | string | - | `llm`, `image`, or `video` |
| `status` | string | - | `pending`, `in_progress`, `completed`, `failed`, or `cancelled` |
| `model` | string | - | Exact filter by model name |
| `after` | string | - | Pagination cursor |
| `limit` | integer | `20` | Range from `1` to `100` |
| `order` | string | `desc` | `asc` or `desc` |

Unified task details:

```bash theme={null}
curl https://aihubmix.com/ai/v1/tasks/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

A unified `output` item for a media task:

```json theme={null}
{
  "index": 0,
  "result_id": "result_01K0XYZ",
  "type": "file",
  "content_type": "image/png",
  "content_url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content/result_01K0XYZ"
}
```

For a single-artifact task, request `/ai/v1/tasks/{id}/content` directly. For a multi-artifact task, request `/ai/v1/tasks/{id}/content/{result_id}`. Omitting the result ID returns `400 result_id_required`.

> [!NOTE]
>
> Unified task list, detail, and content endpoints are isolated by the Bearer
> token used to create the task. Other API Keys under the same account cannot
> read the task.

***

## How Do You Download Media Results?

### Download Images

After an image task is completed, request `output[].content_url` from the media task object for each result:

```bash theme={null}
curl "{content_url}" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  --output result.png
```

The media download path for images is `/ai/v1/images/{id}/content/{result_id}`. The media task object does not expose `result_id` separately, so clients can use `content_url` directly.

When `b64_json` is not empty, decode that field directly from Base64.

## How Do You Use Webhooks?

Asynchronous images and videos support task-level webhooks:

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/images/generations \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "prompt": "A tranquil garden at sunrise",
    "n": 1,
    "async": true,
    "size": "1024x1024",
    "webhook_url": "https://example.com/webhooks/aihubmix",
    "webhook_events_filter": ["completed", "failed"]
  }'
```

`webhook_url` can be up to 512 characters and cannot point to localhost, private networks, or other restricted addresses. When `webhook_events_filter` is omitted, the platform sends `completed`, `failed`, and `cancelled`. When explicitly provided, the array must not be empty or contain duplicates, and it must be used with `webhook_url`.

When `webhook_url` is omitted from the request, asynchronous image and video tasks try to use the default callback URL configured for the account. An invalid account default is ignored and does not prevent task creation.

### Callback Request

```json theme={null}
{
  "event_id": "evt_01K0ABCDEF",
  "event_type": "completed",
  "created_at": "2026-08-12T12:00:00Z",
  "data": {
    "task_id": "task_01K0ABCDEF",
    "status": "completed",
    "model": "qwen-image-2.0",
    "results": [
      {
        "url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content/result_01K0XYZ"
      }
    ]
  }
}
```

| Field | Description |
| - | - |
| `event_id` | Callback event ID, used for deduplication |
| `event_type` | `completed`, `failed`, or `cancelled` |
| `created_at` | Event time in RFC 3339 format |
| `data.task_id` | Platform task ID |
| `data.status` | Current final status |
| `data.model` | Model name |
| `data.results[].url` | Result download URL, when available on completion |
| `data.error` | Error details, when available on failure |

`results` appears only when results have been archived. Downloads still require a Bearer token.

### Retries and Deduplication

The platform uses at-least-once delivery, so the same event may be delivered more than once:

* HTTP `2xx` indicates successful receipt.
* HTTP `5xx`, network errors, or timeouts trigger a retry.
* HTTP `3xx` and `4xx` are not retried.
* Up to 6 delivery attempts are made, with retry intervals of 1, 4, 16, 64, and 256 seconds.

The receiver should store `event_id` and return `2xx` immediately when the same event is received again.

> [!WARNING]
>
> Task-level webhooks do not include a separate signing secret. If signature
> verification is required, configure an account-level webhook subscription and
> retain task detail queries as the method for confirming results.

***

## Error Responses and Error Codes

This section applies to `/ai/v1/images/*` and image tasks. For video errors, see the [video API](https://docs.aihubmix.com/en/api/aihubmix-video-generation.md#error-codes).

* **Current request failure**: A non-2xx HTTP status means the current creation, query, or download request failed. See [HTTP Request Failures](#http-errors).
* **Task execution failure**: The query returns HTTP 200, but the task has `status=failed`, with the cause recorded in its `error`. See [Task Execution Failures](#task-errors).
* **Output read failure for an individual list row**: The list returns HTTP 200, but a task includes `output_error`. See [Individual List Output Read Failures](#output-read-errors).

The `message` columns below contain the English response messages. The description columns explain their meaning and how to handle them. Parameter validation errors show generic messages; actual responses may identify specific fields and constraints. Clients should identify error types by `code` and should not depend on matching the full `message`.

```json theme={null}
{
  "error": {
    "message": "The task was not found.",
    "type": "invalid_request_error",
    "code": "task_not_found",
    "tid": "req_01K0ABCDEF"
  }
}
```

> [card] [Report an HTTP 5xx Error](https://console.aihubmix.com/support)
>
> When a request returns HTTP `5xx`, submit feedback and include `error.tid`.

### HTTP Request Failures

The HTTP statuses below apply when the current request fails directly. For execution failures after a task has been created, see the Task Execution Failures table below.

#### Request Parameters and Media Input

| HTTP | `code` | `message` | Description |
| - | - | - | - |
| 400 | `invalid_request` | `Invalid request. Check the request body and parameters.` | The request body, query parameters, or parameter types are incorrect. Follow the error message to check the request format, parameter types, and values. |
| 404 | `model_not_found` | `The requested model was not found. Check the model name.` | The requested model does not exist. Check the model name. |
| 400 | `schema_violation` | `One or more model parameters are invalid. Check the model schema and request values.` | The parameters do not meet the selected model's input requirements. Consult the model schema and correct the fields identified in the error message. |
| 400 | `unsupported_input_combination` | `This model does not support this operation or media input combination. Change the inputs or choose another model.` | The model does not support this combination of operation and media inputs. Change the input combination or choose a model that supports it. |
| 400 | `capability_not_supported` | `One or more requested parameters are not supported by this model. Change the parameters or choose another model.` | The requested parameters exceed the model's capabilities. Adjust them according to the error message or choose another model. |
| 400 | `unsupported_media_format` | `The {media_kind} format is not supported for this model.` | The model does not support this media format. Use a format listed in the error message or `error.details.allowed_mime_types`. If no list is provided, consult the model's input requirements. |
| 400 | `invalid_media_data` | `The media data is invalid. Provide valid media data.` | The media data is confirmed to be invalid, for example, corrupted base64 or a malformed data URI. Check data integrity and encoding, then provide valid media again. |
| 400 | `media_url_unreachable` | `The media URL could not be accessed. Make sure it is publicly accessible and returns valid media data.` | The media URL cannot be accessed or read. Check that it is valid, publicly accessible, and returns valid media content. |
| 400 | `invalid_media` | `The media input could not be processed. Check that its data or URL is valid and uses a supported format.` | The media input could not be processed, and a more specific cause cannot currently be confirmed. Check that the data or URL is valid and the model supports the format. |
| 413 | `image_too_large` | `The image is too large. Reduce the image size to {max_bytes} bytes or less and try again.` | The media content of the image task exceeds the current processing limit. Reduce its size according to `error.details.max_bytes` or the limit in the error message, then try again. |
| 413 | `request_too_large` | `The request body exceeds the 32 MiB limit. Reduce the request size and try again.` | The entire HTTP request body exceeds 32 MiB. Reduce the body actually sent, including text, parameters, and inline media encoding. |

**Size Limits**

* **Media size**: Image tasks that exceed the limit return `image_too_large`. See the error message or `error.details.max_bytes` for the exact limit.
* **Total request size**: `request_too_large` means the HTTP request body exceeds **32 MiB**, including text, parameters, and inline media encoding. When only a URL is provided, the URL itself counts toward the request body size, and the referenced file must still meet the model's media limits.
* **Actual size**: `error.details.actual_bytes` is provided only when the full size is confirmed. When media is read from a URL and reading stops at the limit, this field may be omitted.

**Supported Formats**

Supported formats depend on the selected model. First check `error.details.allowed_mime_types` or the format list in the error message. If no list is provided, consult the model's Schema.

**Message Placeholders**

* `{media_kind}`: The actual media type. When the type is confirmed, the messages for `invalid_media_data` and `media_url_unreachable` also use `image` or `video`.
* `{max_bytes}`: The size limit in bytes. If the image limit is unknown, the response is `The image is too large. Reduce the image size and try again.`
* `{allowed_formats}`: The list of allowed formats. Format error messages may append `Use one of: {allowed_formats}.`

#### Generation Requests and Returned Results

| HTTP | `code` | `message` | Description |
| - | - | - | - |
| 502 | `image_not_generated` | `The model provider completed the request but did not return an image. Adjust the request or choose another model, then try again. If the problem persists, contact support with the request ID.` | The model provider completed the request but returned no usable image. Adjust the request or choose another model, then try again. If failures persist, contact support with the request ID. Do not automatically repeat generation unconditionally just because the HTTP status is 502. |
| 422 | `output_blocked` | `The model provider blocked the generated output. Change the prompt or input content and try again.` | The model provider blocked the generated content and returned no usable image. Change the prompt or input content, then try again. No generation fee is charged for this attempt. |
| 400 | `upstream_rejected` | `The model provider rejected the request. Check the request parameters and content.` | The model provider rejected the request. This code alone does not establish a content policy violation. Check and change the request parameters and input content, then try again. |
| 502 | `upstream_bad_response` | `The model provider response could not be processed. Contact support with the request ID.` | The model provider returned a response that the platform could not process. This does not confirm that no result was generated. Contact support with the request ID; do not assume a parameter error or empty result. |
| 400 | `doubao_real_person_required` | `This request uses a real-person image. Complete real-person verification and use an active asset reference. See https://docs.aihubmix.com/cn/api/doubao-real-person-assets.` | Doubao returned a specific privacy rejection code for a real-person image. Complete real-person verification, then use an activated `asset://` asset. See the [real-person asset documentation](https://docs.aihubmix.com/en/api/doubao-real-person-assets.md). |
| 504 | `sync_timeout` | `Generation did not complete within the waiting period. Contact support with the request ID.` | Generation did not finish within the waiting period. A timeout does not prove that the request was not executed. Contact support with the request ID; do not query a task ID that was not returned to you. |
| 502 | `task_status_unavailable` | `The model provider task state could not be confirmed. Do not submit it again. Contact support with the task ID or request ID.` | The task was submitted to the model provider, but its subsequent state cannot be confirmed. Do not submit it again. Contact support with the request ID and include the task ID if available. |

#### Account and Permissions

| HTTP | `code` | `message` | Description |
| - | - | - | - |
| 401 | `authentication_failed` | `Authentication failed: invalid or missing API key.` | The API key is missing or invalid. Check the `Authorization` header and API key. |
| 402 | `insufficient_quota` | `Your account has insufficient quota. Add credits and try again.` | The account has insufficient quota. Add credits, then try again. |
| 403 | `permission_denied` | `You do not have permission to access this resource. Check the account, API key permissions, and IP restrictions.` | The account or API key does not have access. Check account permissions, API key permissions, and IP restrictions. |
| 403 | `async_not_enabled` | `Asynchronous tasks are not enabled. Please go to https://console.aihubmix.com/async-tasks to activate.` | Asynchronous tasks are not enabled for the account. Enable them using the console link in the response, then try again. |

#### Service Availability and Rate Limits

| HTTP | `code` | `message` | Description |
| - | - | - | - |
| 429 | `rate_limited` | `Too many requests. Reduce the request rate and try again later.` | Requests are too frequent. Reduce the request rate, then try again. |
| 429 | `upstream_rate_limited` | `Upstream service is rate limiting. Please retry later.` | The model provider is rate limiting requests. Try again later and avoid repeated immediate submissions. |
| 500 | `internal_error` | `An internal error occurred. Contact support with the request ID.` | The platform encountered an internal error. Contact support with the request ID. There is no need to repeatedly modify valid input. |
| 502 | `upstream_unreachable` | `Upstream service is temporarily unavailable. Please retry.` | The model provider is temporarily unavailable, possibly due to a connection failure, provider service error, or failure to read the response. This code alone cannot confirm whether a result was generated. If failures persist, contact support with the request ID. |
| 502 | `provider_unavailable` | `The model provider is unavailable. Contact support with the request or task ID.` | The model provider is unavailable. The table shows the default message; the actual response may provide more specific guidance. Use `code` to identify the error type. Contact support with the request ID. |
| 503 | `model_unavailable` | `The requested model is temporarily unavailable. Try again later or choose another model. If the problem persists, contact support with the request ID.` | The requested model is temporarily unavailable. Try again later or choose another model. If failures persist, contact support with the request ID. |
| 503 | `service_unavailable` | `The service is temporarily unavailable. Try again later. If the problem persists, contact support with the request ID.` | The service is temporarily unavailable. Retry the current operation later. If a download fails, retry the download without generating again. |

`provider_unavailable` indicates a positively identified model provider failure. A generic 429 or 4xx status alone cannot establish an account quota, content moderation, or parameter issue.

#### Task Queries and Result Downloads

| HTTP | `code` | `message` | Description |
| - | - | - | - |
| 404 | `task_not_found` | `The task was not found.` | The task does not exist or does not belong to the current account. Check the task ID and ensure the API key belongs to the account that created the task. |
| 404 | `result_not_found` | `The result was not found.` | The result does not exist or cannot be accessed. Check the task ID, result ID, and API key. A known invalid result ID does not become a 409 error just because the task is still running. |
| 400 | `invalid_cursor` | `The cursor is invalid or expired. Start a new list request.` | The pagination cursor is invalid or expired. Remove `after`, start again from the first page, and use the new cursor returned by that list. |
| 400 | `result_id_required` | `This task has multiple results. Specify result_id.` | The task has multiple results, but no `result_id` was specified. Select a result from the task output and specify its `result_id`. |
| 409 | `result_not_ready` | `The result is not available yet. Check the task status before downloading.` | The task is still queued or running, and the result is not ready. Continue checking task status and download when ready. There is no need to generate again. |
| 410 | `artifact_expired` | `The result has expired and is no longer available. Submit a new generation request.` | The result's retention period has ended. Expired results can no longer be downloaded. Submit a new generation request if needed. |
| 429 | `too_many_downloads` | `Download limit exceeded for this result.` | The download limit has been reached. Check any results you have already saved. Waiting alone does not guarantee that downloads will become available again. |

### Task Execution Failures

After a task is successfully created, generation failures are reported through `status=failed` and the task's `error`. A successful query still returns HTTP 200.

```json theme={null}
{
  "id": "task_01K0ABCDEF",
  "object": "image",
  "status": "failed",
  "output": [],
  "error": {
    "code": "image_not_generated",
    "message": "The model provider completed the request but did not return an image. Adjust the request or choose another model, then submit a new task."
  }
}
```

| Task `code` | `message` | Description |
| - | - | - |
| `image_not_generated` | `The model provider completed the request but did not return an image. Adjust the request or choose another model, then submit a new task.` | The model provider completed the request but returned no usable image. Adjust the request or choose another model, then submit a new task. Do not automatically repeat generation unconditionally. |
| `output_blocked` | `The model provider blocked the generated output. Change the prompt or input content and try again.` | The model provider blocked the generated content and returned no usable image. Change the prompt or input content, then submit a new task. No generation fee is charged for this attempt. |
| `output_policy_violation` | `Generated content was rejected by the content policy.` | The generated content did not pass moderation. Change the prompt or input content, then submit a new task. Existing content moderation billing rules apply; refer to billing records for historical charges. |
| `upstream_rejected` | `The model provider rejected the request. Check the request parameters and content.` | The model provider rejected the request. This code alone does not establish a content policy violation. Check and change the request parameters and input content, then submit a new task. |
| `upstream_bad_response` | `The model provider response could not be processed. Contact support with the task ID.` | The platform could not process the model provider's response. This does not confirm that no result was generated. Contact support with the task ID. |
| `task_status_unavailable` | `The model provider task state could not be confirmed. Do not submit it again. Contact support with the task ID.` | The task was submitted to the model provider, but its subsequent state cannot be confirmed. Do not submit it again. Contact support with the task ID. |
| `result_delivery_failed` | `The generated result could not be delivered. Do not resubmit automatically. Contact support with the task ID.` | A generated result exists, but the platform could not finish saving or delivering it. Do not automatically generate again. Contact support with the task ID to investigate the existing result first. |
| `upstream_rate_limited` | `Upstream service is rate limiting. Please retry later.` | The model provider is rate limiting requests. Try again later and avoid repeated immediate submissions. |
| `upstream_unreachable` | `Upstream service is temporarily unavailable. Please retry.` | A connection failure, provider service error, or failure to read the model provider's response occurred during task execution. This code alone cannot confirm whether a result was generated. If failures persist, contact support with the task ID. |
| `provider_unavailable` | `The model provider is unavailable. Contact support with the request or task ID.` | The model provider is unavailable. The table shows the default message; the actual response may provide more specific guidance. Use `code` to identify the error type. Contact support with the task ID. |
| `doubao_real_person_required` | `This request uses a real-person image. Complete real-person verification and use an active asset reference. See https://docs.aihubmix.com/cn/api/doubao-real-person-assets.` | Doubao returned a specific privacy rejection code for a real-person image. Complete real-person verification, then use an activated `asset://` asset. See the [real-person asset documentation](https://docs.aihubmix.com/en/api/doubao-real-person-assets.md). |
| `sync_timeout` | `Generation timed out. Contact support with the task ID.` | The generation task timed out. Contact support with the task ID. |
| `internal_error` | `An internal error occurred. Contact support with the task ID.` | The platform encountered an internal error. Contact support with the task ID. There is no need to repeatedly modify valid input. |

Media input errors may also appear in failed tasks. Their codes have the same meanings as in the media input table above; successful queries still return HTTP 200. For media size errors, the `message` ends with `submit a new task.`, instructing you to reduce the media size before submitting a new task.

`output_blocked` indicates an explicit block with no usable image returned, and no generation fee is charged for this attempt. Existing content moderation billing rules apply to `output_policy_violation`. Refer to billing records for historical charges.

### Individual List Output Read Failures

Individual rows in image and video task lists may include `output_error`:

```json theme={null}
{
  "output_error": {
    "code": "internal_error",
    "type": "server_error",
    "message": "The task output could not be read. Contact support with the request ID.",
    "tid": "req_01K0ABCDEF"
  }
}
```

This field indicates that the row's output could not be read for this request. The list still returns HTTP 200, with `output=[]` for that row. Its original `id`, `status`, `error`, and pagination remain unchanged, and other readable tasks are unaffected. Even when `status=completed`, check `output_error` before deciding whether the result can be read.

Contact support with `output_error.tid`. If the field has no `tid`, provide the request ID from the current response headers. This error does not change task status or charges, and does not trigger a Webhook.

Image and video lists preserve any `expires_at` already retrieved. Rows whose output could not be read in the unified `/ai/v1/tasks` list may return `expires_at=null`; the original retention period still applies to those results.

This handling applies only when an individual row's output cannot be read and no fallback is available. A query failure for the entire batch in the unified tasks API still returns an HTTP error; the same type of failure when reading task details still returns HTTP 500.

Related documentation: [Image API](https://docs.aihubmix.com/en/api/aihubmix-image-generation.md#error-codes) · [Video API](https://docs.aihubmix.com/en/api/aihubmix-video-generation.md#error-codes) · [Async Tasks](https://docs.aihubmix.com/en/api/async-tasks.md#error-codes)

## Complete example

These examples create an asynchronous task, poll it, and save every returned image.

```python Python theme={null}
import base64
import os
import time

import requests

base_url = "https://aihubmix.com"
headers = {
    "Authorization": f"Bearer {os.environ['AIHUBMIX_API_KEY']}",
    "Content-Type": "application/json",
}

response = requests.post(
    f"{base_url}/ai/v1/images/generations",
    headers=headers,
    json={
        "model": "qwen-image-2.0",
        "prompt": "A flower shop with delicate windows, warm sunlight streaming in",
        "n": 1,
        "size": "1024x1024",
        "async": True,
    },
    timeout=60,
)
response.raise_for_status()
task = response.json()

while task["status"] not in {"completed", "failed", "cancelled"}:
    time.sleep(15)
    response = requests.get(
        f"{base_url}/ai/v1/images/{task['id']}",
        headers=headers,
        timeout=30,
    )
    response.raise_for_status()
    task = response.json()

if task["status"] != "completed":
    raise RuntimeError(task.get("error") or task["status"])

for output in task["output"]:
    filename = f"result-{output['index']}.png"
    if output.get("b64_json"):
        content = base64.b64decode(output["b64_json"])
    else:
        result = requests.get(output["content_url"], headers=headers, timeout=120)
        result.raise_for_status()
        content = result.content
    with open(filename, "wb") as file:
        file.write(content)
```

```typescript TypeScript theme={null}
import { writeFile } from "node:fs/promises";

const baseUrl = "https://aihubmix.com";
const headers = {
  Authorization: `Bearer ${process.env.AIHUBMIX_API_KEY}`,
  "Content-Type": "application/json",
};

const created = await fetch(`${baseUrl}/ai/v1/images/generations`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    model: "qwen-image-2.0",
    prompt: "A flower shop with delicate windows, warm sunlight streaming in",
    n: 1,
    size: "1024x1024",
    async: true,
  }),
});
if (!created.ok) throw new Error(await created.text());
let task = await created.json();

const finished = new Set(["completed", "failed", "cancelled"]);
while (!finished.has(task.status)) {
  await new Promise((resolve) => setTimeout(resolve, 15_000));
  const polled = await fetch(`${baseUrl}/ai/v1/images/${task.id}`, { headers });
  if (!polled.ok) throw new Error(await polled.text());
  task = await polled.json();
}

if (task.status !== "completed") {
  throw new Error(JSON.stringify(task.error ?? task.status));
}

for (const output of task.output) {
  let content;
  if (output.b64_json) {
    content = Buffer.from(output.b64_json, "base64");
  } else {
    const result = await fetch(output.content_url, { headers });
    if (!result.ok) throw new Error(await result.text());
    content = Buffer.from(await result.arrayBuffer());
  }
  await writeFile(`result-${output.index}.png`, content);
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.