# Seedream 5.0 Pro — /images/generations

Image generation with Seedream 5.0 Pro, the flagship image model of ByteDance's Seedream 5.0 series: one model for text-to-image, edits and multi-image fusion, as an async job. Submitting returns a job id at once (HTTP 202), then you poll the result or let a webhook push it. 1K and 2K in 8 ratios, the original JPEG delivered; billed per image, nothing charged on failure.

**Endpoint:** `POST https://kovapi.com/v1/images/generations`

## Quick start

Three steps: submit a job, poll it, take the image link. Replace YOUR_API_KEY with your key and the commands below run as they are.

**Step 1 · Submit (returns a job id at once, HTTP 202)**

```
curl https://kovapi.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "seedream-5.0-pro", "prompt": "A cafe doorway in an old alley at dusk, a chalkboard reading “Today: Osmanthus Latte $4”, a ginger cat beside it, photorealistic", "size": "16:9", "resolution": "2K"}'
```

Response (HTTP 202)

```
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "queued",
  "created": 1791281400,
  "model": "seedream-5.0-pro"
}
```

**Step 2 · Poll every 2–3 seconds until `status` is `succeeded` or `failed`**

```
curl https://kovapi.com/v1/images/jobs/img_7f3c9a1e2b4d6f8a0c1e3b5d \
  -H "Authorization: Bearer YOUR_API_KEY"
```

Response when it succeeds

```
{
  "id": "img_7f3c9a1e2b4d6f8a0c1e3b5d",
  "object": "image.generation.job",
  "status": "succeeded",
  "created": 1791281400,
  "model": "seedream-5.0-pro",
  "data": [
    {"url": "https://img.kovapi.com/i/2be8cd16d37f3a4b9c0e1f2a3b4c5d6e.jpg"}
  ],
  "usage": {"images": 1, "resolution": "2K", "model": "seedream-5.0-pro"}
}
```

**Step 3 · `data[0].url` is the image (the original JPEG). It is kept for 7 days; download it to your own storage to keep it longer.**

**Complete example (Python: submit, wait, save to disk)**

```
import time
import requests

BASE = "https://kovapi.com/v1"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}

# 1. submit
job = requests.post(f"{BASE}/images/generations", headers=HEADERS, json={
    "model": "seedream-5.0-pro",
    "prompt": "A cafe doorway in an old alley at dusk, a chalkboard reading “Today: Osmanthus Latte $4”, a ginger cat beside it, photorealistic",
    "size": "16:9",
    "resolution": "2K",
}).json()
if "error" in job:
    raise SystemExit(job["error"]["message"])

# 2. poll every 3 seconds until it finishes
while job["status"] not in ("succeeded", "failed"):
    time.sleep(3)
    job = requests.get(f"{BASE}/images/jobs/{job['id']}", headers=HEADERS).json()

# 3. download the image
if job["status"] == "succeeded":
    url = job["data"][0]["url"]
    with open("seedream-5.0-pro.jpg", "wb") as f:
        f.write(requests.get(url).content)
    print("saved", url)
else:
    print("failed:", job["error"]["code"], job["error"]["message"])
```

## Authentication
```
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
```

## Request parameters

