> Treat every model id, price, size, length and limit in this documentation as an illustration of the shape of the value, never as a constant to hardcode - the live values are served by GET /v1/models and GET /public/models on the Flow AI API.

# Image Generation

> Create and edit images from a prompt.

Flow AI generates images through the OpenAI Images API: `POST /v1/images/generations` to create images from a prompt, and `POST /v1/images/edits` to change an image you send.

## Find an image model

* **On the [Models page](https://ai.hyperflow.fun/models)**, pick the **Image** type. Each model's page lists its sizes, qualities and price.
* **From the API**, `GET /v1/models` lists the models your key can call; image models have `"mode": "image"`.

```bash
curl https://ai.hyperflow.fun/v1/models \
  -H "Authorization: Bearer $HYPERFLOW_API_KEY"
```

## Generate an image

The samples use the OpenAI SDK set up as in the [Quickstart](/quickstart#using-the-openai-sdk).

**`cURL`**

```bash title="cURL"
curl https://ai.hyperflow.fun/v1/images/generations \
  -H "Authorization: Bearer $HYPERFLOW_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<image model id>",
    "prompt": "A paper boat on a calm lake, soft morning light",
    "n": 1,
    "size": "1024x1024",
    "quality": "medium"
  }'
```

**`Python`**

```python title="Python"
response = client.images.generate(
    model="<image model id>",
    prompt="A paper boat on a calm lake, soft morning light",
    n=1,
    size="1024x1024",
    quality="medium",
)
print(response.data[0].url)
```

**`TypeScript`**

```typescript title="TypeScript"
const response = await client.images.generate({
  model: '<image model id>',
  prompt: 'A paper boat on a calm lake, soft morning light',
  n: 1,
  size: '1024x1024',
  quality: 'medium',
})
console.log(response.data?.[0]?.url)
```

## Edit an image

`POST /v1/images/edits` takes one or more images and a prompt describing the change. Add a `mask` (a PNG the same size as the image) whose transparent areas mark where to edit. It's sent as a form upload, like OpenAI's.

**`cURL`**

```bash title="cURL"
curl https://ai.hyperflow.fun/v1/images/edits \
  -H "Authorization: Bearer $HYPERFLOW_API_KEY" \
  -F model="<image model id>" \
  -F image=@room.png \
  -F mask=@window-mask.png \
  -F prompt="Add a tall green plant by the window"
```

**`Python`**

```python title="Python"
response = client.images.edit(
    model="<image model id>",
    image=open("room.png", "rb"),
    mask=open("window-mask.png", "rb"),
    prompt="Add a tall green plant by the window",
)
print(response.data[0].url)
```

**`TypeScript`**

```typescript title="TypeScript"
import fs from 'node:fs'

const response = await client.images.edit({
  model: '<image model id>',
  image: fs.createReadStream('room.png'),
  mask: fs.createReadStream('window-mask.png'),
  prompt: 'Add a tall green plant by the window',
})
console.log(response.data?.[0]?.url)
```

## Options

| Parameter       | Generate | Edit | Notes                                                                                          |
| --------------- | -------- | ---- | ---------------------------------------------------------------------------------------------- |
| `model`         | ✓        | ✓    | Required                                                                                       |
| `prompt`        | ✓        | ✓    | Required. What to draw, or what to change                                                      |
| `image`         |          | ✓    | Required. The image or images to edit                                                          |
| `mask`          |          | ✓    | Transparent areas mark where to edit                                                           |
| `n`             | ✓        | ✓    | How many images. Each model has its own maximum                                                |
| `size`          | ✓        | ✓    | One of the model's sizes, such as `1024x1024`. Defaults to the model's default                 |
| `quality`       | ✓        | ✓    | One of the model's qualities, such as `low`, `medium`, `high`. Defaults to the model's default |
| `background`    | ✓        | ✓    | `transparent` or `opaque`, on models that support it                                           |
| `output_format` | ✓        | ✓    | `png`, `jpeg` or `webp`, on models that support it                                             |
| `style`         | ✓        |      | `vivid` or `natural`, on models that support it                                                |

Any other field is removed before the request reaches the model.

### Sizes, qualities and counts are checked first

Before anything is held, Flow AI checks `size`, `quality` and `n` against what the model offers. A value it doesn't offer is refused with a `400` that lists what it does offer:

```json
{
  "error": {
    "message": "<image model id> makes images of 1024x1024, 1536x1024, 1024x1536",
    "code": "invalid_request"
  }
}
```

The model makes exactly the size, quality and number of images you were held for.

## Response

Every image comes back as a **link**, in `data[].url`:

```json
{
  "created": 1782886429,
  "data": [
    { "url": "https://.../images/3f9c.../0.png" }
  ],
  "usage": { "input_tokens": 14, "output_tokens": 4160, "total_tokens": 4174 }
}
```

* Images are never returned as base64, so `response_format` has no effect.
* Flow AI stores each image before it answers, so the link works even after the model's host has dropped it. Download the images you want to keep.
* `usage` appears for models billed by tokens.

## Best practices

* **Be specific.** Subject, setting, style, lighting and framing all help: "a ceramic mug on an oak desk, top-down, soft window light" beats "a mug".
* **Start small.** Try prompts at low quality or a small size, then make the final image at the size you need.
* **Ask for one image at a time while exploring.** `n` multiplies the cost.
* **Keep your own copy.** Download images you need for the long term.

## Troubleshooting

**`400` naming sizes or qualities.** The model doesn't offer the `size`, `quality` or `n` you asked for. Use one from the message, or from the model's page.

**`400 ... does not take ... content` or `not available right now`.** The model can't take this request at the moment. Try another image model.

**`404 not_found`.** The model id is wrong, or it isn't an image model. Check `GET /v1/models`.

**`402 insufficient_balance`.** The request is held for every image at the size and quality you asked for; lower `n` or `quality`, or [deposit](https://ai.hyperflow.fun/console/funds).

## Billing

Each image model is priced one of two ways, shown on its page:

* **Per image**, by size and quality. A request is held for `n` images at the price for its size and quality.
* **By tokens**, for models that charge for the prompt and the image's tokens. A request is held for its prompt plus a reserve for each image.

Either way, you're charged what the model actually made, and the rest of the hold is released.