# Generate Image (OpenRouter)

`POST https://api.vultrinference.com/v1/images`

OpenRouter's image endpoint, for `images.generate()` in OpenRouter's SDKs (set the base URL to this gateway's `/v1`). It is the same implementation as `/v1/images/generations` and `/v1/images/edits`; what differs is the default answer: **base64** (`response_format` `b64_json`), because OpenRouter's SDKs require `b64_json` in every item. Send `input_references` to edit with a model that has reference editing.

Model-specific settings (`steps`, `guidance_scale`, `negative_prompt`) go at the top level, or under `provider.options` for an SDK that cannot add fields: OpenRouter's SDKs keep only the slugs on their closed list, so use `provider.options.stealth` there. A key the model does not declare is a 400 naming it.

Billing is output megapixels only (`usage.megapixels`, at the model's price per megapixel in `usage.cost`); reference images are not billed, and a failed request is not billed.

## Body (application/json)

- `prompt` (string, required): A text description of the desired image(s). The maximum length is the model's (4000 characters for `z-image-turbo`), counted as Unicode characters rather than bytes. [at most 4000 characters]
- `model` (string): The model to use for image generation. Defaults to `z-image-turbo`. `GET /v1/images/models` lists the image models currently served. An unknown model returns 404. [default z-image-turbo]
- `n` (integer): The number of images to generate. The images in one request are generated together, so changing `n` can change every image, including the first, for the same `seed`. [default 1, range 1–10]
- `response_format` (string): How the image comes back. `url` is a presigned link that expires after one hour; `b64_json` is the image inline as base64. The default is `b64_json` on `POST /v1/images` (OpenRouter's SDKs require it) and `url` on `/v1/images/generations` and `/v1/images/edits`. [url, b64_json]
- `size` (string): `WIDTHxHEIGHT` in pixels, or a resolution label (`1K`, `2K`, ...). For `z-image-turbo` any sides that are multiples of 16, an area from 65,536 to 4,194,304 pixels and a longer side at most 4 times the shorter (so `768x768` works and `1000x1000` is a 400). `auto` is the same as leaving it out. An `aspect_ratio` or `resolution` beside an explicit size must agree with it. [default 1024x1024]
- `width` (integer): Legacy spelling of `size`, kept because this API once documented it as ignored. Needs `height` and means `size` `"{width}x{height}"` under the same rules; a 400 if it disagrees with a `size` sent beside it. Use `size`.
- `height` (integer): See `width`.
- `aspect_ratio` (string): One of the model's aspect ratios (`GET /v1/images/models`). With `resolution`, or alone at the model's default resolution, it picks the size.
- `resolution` (string): One of the model's resolutions (`512`, `768`, `1K`, `1.5K`, `2K` for `z-image-turbo`; `4K` is a 400).
- `seed` (integer (int64)): Random seed. Must be an integer; fractional values are rejected rather than rounded. When omitted, each request uses a random seed. Repeating a request with the same seed and the same value for every other field, including `n` and `size`, returns the same images from the same model version on the same hardware. A model or engine update can change the images a seed produces, and replicas on different GPUs can differ in the last bits.
- `output_format` (string) [default png, png, jpeg, webp]
- `output_compression` (integer): The encoder quality for `jpeg` and `webp`, the compression level for `png`. The engine's own default applies when omitted. [range 0–100]
- `background` (string): `auto` and `opaque` give an opaque image. `transparent` only works on a model whose spec supports it (it also needs `output_format` `png` or `webp`); on `z-image-turbo` it is a 400. [default auto, auto, opaque, transparent]
- `input_references` (array of objects): OpenRouter's reference images, for a model with reference editing (`z-image-turbo` has none, so it is a 400 naming this field). Each is `{"type": "image_url", "image_url": {"url": "<https URL or base64 data URI>"}}`. The gateway fetches an https URL itself.
  - `type` (string, required) [image_url]
  - `image_url` (object, required)
    - `url` (string, required)
- `steps` (integer): The number of denoising steps (`z-image-turbo`: 1 to 50, default 8). Generation time grows roughly linearly with steps. Also accepted as `num_inference_steps`, and under `provider.options` (see `provider`). For `z-image-turbo` the last step of the schedule lands at zero noise and does not change the image, so `N` steps apply `N - 1` denoising updates. The default of 8 applies 7; 9 matches the 8 updates in the upstream Z-Image-Turbo reference. [range 1–50]
- `num_inference_steps` (integer): Alias of `steps`. [range 1–50]
- `guidance_scale` (number (float)): Classifier-free guidance strength. When omitted, the model's default is used: 0 for `z-image-turbo`, which is also the upstream recommendation for Turbo models. `0` turns guidance off. Values above 0 turn it on, which enables `negative_prompt` and roughly doubles the model work per step. Higher values are not a quality setting for `z-image-turbo`. [range 0–20]
- `negative_prompt` (string): Text describing what to steer the image away from. It only takes effect when `guidance_scale` is above 0; at the `z-image-turbo` default of 0 it is ignored. It changes the output, but does not guarantee that the described content is absent.
- `provider` (object): OpenRouter's provider preferences. The routing fields (`order`, `only`, `ignore`, `sort`, `allow_fallbacks`, ...) are accepted and ignored. `options` carries the model's own settings (`steps`, `guidance_scale`, `negative_prompt`) for clients that cannot add top-level fields. From OpenRouter's SDKs use `options.stealth`: they keep only the slugs on their closed list and drop any other, `vultr` included, without an error. The first form present wins, the top level before any option; a key the model does not declare is a 400 naming its path.
- `stream` (boolean): `true` answers `text/event-stream`: one `image_generation.completed` event (see the response), then `[DONE]`. Always base64. Not with `n` above 1.
- `partial_images` (integer): OpenAI's partial image count. Only 0 is accepted; a stream carries the finished image only. [range 0–0]
- `user` (string): Accepted and ignored.
- `session_id` (string): Accepted and ignored.
- `trace` (object): Accepted and ignored.

## Responses

- `200`: OK. With stream: true, text/event-stream carrying one image_generation.completed event and [DONE]. (create-image-response-payload)
- `400`: A field the model does not accept or a malformed input. The message names the field. (error-payload)
- `401`: The API key is missing, unknown or not active. Send it as Authorization: Bearer <key>. (error-payload)
- `404`: The model does not exist (error-payload)
- `413`: A reference image over 20 MB, or the images over 64 MB together (error-payload)
- `429`: Too many requests for this model from your subscription in the last minute, or too many running at once. Wait for Retry-After, then retry. (error-payload)
- `503`: The model is temporarily unavailable (error-payload)
- `502`: The model answered without an image (error-payload)

## Example

```bash
curl https://api.vultrinference.com/v1/images \
  -H "Authorization: Bearer $VULTR_INFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "z-image-turbo",
    "prompt": "Studio photograph of a red ceramic teapot beside a blue cup on a wooden table.",
    "aspect_ratio": "16:9",
    "resolution": "1K",
    "provider": {
      "options": {
        "stealth": {
          "steps": 8
        }
      }
    }
  }'
```

```python
import os
import requests

response = requests.post(
    "https://api.vultrinference.com/v1/images",
    headers={"Authorization": f"Bearer {os.environ['VULTR_INFERENCE_API_KEY']}"},
    json={
        "model": "z-image-turbo",
        "prompt": "Studio photograph of a red ceramic teapot beside a blue cup on a wooden table.",
        "aspect_ratio": "16:9",
        "resolution": "1K",
        "provider": {
            "options": {
                "stealth": {
                    "steps": 8,
                },
            },
        },
    },
)
print(response.json())
```

```javascript
const response = await fetch("https://api.vultrinference.com/v1/images", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.VULTR_INFERENCE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "model": "z-image-turbo",
    "prompt": "Studio photograph of a red ceramic teapot beside a blue cup on a wooden table.",
    "aspect_ratio": "16:9",
    "resolution": "1K",
    "provider": {
      "options": {
        "stealth": {
          "steps": 8
        }
      }
    }
  }),
});
console.log(await response.json());
```
