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

# Image Generations

> Generate or edit images. Asynchronous — returns 202 with a job_id; poll GET /v1/jobs/{id} for the result.

Async endpoint. The request returns immediately with a `job_id`; the actual generation runs in the background and is charged on success only.

## Request body

<ParamField body="model" type="string" required>
  One of: `recraft-v4`, `recraft-v4-pro`, `recraft-v4-vector`, `recraft-v4-vector-pro`, `flux-2-pro`, `flux-kontext-pro`, `ideogram-v3`, `flux-1.1-ultra` (legacy), `recraft-v3` (legacy). See [Image Generation](/models/image-generation).
</ParamField>

<ParamField body="prompt" type="string" required>
  Text prompt describing the desired image. Maximum 4000 characters.
</ParamField>

<ParamField body="n" type="number" default="1">
  Number of images to generate. Range 1–4. Each image is billed at the model's per-image rate. Ignored by `flux-2-pro` (per-megapixel billing — `n=1` always).
</ParamField>

<ParamField body="size" type="string">
  Output dimensions or aspect ratio. Accepted forms: `"auto"`, `"WIDTHxHEIGHT"` (e.g. `"1024x1024"`), or an aspect string like `"16:9"`. Mapped to one of the canonical aspect ratios: `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `21:9`. Unrecognized sizes use the model default. For `flux-2-pro`, larger sizes increase the per-megapixel charge.
</ParamField>

<ParamField body="image_url" type="string">
  HTTPS URL of a single source image. **Required for `flux-kontext-pro`** (image-edit model). Optionally accepted by `flux-2-pro` for image-to-image generation. Ignored by other text-to-image models. A `flux-kontext-pro` request without `image_url` (or `image_urls`) returns `400 image_url_required`.
</ParamField>

<ParamField body="image_urls" type="string[]">
  Array of up to 10 HTTPS source image URLs for **multi-reference blending**. Currently supported by `flux-2-pro` only — first 6 entries are processed at high fidelity, entries 7–10 act as supplementary composition guides. When both `image_url` and `image_urls` are present, `image_urls` takes precedence. Arrays longer than 10 return `400 too_many_references`.
</ParamField>

<ParamField body="idempotency_key" type="string">
  Client-supplied key (≤128 chars) to make the request safe to retry. Repeated POSTs with the same `(api_key, idempotency_key)` pair return the same job — no duplicate charge, no duplicate generation.
</ParamField>

<ParamField body="extra" type="object">
  Pass-through model-specific parameters (e.g. `seed`, `style`). Forwarded to the underlying provider unchanged.
</ParamField>

## Response

`202 Accepted` for new jobs, `200 OK` if the same `idempotency_key` is replayed.

```json theme={null}
{
  "id": "f3a9c8b2e1d0a4b6c7d8e9f0",
  "object": "image.job",
  "status": "pending",
  "model": "flux-1.1-ultra",
  "created_at": "2026-04-25T10:00:00.000Z",
  "completed_at": null,
  "output": null,
  "error": null,
  "estimated_cost": 0.081,
  "charged_amount": null
}
```

<ResponseField name="id" type="string">Job ID. Use it to poll `GET /v1/jobs/{id}`.</ResponseField>
<ResponseField name="status" type="string">One of: `pending`, `processing`, `succeeded`, `failed`, `refunded`, `expired`.</ResponseField>
<ResponseField name="estimated_cost" type="number">Hold amount placed at submit time (USD). Refunded if the job fails.</ResponseField>
<ResponseField name="charged_amount" type="number | null">Final billed amount once the job succeeds. `null` until then.</ResponseField>

## Poll for the result

```
GET /v1/jobs/{id}
```

Same response shape. Poll every 1–2 seconds until `status` is `succeeded`, `failed`, `refunded`, or `expired`. Most images complete within 30 seconds; the runner times out at 5 minutes.

```json theme={null}
{
  "id": "f3a9c8b2e1d0a4b6c7d8e9f0",
  "object": "image.job",
  "status": "succeeded",
  "model": "flux-1.1-ultra",
  "created_at": "2026-04-25T10:00:00.000Z",
  "completed_at": "2026-04-25T10:00:14.220Z",
  "output": {
    "url": "https://blob.vercel-storage.com/.../image.jpg",
    "metadata": { "images": [{ "width": 1920, "height": 1080, "content_type": "image/jpeg" }] }
  },
  "error": null,
  "estimated_cost": 0.081,
  "charged_amount": 0.081
}
```

The `output.url` points to a Vercel Blob URL hosted by Kyma — the original upstream URL is rehosted so it remains stable after the upstream TTL expires.

## Errors

| Status | `error.code`                  | When                                                          |
| ------ | ----------------------------- | ------------------------------------------------------------- |
| `400`  | `invalid_model`               | Model is not a supported image model                          |
| `400`  | `invalid_prompt`              | Missing prompt or > 4000 chars                                |
| `400`  | `image_url_required`          | `flux-kontext-pro` called without `image_url` or `image_urls` |
| `400`  | `too_many_references`         | `image_urls` array contains more than 10 entries              |
| `401`  | `auth_error`                  | Missing or invalid API key                                    |
| `402`  | `insufficient_balance`        | Hold could not be placed                                      |
| `413`  | `invalid_request`             | Request body > 25 MB                                          |
| `429`  | `rate_limited`                | Tier limit exceeded                                           |
| `500`  | `db_error` / `provider_error` | Internal failure — hold is fully refunded                     |

When `status` becomes `failed` or `refunded`, no charge is made and the held funds are returned to your balance via a `hold_release` ledger entry.

## Examples

### Cinematic hero shot

```bash theme={null}
curl -X POST https://kymaapi.com/v1/images/generations \
  -H "Authorization: Bearer $KYMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-1.1-ultra",
    "prompt": "an architectural photo of a modernist house at dusk, long exposure",
    "size": "16:9"
  }'
```

### Image edit with kontext

```bash theme={null}
curl -X POST https://kymaapi.com/v1/images/generations \
  -H "Authorization: Bearer $KYMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-kontext-pro",
    "prompt": "replace the sky with a stormy sunset",
    "image_url": "https://example.com/source.jpg"
  }'
```

### Multi-reference blend with FLUX.2 Pro

```bash theme={null}
curl -X POST https://kymaapi.com/v1/images/generations \
  -H "Authorization: Bearer $KYMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "flux-2-pro",
    "prompt": "blend these references into one cohesive editorial scene",
    "image_urls": [
      "https://example.com/style-ref-a.jpg",
      "https://example.com/style-ref-b.jpg",
      "https://example.com/composition-c.jpg"
    ],
    "size": "16:9"
  }'
```

### Native vector (SVG) output

```bash theme={null}
curl -X POST https://kymaapi.com/v1/images/generations \
  -H "Authorization: Bearer $KYMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft-v4-vector",
    "prompt": "minimalist Greek psi symbol shaped like a wave, gold on navy"
  }'
```

The resulting `output.url` returns an SVG file (`Content-Type: image/svg+xml`) with editable paths and layers — open directly in Figma or Illustrator.

### Idempotent retry

```bash theme={null}
curl -X POST https://kymaapi.com/v1/images/generations \
  -H "Authorization: Bearer $KYMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ideogram-v3",
    "prompt": "minimalist coffee bag label that reads KYMA ROAST",
    "idempotency_key": "order-78421-asset-1"
  }'
```

Replaying this exact request returns the same job — no new charge.
