# Images

> Generate images from a prompt with an image model.

**POST** `https://deference.si/v1/images`

Takes a model and a prompt and returns base64 images. The format is OpenRouter's Images API, not OpenAI's `images/generations`. Send the key as `Authorization: Bearer sk-df-...` or `x-api-key`.

Find image models at [`/models?type=image`](https://deference.si/models?type=image).

## Example

**curl**

```bash
curl https://deference.si/v1/images \
  -H "Authorization: Bearer $DEFERENCE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "recraft/recraft-v4.1-flash",
    "prompt": "A lighthouse on a cliff at dawn, flat illustration",
    "n": 1
  }' | jq -r '.data[0].b64_json' | base64 --decode > lighthouse.png
```

**Python**

```python
import base64
import os
import requests

response = requests.post(
    "https://deference.si/v1/images",
    headers={"Authorization": f"Bearer {os.environ['DEFERENCE_API_KEY']}"},
    json={
        "model": "recraft/recraft-v4.1-flash",
        "prompt": "A lighthouse on a cliff at dawn, flat illustration",
        "n": 1,
    },
    timeout=180,
)
response.raise_for_status()
for index, image in enumerate(response.json()["data"]):
    with open(f"image-{index}.png", "wb") as file:
        file.write(base64.b64decode(image["b64_json"]))
```

**TypeScript**

```typescript
import { writeFile } from "node:fs/promises";

const response = await fetch("https://deference.si/v1/images", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DEFERENCE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "recraft/recraft-v4.1-flash",
    prompt: "A lighthouse on a cliff at dawn, flat illustration",
    n: 1,
  }),
  signal: AbortSignal.timeout(180_000),
});
if (!response.ok) throw new Error(await response.text());

const { data } = await response.json();
for (const [index, image] of data.entries()) {
  await writeFile(`image-${index}.png`, Buffer.from(image.b64_json, "base64"));
}
```

## Request body

* `model` (string, required): An image model id.
* `prompt` (string, required): What to draw.
* `n` (integer): How many images, a whole number from 1 to 10. Defaults to 1. Any other value returns `400 invalid_parameter`.
* `aspect_ratio` (string): For example `16:9`. Accepted values depend on the model.
* `resolution` (string): For example `1K` or `2K`, on models that offer sizes.
* `size` (string): Pixel size, such as `1024x1024`, on models that take one.
* `quality` (string): Quality level, on models that offer it.
* `output_format` (string): `png`, `jpeg` or `webp`, on models that offer a choice.
* `input_references` (array): Reference images, on models that accept them.
* `stream` (boolean): Return server-sent events. Only OpenAI image models stream.

Other fields pass through to the provider, and fields a model does not support are ignored. `models`, `route`, `provider` and `plugins` that add a fee return 400 `unsupported_parameter`. Deference replaces `user` with an account tag.

## Response

```json
{
  "created": 1760000000,
  "data": [{ "b64_json": "iVBORw0KGgo...", "media_type": "image/png" }],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0,
    "cost": 0.007
  }
}
```

`b64_json` is shortened here. `media_type` tells you the file type to save. `usage.cost` is the provider's cost in dollars, before Deference's platform fee. What you are charged is in Activity, and on non-streamed responses in `x-deference-cost`, in micro-dollars (1,000,000 is $1).

## Streaming

On models that stream, `stream: true` returns `image_generation.partial_image` events as the image forms, then `image_generation.completed` with the final image and usage, then `[DONE]`. An `error` event can replace either.

## Billing

* Each requested image holds at least $0.20, or more when the model's image price is higher. If the hold does not fit, the request returns `402`: ask for fewer images or add credit.
* A success is charged the provider's cost plus the 5% platform fee, and the charge is final at once. A success that reports no cost is charged the whole hold.
* A failed generation is charged only what the provider reports for it, usually nothing. A timeout is charged the whole hold, because the provider may still have generated the image.
* Free credit never pays for images. An account with only free credit gets `402 free_credit_not_eligible`.

## Limits

| Limit              | Value                                     | When exceeded                                                             |
| ------------------ | ----------------------------------------- | ------------------------------------------------------------------------- |
| Request body       | 64 MB                                     | `413 request_too_large`                                                   |
| Time to generate   | 120 seconds once the request is forwarded | `504 upstream_timeout`, charged the hold. A stream is cut off where it is |
| Images per request | 10                                        | `400 invalid_parameter`                                                   |

Generation can take over a minute, so set a client timeout of at least 180 seconds.

## Also from chat

Some chat models, such as Gemini and GPT image models, generate images inside a chat reply. Send `modalities: ["image", "text"]` to [Chat completions](https://deference.si/docs/api-reference/chat-completions). Image-only models, such as Recraft and FLUX, need this endpoint.