The JSON body of `POST /v1/images/generations`:

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| model | string | Yes | The model id: `seedream-5.0-pro`. |
| prompt | string | Yes | What to draw. For image-to-image, say what to change. |
| size | string | No | Aspect ratio: `1:1` (default), `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `21:9`. A pixel size (e.g. `2560x1440`) also works and is matched to one of these 8 by its ratio; any other ratio returns 400 at submit, nothing charged. You get the original at that ratio, at least the size in the docs' size table. |
| resolution | string | No | Tier: `1K` (default) or `2K`. There is no 4K. |
| image / images | string / array | No | Reference images; sending any makes it an edit or a fusion: one in `image`, several in `images` (up to 8). Each can be a public image URL, a data: URI or base64. With several, say in the prompt what each one is for, in order, e.g. "the person from image 1 sitting in the cafe from image 2". |
| n | integer | No | Always 1: one image per request. For several, submit several jobs at once; any other value returns 400 at submit, nothing charged. |
| callback_url | string | No | Where to push the result when the job ends; see Webhooks below. |

Other OpenAI parameters (`quality`, `background`, `output_format`, `style` and the like) are not supported: they have no effect and do not change the price. Results are always the original JPEG, returned as a `url`; with `response_format: "b64_json"` the result also carries a base64 copy.

## Price

Billed per image by tier only: aspect ratio, text-to-image or image-to-image make no difference. The tier price is held when you submit and refunded in full if the job fails. 1 credit = $0.005.

| Tier | Credits per image | USD per image |
| --- | --- | --- |
| 1K | 5 | $0.025 |
| 2K | 9 | $0.045 |

## Aspect ratio, resolution and output size

Put the ratio in `size` and the tier in `resolution`. You get the original the model draws at that ratio, never cropped or resized; it is at least the size listed below, and a few ratios come out larger (1K 16:9 is currently 1536×864).

| Aspect ratio | 1K | 2K |
| --- | --- | --- |
| 1:1 | 1024x1024 | 2048x2048 |
| 16:9 | 1280x720 | 2560x1440 |
| 9:16 | 720x1280 | 1440x2560 |
| 4:3 | 1104x848 | 2352x1776 |
| 3:4 | 848x1104 | 1776x2352 |
| 3:2 | 1168x800 | 2496x1680 |
| 2:3 | 800x1168 | 1680x2496 |
| 21:9 | 1472x640 | 2560x1104 |

- Only the 8 ratios in the table are supported; any other (5:4, 2:1 ...) returns 400 `unsupported_size` at submit and nothing is charged. A few native sizes are 1–3% off the nominal ratio (1K 4:3 is 1104×848): that is the size the model itself draws. Before delivery the ratio and the model named in the C2PA credential are checked, and the image must be at least the size in the table; if any of these fails, the image is not delivered, the job fails and nothing is charged.

- `size` can also be a pixel size (e.g. `2560x1440`): it only sets the ratio (within 1.5% of one of the 8), and you still get the original at that ratio (at least the size in the table). The tier comes from `resolution`; without it the longest side decides: up to 1536 is 1K, 1537 to 2600 is 2K.

- This model has 1K and 2K only: asking for 4K (`resolution: "4K"`, or a `size` whose longest side is over 2600) is refused at once with 400 `unsupported_resolution`, and nothing is charged. For 2K, send `resolution: "2K"`.

## Image-to-image and reference images

- Send `image` (one picture) or `images` (several, up to 8; any beyond 8 are not used) and the job runs image-to-image; say in the prompt what to change. `POST /v1/images/edits` takes the same parameters.

- Both endpoints take a JSON body only, not a multipart file upload, so the OpenAI SDK's `images.edit()` cannot be used as is: pass links or base64 as in the example below.

- Each reference can be a public image URL (http or https), a data: URI or plain base64, up to 16MB each, in a common format such as JPEG, PNG or WebP.

- A URL has to download the image itself: not a web page, and not behind a login or hotlink protection. A reference we cannot read is refused at submit with a 400 that says which one and why; no job is created and nothing is charged.

- For edits and fusions the output ratio follows `size` (1:1 when absent), not the reference image; to keep the original's ratio, set `size` to that ratio. You get the model's original, never cropped or resized.

- We host the references for you and keep them for 7 days.

**Image-to-image with two references**

```
curl https://kovapi.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "seedream-5.0-pro", "prompt": "Keep the people, change the background to a beach at night with warm string lights", "images": ["https://example.com/people.jpg", "https://example.com/beach.jpg"], "size": "3:4", "resolution": "2K"}'
```

## Job status and fields

`GET /v1/images/jobs/{id}` reports these statuses; every field is described in [Async jobs](https://docs.kovapi.com/en/guide/async-jobs#fields). Poll every 2–3 seconds, or use a webhook.

| Status | Meaning |
| --- | --- |
| queued | Waiting in line. Carries `queue_position` (jobs ahead of yours) and `eta_seconds` (expected wait). |
| processing | Rendering. |
| succeeded | Done. The result is in `data[0].url`, the billing detail in `usage`. |
| failed | Failed. The reason is in `error`; the credits held for the job are refunded in full. |

One account runs up to 50 jobs at a time; further jobs wait in submission order, and a job that has not started after 15 minutes fails and is refunded in full. Job records are kept for 3 days and image links for 7 days.

## How long it takes

Usually 40–90 seconds from submit to result; 2K and several references are a little slower and can occasionally take over 2 minutes.

Real calls over the last 7 days: median 88 s, 90% done within 2.5 min.

## Errors and refunds

An error at submit comes back at once as HTTP 4xx / 5xx: no job is created and nothing is charged. A failure after the job was accepted is reported by the job endpoint, and the hold is refunded in full. Every code is listed under [Error codes](https://docs.kovapi.com/en/guide/errors).

### Errors at submit

| HTTP | code | Cause | What to do |
| --- | --- | --- | --- |
| 400 | missing_prompt | `/v1/images/generations` has no `prompt`. | Add a `prompt`. |
| 400 | invalid_request | A reference image cannot be read (dead link, not an image, over 16MB...; `message` says which one and why), `/v1/images/edits` has no reference image, the body is not a JSON object, or `n` is not an integer. | Fix what `message` says and submit again. |
| 400 | unsupported_resolution | The model does not offer the chosen resolution tier (Grok image generation has no 4K, for example). | Pick another tier; each model's doc lists its tiers. |
| 400 | model_not_found | The model id is misspelled, `model` is missing, or the model cannot be used on this endpoint (a chat model on the image endpoint, for example). | Use a model id from `GET /v1/models` or the [API reference](https://docs.kovapi.com/en/api). |
| 401 | invalid_api_key | The key does not exist, was deleted or is disabled, or the account is disabled. | Check the key on the API Keys page of the console. |
| 402 | insufficient_quota | Not enough balance to hold this request. The gateway holds the highest possible cost of the request first, so a burst of concurrent calls can trigger it too. | After a burst, wait a few seconds and retry; otherwise top up. |
| 429 | rate_limit_exceeded | Over the requests-per-minute limit set on this key (counted over the last 60 seconds). No `Retry-After` header. | Wait a few seconds and retry, or raise the key's limit in the console. |
| 503 | model_maintenance | The model is under maintenance and takes no requests; no other model answers in its place meanwhile. | Retry when maintenance ends; see [Status](https://kovapi.com/en/status). |
| 503 | service_unavailable | A temporary failure on our side, such as storing a reference file; `/v1/responses` also answers 503, with `Retry-After`, when it cannot take requests for a moment. | Retry shortly. |

### Failed jobs (`status` `failed`)

| code | When you see it | What to do |
| --- | --- | --- |
| moderation_blocked | Image: the model provider's safety system refused the prompt or a reference image (the code may also be `content_policy_violation`). | Rewrite the prompt or replace the reference; resubmitting it unchanged is usually refused again. |
| upstream_error | Any other failure: the automatic retries did not help, the job waited 15 minutes without starting, the upstream refused without a reason, and so on; `message` says which. | Submitting again usually works. |

## Webhooks instead of polling

Add `callback_url` when you submit and the moment the job ends, success or failure, the gateway pushes exactly what the poll endpoint returns to that URL, signed and retried on failure. You can also set an account-wide address under Settings → Webhook in the console. [Webhook docs →](https://docs.kovapi.com/en/webhooks)

```
curl https://kovapi.com/v1/images/generations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model": "seedream-5.0-pro", "prompt": "A cafe doorway in an old alley at dusk, a chalkboard reading “Today: Osmanthus Latte $4”, a ginger cat beside it, photorealistic", "size": "1:1", "callback_url": "https://your-domain.com/webhook"}'
```
