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

# Image Generation

> How to generate images with OpenRouter's dedicated Image API

export const API_KEY_REF = '<OPENROUTER_API_KEY>';

OpenRouter provides a dedicated Image API for generating images from text prompts (and optional reference images). The API covers model discovery, per-endpoint capabilities, and generation. You can browse available models and pricing on the [models page filtered by image output](https://openrouter.ai/models?output_modalities=image).

## Model Discovery

### Via the Image Models API

The dedicated image models endpoint lists every available image model with its capabilities:

```bash lines theme={null}
curl "https://openrouter.ai/api/v1/images/models"
```

Each entry in the `data` array includes:

```json lines theme={null}
{
  "data": [
    {
      "id": "bytedance-seed/seedream-4.5",
      "name": "Seedream 4.5",
      "description": "A text-to-image model.",
      "created": 1692901234,
      "architecture": {
        "input_modalities": ["text", "image"],
        "output_modalities": ["image"]
      },
      "supported_parameters": {
        "resolution": { "type": "enum", "values": ["1K", "2K", "4K"] },
        "seed": { "type": "boolean" }
      },
      "supports_streaming": false,
      "endpoints": "/api/v1/images/models/bytedance-seed/seedream-4.5/endpoints"
    }
  ]
}
```

| Field                  | Description                                                                                                                                   |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `id`                   | Model slug to use in generation requests                                                                                                      |
| `architecture`         | Input and output modalities the model accepts                                                                                                 |
| `supported_parameters` | Union of capabilities across all endpoints. Each key is a request field name; the value is a [capability descriptor](#capability-descriptors) |
| `supports_streaming`   | Whether any endpoint supports native SSE streaming (`stream: true`)                                                                           |
| `endpoints`            | URL to the full per-endpoint records for this model                                                                                           |

### Per-Endpoint Records

Each model may be served by multiple providers. To see the definitive capabilities, pricing, and passthrough options per endpoint:

```bash lines theme={null}
curl "https://openrouter.ai/api/v1/images/models/bytedance-seed/seedream-4.5/endpoints"
```

```json lines theme={null}
{
  "id": "bytedance-seed/seedream-4.5",
  "endpoints": [
    {
      "provider_name": "Bytedance",
      "provider_slug": "bytedance",
      "provider_tag": "bytedance",
      "supported_parameters": {
        "resolution": { "type": "enum", "values": ["1K", "2K", "4K"] },
        "seed": { "type": "boolean" }
      },
      "allowed_passthrough_parameters": [],
      "supports_streaming": false,
      "pricing": [
        { "billable": "output_image", "unit": "image", "cost_usd": 0.05 }
      ]
    }
  ]
}
```

| Field                            | Description                                                                                                                                                                                                                                                        |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `provider_slug`                  | Use in `provider.options[slug]` to pass provider-specific parameters                                                                                                                                                                                               |
| `provider_tag`                   | Use to pin requests to a specific provider. `null` when provider-level routing is unavailable                                                                                                                                                                      |
| `supported_parameters`           | The definitive set of parameters *this* endpoint accepts (a subset of the model-level union)                                                                                                                                                                       |
| `allowed_passthrough_parameters` | Provider-specific keys accepted under `provider.options[provider_slug]`                                                                                                                                                                                            |
| `supports_streaming`             | Whether *this* endpoint supports native SSE streaming                                                                                                                                                                                                              |
| `pricing`                        | Billable pricing lines for this endpoint. Each entry has `billable` (e.g. `output_image`, `input_image`, `input_reference`), `unit` (`image`, `megapixel`, or `token`), `cost_usd`, and an optional `variant` tier (e.g. `2k`, `4k` for resolution-tiered pricing) |

### Capability Descriptors

The `supported_parameters` map uses typed descriptors to describe what each request field accepts:

| Type      | Shape                                          | Meaning                                      |
| --------- | ---------------------------------------------- | -------------------------------------------- |
| `enum`    | `{ type: "enum", values: ["1K", "2K", "4K"] }` | Discrete allowlist of accepted string values |
| `range`   | `{ type: "range", min: 0, max: 100 }`          | Any integer in `[min, max]` is valid         |
| `boolean` | `{ type: "boolean" }`                          | Supported (present) or unsupported (absent)  |

An absent key means the parameter is unsupported by that endpoint.

### Via the Models API

You can also discover image models through the general [Models API](/api/reference/models/get-models):

```bash lines theme={null}
curl "https://openrouter.ai/api/v1/models?output_modalities=image"
```

### On the Models Page

Visit the [Models page](/models) and filter by output modalities to find models with image generation capabilities.

## API Usage

Send a `POST` request to `/api/v1/images` with the model and prompt:

<Template
  data={{
API_KEY_REF,
MODEL: 'bytedance-seed/seedream-4.5'
}}
>
  <CodeGroup>
    ```python title="Python (requests)" lines theme={null}
    import requests
    import json

    url = "https://openrouter.ai/api/v1/images"
    headers = {
        "Authorization": f"Bearer {API_KEY_REF}",
        "Content-Type": "application/json"
    }

    payload = {
        "model": "{{MODEL}}",
        "prompt": "a red panda astronaut floating in space, studio lighting"
    }

    response = requests.post(url, headers=headers, json=payload)
    result = response.json()

    for image in result["data"]:
        # image["b64_json"] contains the base64-encoded image
        print(f"Generated image ({len(image['b64_json'])} chars)")
    ```

    ```typescript title="TypeScript (fetch)" lines theme={null}
    const response = await fetch('https://openrouter.ai/api/v1/images', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${API_KEY_REF}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: '{{MODEL}}',
        prompt: 'a red panda astronaut floating in space, studio lighting',
      }),
    });

    const result = await response.json();

    for (const image of result.data) {
      // image.b64_json contains the base64-encoded image
      console.log(`Generated image (${image.b64_json.length} chars)`);
    }
    ```

    ```bash title="cURL" lines theme={null}
    curl -X POST "https://openrouter.ai/api/v1/images" \
      -H "Authorization: Bearer $OPENROUTER_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "{{MODEL}}",
        "prompt": "a red panda astronaut floating in space, studio lighting"
      }'
    ```
  </CodeGroup>
</Template>

### Response Format

Images are returned as base64-encoded bytes. The `usage` field reports token counts and cost when available.

For raster PNG outputs (most models), `media_type` is omitted:

```json lines theme={null}
{
  "created": 1748372400,
  "data": [
    {
      "b64_json": "<base64-encoded-image>"
    }
  ],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 4175,
    "total_tokens": 4175,
    "cost": 0.04
  }
}
```

For vector outputs (e.g., SVG from Recraft vector models), the `media_type` field is included:

```json lines theme={null}
{
  "created": 1748372400,
  "data": [
    {
      "b64_json": "<base64-encoded-image>",
      "media_type": "image/svg+xml"
    }
  ],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 4175,
    "total_tokens": 4175,
    "cost": 0.04
  }
}
```

## Image Configuration Options

### Resolution and Aspect Ratio

Control output dimensions with `resolution`, `aspect_ratio`, or the convenience `size` shorthand:

```json lines theme={null}
{
  "model": "bytedance-seed/seedream-4.5",
  "prompt": "a landscape photo",
  "resolution": "2K",
  "aspect_ratio": "16:9"
}
```

* `resolution` — normalized tier (`512`, `1K`, `2K`, `4K`). Concrete pixel dimensions are derived per-provider.
* `aspect_ratio` — normalized ratio. Pass `auto` to let the provider choose. Common values include `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `4:5`, `5:4`, and extended ratios like `1:2`, `2:1`, `1:4`, `4:1`, `1:8`, `8:1`, `9:21`, `21:9`. Providers clamp to their supported subset — check the model's `supported_parameters` for accepted values.
* `size` — convenience shorthand. Pass a tier (`"2K"`) or explicit pixels (`"2048x2048"`) and it gets normalized for the provider. A tier size is equivalent to setting `resolution` and combines with `aspect_ratio`. An explicit pixel size is authoritative — a mismatched `resolution` or `aspect_ratio` alongside it is rejected with a 400.

Check the model's `supported_parameters` to see which values each endpoint accepts.

### Quality and Output Format

```json lines theme={null}
{
  "model": "openai/gpt-image-1",
  "prompt": "a product photo",
  "quality": "high",
  "output_format": "png",
  "background": "transparent"
}
```

* `quality` — `auto`, `low`, `medium`, or `high`. Providers without a quality knob ignore this.
* `output_format` — `png`, `jpeg`, `webp`, or `svg` (vectorization models only; SVG markup is base64-encoded in `b64_json`).
* `background` — `auto`, `transparent`, or `opaque`. `transparent` requires an alpha-capable format (png or webp).
* `output_compression` — 0–100 for webp/jpeg. Ignored for png.

### Multiple Images

Request up to 10 images per call with `n`:

```json lines theme={null}
{
  "model": "openai/gpt-image-1",
  "prompt": "a cute cat",
  "n": 4
}
```

Not all providers support `n > 1`. Check the model's `supported_parameters` for availability.

### Image-to-Image (Reference Images)

Pass reference images to guide generation via `input_references`:

```json lines theme={null}
{
  "model": "openai/gpt-image-1",
  "prompt": "make this scene look like a watercolor painting",
  "input_references": [
    {
      "type": "image_url",
      "image_url": {
        "url": "https://example.com/photo.jpg"
      }
    }
  ]
}
```

Reference images can be HTTP(S) URLs or base64 data URLs. The number of references accepted varies by provider.

### Provider-Specific Options

Pass provider-specific parameters through `provider.options`, keyed by the provider slug from the endpoints API:

```json lines theme={null}
{
  "model": "black-forest-labs/flux.2-pro",
  "prompt": "a dramatic portrait",
  "provider": {
    "options": {
      "black-forest-labs": {
        "steps": 40,
        "guidance": 3
      }
    }
  }
}
```

The `allowed_passthrough_parameters` field in each endpoint record lists which keys are accepted.

## Streaming Image Generation

Models that support native SSE streaming (`supports_streaming: true` in the discovery API) can return partial images as they're generated:

```json lines theme={null}
{
  "model": "openai/gpt-image-1",
  "prompt": "a detailed landscape",
  "stream": true
}
```

The response is an SSE stream with three event types:

**Partial image** — emitted as each partial render becomes available:

```
data: {"type":"image_generation.partial_image","partial_image_index":0,"b64_json":"<base64>"}
```

**Completed** — emitted when the final image is ready. For raster PNG outputs, `media_type` is omitted:

```
data: {"type":"image_generation.completed","b64_json":"<base64>","created":1748372400,"usage":{"prompt_tokens":16,"completion_tokens":272,"total_tokens":288,"cost":0.011}}
```

For vector outputs (e.g., SVG from Recraft vector models), `media_type` is included:

```
data: {"type":"image_generation.completed","b64_json":"<base64>","media_type":"image/svg+xml","created":1748372400,"usage":{"prompt_tokens":16,"completion_tokens":272,"total_tokens":288,"cost":0.011}}
```

The `usage` object in the completed event includes `cost` (USD), matching the buffered response shape.

**Error** — emitted if generation fails mid-stream:

```
data: {"type":"error","error":{"message":"Generation failed","code":"server_error"}}
```

The stream terminates with `data: [DONE]`.

<Template
  data={{
API_KEY_REF,
}}
>
  <CodeGroup>
    ```python title="Python (requests)" expandable lines theme={null}
    import requests

    url = "https://openrouter.ai/api/v1/images"
    headers = {
        "Authorization": f"Bearer {API_KEY_REF}",
        "Content-Type": "application/json"
    }

    response = requests.post(url, headers=headers, json={
        "model": "openai/gpt-image-1",
        "prompt": "a detailed landscape painting",
        "stream": True
    }, stream=True)

    for line in response.iter_lines():
        if line:
            decoded = line.decode("utf-8")
            if decoded.startswith("data: ") and decoded != "data: [DONE]":
                import json
                event = json.loads(decoded[6:])
                print(f"Event: {event['type']}")
    ```

    ```typescript title="TypeScript (fetch)" expandable lines theme={null}
    const response = await fetch('https://openrouter.ai/api/v1/images', {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${API_KEY_REF}`,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        model: 'openai/gpt-image-1',
        prompt: 'a detailed landscape painting',
        stream: true,
      }),
    });

    const reader = response.body?.getReader();
    const decoder = new TextDecoder();

    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      const chunk = decoder.decode(value);
      for (const line of chunk.split('\n')) {
        if (line.startsWith('data: ') && line !== 'data: [DONE]') {
          const event = JSON.parse(line.slice(6));
          console.log(`Event: ${event.type}`);
        }
      }
    }
    ```

    ```bash title="cURL" lines theme={null}
    curl -N -X POST "https://openrouter.ai/api/v1/images" \
      -H "Authorization: Bearer $OPENROUTER_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "model": "openai/gpt-image-1",
        "prompt": "a detailed landscape painting",
        "stream": true
      }'
    ```
  </CodeGroup>
</Template>

## Billing and Cancellation

Image generation billing is **all-or-nothing**. A generation is either completed and billed in full, or it fails and is not billed — there is no partial or fractional image billing. This differs from chat completions, where a cancelled stream still bills for the tokens produced before cancellation.

* **Completed generations** are billed for the full image output based on the endpoint's pricing.
* **Failed or cancelled generations** are not billed. When a generation does not complete, the request returns a `502 Bad Gateway` rather than a partial result, and no charge is recorded.

If a client disconnects mid-generation, the upstream provider may still finish rendering the image and charge OpenRouter for it. Regardless, the client only ever observes one of two outcomes: a fully-billed result, or an error. OpenRouter does not attempt to bill the user for work they did not receive.

For streaming requests, any partial preview images delivered before the stream ends do **not** create partial charges. Billing keys off completion of the final image, so a stream that terminates early (client disconnect or mid-stream error) is billed exactly as a failed generation: not at all.

## Request Parameters

| Parameter            | Type    | Required | Description                                                            |
| -------------------- | ------- | -------- | ---------------------------------------------------------------------- |
| `model`              | string  | Yes      | Model slug (e.g. `bytedance-seed/seedream-4.5`)                        |
| `prompt`             | string  | Yes      | Text description of the desired image                                  |
| `n`                  | integer | No       | Number of images to generate (1–10)                                    |
| `resolution`         | string  | No       | Resolution tier (`512`, `1K`, `2K`, `4K`)                              |
| `aspect_ratio`       | string  | No       | Aspect ratio (`1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `1:4`, `4:1`, etc.) |
| `size`               | string  | No       | Convenience shorthand — a tier or explicit pixels (`"2048x2048"`)      |
| `quality`            | string  | No       | `auto`, `low`, `medium`, or `high`                                     |
| `output_format`      | string  | No       | `png`, `jpeg`, `webp`, or `svg`                                        |
| `background`         | string  | No       | `auto`, `transparent`, or `opaque`                                     |
| `output_compression` | integer | No       | Compression level (0–100) for webp/jpeg                                |
| `seed`               | integer | No       | Seed for deterministic generation (where supported)                    |
| `stream`             | boolean | No       | Stream partial images via SSE                                          |
| `input_references`   | array   | No       | Reference images for image-to-image generation                         |
| `provider.options`   | object  | No       | Provider-specific parameters keyed by provider slug                    |

Use the [Image Models API](#via-the-image-models-api) to check which parameters each model and endpoint supports.
