---
title: Image API
description: Generate images from text prompts and reference images across the Sume image model catalog.
---

Sume offers a dedicated Image API for generating images from text prompts and
optional reference images. The service covers model discovery, per-endpoint
capabilities, and generation features. You can explore available models and
pricing with `GET /v1/images/models`.

Parameters a given model actually accepts are published as capability
descriptors on the catalog, so you can discover what a model supports before
you call it. Behaviour that is specific to Sume is listed in
[Sume specifics](#sume-specifics).

```text
POST /v1/images
GET  /v1/images/models
GET  /v1/images/models/{model_id}/endpoints
```

This is the explicit-catalog surface. If you would rather have Sume pick the
model and manage the product semantics for you, use
[Image 1.0](/models/image) (`POST /v1/image-1.0/generate`) — it is unchanged by
this API.

## Model discovery

### Via the Image Models API

Access the image models endpoint to list available models with capabilities:

```bash
curl "https://api.sume.com/v1/images/models" \
  -H "Authorization: Bearer $SUME_API_KEY"
```

Key response fields include:

- **id**: Model slug for generation requests
- **architecture**: Input/output modalities supported
- **supported_parameters**: Union of capabilities across endpoints
- **supports_streaming**: Whether native SSE streaming is available
- **endpoints**: URL for per-endpoint records

```json
{
  "data": [
    {
      "id": "bytedance-seed/seedream-4.5",
      "name": "Seedream 4.5",
      "description": "Text-to-image and reference-guided image editing.",
      "created": 1748372400,
      "architecture": {
        "input_modalities": ["text", "image"],
        "output_modalities": ["image"]
      },
      "supported_parameters": {
        "prompt": { "type": "boolean" },
        "aspect_ratio": {
          "type": "enum",
          "values": ["1:1", "16:9", "9:16", "4:3", "3:4"]
        },
        "n": { "type": "range", "min": 1, "max": 4 },
        "input_references": { "type": "range", "min": 0, "max": 10 },
        "output_format": { "type": "enum", "values": ["png", "jpeg", "webp"] }
      },
      "supports_streaming": false,
      "endpoints": "/v1/images/models/bytedance-seed/seedream-4.5/endpoints"
    }
  ]
}
```

### Per-endpoint records

Access definitive capabilities and pricing for a model:

```bash
curl "https://api.sume.com/v1/images/models/bytedance-seed/seedream-4.5/endpoints" \
  -H "Authorization: Bearer $SUME_API_KEY"
```

Important fields:

- **provider_slug**: Use for provider-specific parameters
- **provider_tag**: Pin requests to specific providers
- **supported_parameters**: Definitive parameter set for this endpoint
- **allowed_passthrough_parameters**: Provider-specific keys
- **pricing**: Billable lines with cost information

```json
{
  "id": "bytedance-seed/seedream-4.5",
  "endpoints": [
    {
      "provider_name": "Sume",
      "provider_slug": "sume",
      "provider_tag": "sume",
      "supported_parameters": {
        "prompt": { "type": "boolean" },
        "aspect_ratio": {
          "type": "enum",
          "values": ["1:1", "16:9", "9:16", "4:3", "3:4"]
        },
        "n": { "type": "range", "min": 1, "max": 4 },
        "input_references": { "type": "range", "min": 0, "max": 10 },
        "output_format": { "type": "enum", "values": ["png", "jpeg", "webp"] }
      },
      "allowed_passthrough_parameters": [],
      "supports_streaming": false,
      "pricing": [{ "billable": "output_image", "unit": "image", "cost_usd": 0.033 }]
    }
  ]
}
```

Sume serves every catalog model through a single `sume` endpoint in v1, so the
model-level and endpoint-level `supported_parameters` are identical.

### Capability descriptors

Parameters use typed descriptors:

- **enum**: Discrete allowlist of string values
- **range**: Any integer within min/max bounds
- **boolean**: Supported (present) or unsupported (absent)

A request that sets a parameter the selected model does not list is rejected
with `400 unsupported_parameter` rather than silently dropped.

## API usage

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

**Python (requests):**

```python
import requests

url = "https://api.sume.com/v1/images"
headers = {
    "Authorization": f"Bearer {SUME_API_KEY}",
    "Content-Type": "application/json"
}

payload = {
    "model": "bytedance-seed/seedream-4.5",
    "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"]:
    print(f"Generated image: {image['url']}")
```

**TypeScript (fetch):**

```typescript
const response = await fetch('https://api.sume.com/v1/images', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${SUME_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'bytedance-seed/seedream-4.5',
    prompt: 'a red panda astronaut floating in space, studio lighting',
  }),
});

const result = await response.json();

for (const image of result.data) {
  console.log(`Generated image: ${image.url}`);
}
```

**cURL:**

```bash
curl -X POST "https://api.sume.com/v1/images" \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "bytedance-seed/seedream-4.5",
    "prompt": "a red panda astronaut floating in space, studio lighting"
  }'
```

### Response format

Images return as Sume-hosted URLs with usage data:

```json
{
  "created": 1748372400,
  "model": "bytedance-seed/seedream-4.5",
  "data": [
    {
      "url": "https://media.sume.com/img/01J.../0.png",
      "media_type": "image/png"
    }
  ],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0,
    "cost": 0.04
  }
}
```

For non-PNG formats:

```json
{
  "created": 1748372400,
  "model": "bytedance-seed/seedream-4.5",
  "data": [
    {
      "url": "https://media.sume.com/img/01J.../0.webp",
      "media_type": "image/webp"
    }
  ],
  "usage": {
    "prompt_tokens": 0,
    "completion_tokens": 0,
    "total_tokens": 0,
    "cost": 0.04
  }
}
```

`model` echoes the id you requested — `sume/auto` stays `sume/auto`. `cost` is
the USD amount billed to your wallet. Token counts are always `0` in v1 — image
models are metered per image, and per-token accounting is not plumbed through
yet.

### Long-running requests

`POST /v1/images` blocks for up to 30 seconds and returns the response above
with `200`. Most catalog models finish inside that budget.

If the generation is still running when the budget expires — or if you send
`mode: "async"`, or `mode: "webhook"` with a `webhook_url` — Sume returns `202`
with the standard job envelope instead:

```json
{
  "job": {
    "id": "job_01J...",
    "model": "bytedance-seed/seedream-4.5",
    "status": "queued",
    "status_url": "https://api.sume.com/v1/jobs/job_01J.../status",
    "result_url": "https://api.sume.com/v1/jobs/job_01J.../result"
  }
}
```

Poll `GET /v1/jobs/{id}/status` and fetch `GET /v1/jobs/{id}/result` for the
generated images. Those are the standard Sume job endpoints and return the
standard job result shape, not the image body above. See
[Jobs and results](/workflows/jobs-and-results).

Check the status code, not the body shape: `200` is the image response, `202` is
the job envelope. Slow configurations — 4K, high `quality`, large `n` — are the
ones most likely to degrade to `202`.

## Image configuration options

### Resolution and aspect ratio

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

- **resolution**: Normalized tier (512, 1K, 2K, 4K)
- **aspect_ratio**: Normalized ratio (1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 4:5, 5:4, 1:2, 2:1, 1:4, 4:1, 1:8, 8:1, 9:21, 21:9); use "auto" for provider choice
- **size**: Shorthand for a resolution tier. Explicit pixel sizes (e.g. "2048x2048") are not served in v1 — set `resolution` and `aspect_ratio` instead

A model only accepts the values its catalog descriptors list, so read
`supported_parameters` before pinning a tier or ratio.

On edit and image-to-image calls, prefer `aspect_ratio: "auto"` to match the
reference — omitting the field is not the same as `auto`.

### Quality and output format

```json
{
  "model": "openai/gpt-image-2",
  "prompt": "a product photo",
  "quality": "high",
  "output_format": "png"
}
```

- **quality**: auto, low, medium, or high
- **output_format**: png, jpeg, webp, or svg
- **background**: auto, transparent, or opaque — not served in v1
- **output_compression**: 0–100 for webp/jpeg — not served in v1

`background`, `output_compression`, and `seed` are part of the schema but no
model advertises them yet, so sending one returns `400 unsupported_parameter`.
For transparent stills today, use [Image 1.0](/models/image) with
`transparency: true`.

### Multiple images

```json
{
  "model": "openai/gpt-image-2",
  "prompt": "a cute cat",
  "n": 4
}
```

Request up to 10 images per call with `n`. Per-model ceilings are lower — read
the `n` range descriptor from the catalog.

### Image-to-image (reference images)

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

Reference URLs must be public HTTPS. Localhost, private-network, and non-HTTPS
URLs are rejected before submission. Models whose `input_references` descriptor
is `{"min": 0, "max": 0}` are text-to-image only and reject references.

### Provider routing

```json
{
  "model": "bytedance-seed/seedream-4.5",
  "prompt": "a red panda astronaut floating in space",
  "provider": {
    "only": ["sume"],
    "allow_fallbacks": false
  }
}
```

Routing fields:

- **only**: Allow only listed provider slugs
- **order**: Try providers in listed order
- **ignore**: Exclude listed provider slugs
- **sort**: Sort by price, throughput, or latency
- **allow_fallbacks**: Stop after primary provider if false

Sume publishes a single `sume` endpoint per model in v1, so `only` and `order`
accept only `"sume"`; `ignore`, `sort`, and `allow_fallbacks` are accepted and
have no effect. Any other slug returns `400 provider_not_available`.

### Provider-specific options

```json
{
  "model": "black-forest-labs/flux.2-pro",
  "prompt": "a dramatic portrait",
  "provider": {
    "options": {
      "sume": {}
    }
  }
}
```

`allowed_passthrough_parameters` is empty for every endpoint in v1, so
`provider.options` must be omitted or empty.

## Streaming image generation

Sume does not serve native SSE streaming in v1. Every catalog row reports
`supports_streaming: false`, and `stream: true` returns
`400 streaming_not_supported`. The field is in the schema so clients can adopt
streaming without a code change when it ships.

In the meantime, submit with `mode: "async"` and read `GET /v1/jobs/:id/events`
for progress, or take a [webhook](/workflows/webhooks) for the terminal event.
`mode: "subscribe"` is **not** a progress stream — it is an alias of `sync` and
buys you one bounded 30-second wait. See
[what "subscribe" means](/workflows/jobs-and-results#subscribe-means-three-different-things).

## 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.

- **Completed generations** are fully billed based on endpoint pricing
- **Failed or cancelled generations** are not billed; failed requests return 502 Bad Gateway
- **Client disconnects**: requests ending early are billed as failed generations (not at all)

Endpoint `pricing` lines are the amount charged to your wallet — Sume's margin
is already applied, so `cost_usd × n` is what you pay.

## Request parameters

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `model` | string | Yes | Model slug (e.g., bytedance-seed/seedream-4.5), or `sume/auto` |
| `prompt` | string | Yes | Text description of 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 | Shorthand for a resolution tier. Explicit pixels not served in v1 |
| `quality` | string | No | auto, low, medium, or high |
| `output_format` | string | No | png, jpeg, webp, or svg |
| `background` | string | No | auto, transparent, or opaque (not served in v1) |
| `output_compression` | integer | No | Compression level (0–100) for webp/jpeg (not served in v1) |
| `seed` | integer | No | Seed for deterministic generation (not served in v1) |
| `stream` | boolean | No | Stream partial images via SSE (not served in v1) |
| `input_references` | array | No | Reference images for image-to-image |
| `provider.only` | string[] | No | Allow only these provider slugs |
| `provider.order` | string[] | No | Try provider slugs in this order |
| `provider.ignore` | string[] | No | Exclude these provider slugs |
| `provider.sort` | string or object | No | Sort by price, throughput, or latency |
| `provider.allow_fallbacks` | boolean | No | Allow fallback provider on failure |
| `provider.options` | object | No | Provider-specific parameters by slug |
| `metadata` | object | No | Caller metadata stored on the job; not sent to the provider |
| `mode` | string | No | `sync` (default on this route), `async`, `subscribe`, `webhook` |
| `webhook_url` | string | No | Public HTTPS callback for terminal delivery in webhook mode |
| `wait_timeout_seconds` | integer | No | 0–30, default 30 on this route. Blocking wait budget for `sync` / `subscribe` |

## Sume specifics

| Area | Behavior |
|---|---|
| `sume/auto` | Sume-only `model` value. Sume picks the family for you and never discloses which one ran: it is not listed in `GET /v1/images/models`, and `job.model` stays `sume/auto`. |
| Result payload | `data[].url` (Sume-hosted, signed) rather than inline base64. Sume already mirrors generated media, and URLs keep responses small. |
| Async | Sume caps a blocking wait at 30s. Generations that exceed it — and `mode: "async"` / `"webhook"` — return the Sume job envelope with `202`, and the images are then read from the standard job result endpoint. |
| Provider | One `sume` endpoint per model in v1. Upstream provider identity is not disclosed, and multi-provider routing fields are accepted but inert. |
| `stream` | Accepted in the schema, rejected at runtime with `400 streaming_not_supported` until native SSE ships. |
| Catalog-gated parameters | `background`, `output_compression`, `seed`, and explicit pixel `size` are in the schema but advertised by no model in v1, so they return `400 unsupported_parameter`. |
| `usage` | `cost` is the billed USD amount. Token counts are `0` in v1. |
| Legacy ids | The bare Image Router ids (`gpt-image-2`, `nano-banana-2`, …) are accepted as aliases for their `org/slug` equivalents. |

The legacy `POST /v1/image-router/generate` and `GET /v1/image-router/models`
routes still work and are unchanged, but they are deprecated in favour of this
surface and will not gain new parameters.
