> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.beatapi.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.beatapi.io/_mcp/server.

# Qwen Image 2.1

> Generate or edit an image with up to ten public HTTPS references, 1K or 2K output and optional transparent PNG or WebP.

`POST https://api.beatapi.io/v1/images/tasks`

Generate or edit an image with up to ten public HTTPS references, 1K or 2K output and optional transparent PNG or WebP.

### Supported modes

| Mode            | Required input              | Rules                                 |
| --------------- | --------------------------- | ------------------------------------- |
| Text to image   | `model`, `prompt`           | Omit `images`.                        |
| Reference image | `model`, `prompt`, `images` | Provide 1–10 public HTTPS image URLs. |

**Request rules:** auto follows the first reference image; without images it renders 1:1. enhance\_prompt defaults to true without images and false with images. A transparent background requires png or webp, not jpeg. Reference example URLs are placeholders; replace them with accessible HTTPS images. These examples describe the saved public contract, not completed model calls.

**Async flow:** Create the task, save `data.id`, then [poll the Task](/quick-guide#get-task-status) with `GET /v1/tasks/{task_id}`. On `succeeded`, read `data.output.media`. On `failed`, read `data.error_code` and `data.error_message`, then follow the [error and retry policy](/quick-guide#errors-and-retry-policy).

**Using a local file?** [upload a local input](/quick-guide#upload-an-input-file) first and pass the returned `data.url`.

## Authorization

`Authorization`   `string`   **required**

Send your BeatAPI API key as a Bearer token. Create one on the [Dashboard](https://beatapi.io/dashboard).

```
Authorization: Bearer <BEATAPI_API_KEY>
```

Keep permanent API keys on trusted servers. `Content-Type: application/json` is required for the request body. `Idempotency-Key` is optional when the endpoint exposes it and is recommended for safe retries with the exact same body.

## Request body

`aspect_ratio`   `enum<string>`   **optional**

auto follows the first reference image; without images it renders 1:1.

**Available options:** `auto`, `1:1`, `4:3`, `3:4`, `3:2`, `2:3`, `16:9`, `9:16`, `21:9`, `9:21`  \
**Default:** `"auto"`

---

`background`   `enum<string>`   **optional**

opaque or transparent. Transparent output requires PNG or WebP.

**Available options:** `opaque`, `transparent`  \
**Default:** `"opaque"`

---

`enhance_prompt`   `boolean`   **optional**

Rewrites the prompt before rendering. Defaults to true without images and false with images; no unconditional default.

---

`images`   `string[]`   **optional**

One to ten public HTTPS image URLs. Omit for text-to-image.

**Count:** 1 to 10 items

---

`model`   `enum<string>`   **required**

Must be qwen-image-2.1.

**Available options:** `qwen-image-2.1`

---

`output_format`   `enum<string>`   **optional**

Output file format. Use png or webp with transparent background; jpeg cannot retain alpha.

**Available options:** `png`, `webp`, `jpeg`  \
**Default:** `"png"`

---

`prompt`   `string`   **required**

Generation or reference-editing instructions, from 1 to 5000 characters.

**Length:** 1 to 5000 characters

---

`resolution`   `enum<string>`   **optional**

Output tier, 1K or 2K. A prompt cannot select a different tier.

**Available options:** `1K`, `2K`  \
**Default:** `"1K"`

---

`seed`   `integer`   **optional**

Optional integer from 0 to 2147483647; no -1 value and no documented default.

**Range:** 0 to 2147483647

## Request examples

### Text to image

```bash
curl --request POST \
  --url https://api.beatapi.io/v1/images/tasks \
  --header 'Authorization: Bearer <BEATAPI_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "qwen-image-2.1",
  "prompt": "A white porcelain crane above misty mountains, no text."
}'
```

### Transparent WebP

```bash
curl --request POST \
  --url https://api.beatapi.io/v1/images/tasks \
  --header 'Authorization: Bearer <BEATAPI_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "qwen-image-2.1",
  "prompt": "A single green glass perfume bottle, isolated on a transparent background, no text.",
  "resolution": "2K",
  "aspect_ratio": "1:1",
  "background": "transparent",
  "output_format": "webp",
  "enhance_prompt": true,
  "seed": 0
}'
```

### Reference image

```bash
curl --request POST \
  --url https://api.beatapi.io/v1/images/tasks \
  --header 'Authorization: Bearer <BEATAPI_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
  "model": "qwen-image-2.1",
  "prompt": "Keep the product shape and label from the reference, place it on a pale stone counter under soft morning light.",
  "images": [
    "https://example.com/product.png"
  ],
  "resolution": "1K",
  "aspect_ratio": "auto",
  "background": "opaque",
  "output_format": "png",
  "enhance_prompt": false,
  "seed": 42
}'
```

## Response

Contract example only, not an executed task or generated result. The 1K example amount comes from the bundled Qwen price catalogue; actual usage is returned by the task.

```json
{
  "data": {
    "id": "task_8K2qA",
    "object": "task",
    "task_kind": "image",
    "capability_id": "qwen-image-2.1",
    "capability_version": null,
    "media_type": "image",
    "model": "qwen-image-2.1",
    "status": "queued",
    "stage": "queued",
    "created_at": 1782210000,
    "updated_at": 1782210000,
    "completed_at": null,
    "output": null,
    "usage": {
      "credits_reserved": 0.03,
      "credits_charged": 0.03,
      "credits_settled": 0,
      "credits_refunded": 0
    },
    "request_id": "req_abc123",
    "error_code": null,
    "error_message": null
  }
}
```

## Errors

| Status | Meaning                                                                                                                                                                                                                                                              |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `400`  | Malformed JSON or a field, value or combination this endpoint does not accept (`bad_request`; the message names the field), or input refused by moderation (`content_policy_violation`). Not retryable unchanged.                                                    |
| `401`  | No API key (`missing_api_key`), or a key that is wrong, expired, disabled or exhausted (`invalid_api_key`; the message says which). Send it as `Authorization: Bearer <key>`; the key works with or without the `sk-` prefix. Not retryable.                         |
| `402`  | Insufficient balance (`insufficient_credits`). The account balance is zero or below the price of this request. Top up, then send it again; not retryable before that.                                                                                                |
| `403`  | The key or account is not permitted to make this call (`forbidden`), for example a model that is not available on free credit (a top-up unlocks it), a request from outside the key's IP allowlist, or a model outside the key's group. Not retryable.               |
| `409`  | The `Idempotency-Key` was already used with a different request body, or the first request with it is still being processed (`idempotency_conflict`). Not retryable unchanged.                                                                                       |
| `429`  | Too many requests (`rate_limit_exceeded`, including the free-model limits) or too many tasks processing at once (`user_concurrency_exceeded`). Retryable after `Retry-After` seconds (also `error.retry_after_seconds`).                                             |
| `500`  | Unexpected internal error (`internal_error`). Retryable; keep `request_id` for support if it persists.                                                                                                                                                               |
| `503`  | The request could not be completed (`processing_unavailable`, `processing_timeout`, `processing_failed` or `result_transfer_failed`). Nothing was charged. Retryable with backoff; `Retry-After` is sent when the wait is known. BeatAPI does not answer 502 or 504. |