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

# Nano Banana 2.1

> Generate or edit images with the successor to Nano Banana 2, from text and up to 14 public HTTPS reference images, with 1K, 2K, or 4K output.

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

Generate or edit images with the successor to Nano Banana 2, from text and up to 14 public HTTPS reference images, with 1K, 2K, or 4K output.

### Supported modes

| Mode            | Required input              | Rules                                                   |
| --------------- | --------------------------- | ------------------------------------------------------- |
| Text to image   | `model`, `prompt`           | Omit `images`.                                          |
| Reference image | `model`, `prompt`, `images` | Provide 1–14 public HTTPS PNG, JPEG or WebP image URLs. |

**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

`model`   `string`   **required**

Must be `nano-banana-2.1`.

**Value:** `nano-banana-2.1`

---

`prompt`   `string`   **required**

Generation or image-editing instructions.

**Length:** 1 to 5000 characters

---

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

Public HTTPS reference-image URLs in PNG, JPEG or WebP; each link is checked when the task is created, and one that is not such an image (an error page, a GIF, a 404) is refused with 400. Omit for text-to-image.

**Count:** 1 to 14 items

---

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

Output image aspect ratio.

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

---

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

Output resolution tier.

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

---

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

Output image file format.

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

## 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": "nano-banana-2.1",
  "prompt": "Editorial campaign image with crisp product typography.",
  "aspect_ratio": "4:5",
  "resolution": "2K",
  "output_format": "png"
}'
```

### 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": "nano-banana-2.1",
  "prompt": "Keep the product identity and create a polished campaign variation.",
  "images": [
    "https://media.beatapi.io/samples/smart-bottle.png"
  ],
  "aspect_ratio": "4:5",
  "resolution": "2K",
  "output_format": "png"
}'
```

## Response

A successful request returns HTTP `201`.

```json
{
  "data": {
    "id": "task_8K2qA",
    "object": "task",
    "task_kind": "image",
    "capability_id": "nano-banana-2.1",
    "capability_version": null,
    "media_type": "image",
    "model": "nano-banana-2.1",
    "status": "queued",
    "stage": "queued",
    "created_at": 1782210000,
    "updated_at": 1782210000,
    "completed_at": null,
    "output": null,
    "usage": {
      "credits_reserved": 0.04,
      "credits_charged": 0.04,
      "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. |