curl --request POST \
--url https://api.apiyi.com/v1/images/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "seedream-5-0-260128",
"prompt": "Replace the clothing in image 1 with the outfit from image 2."
}
'import requests
url = "https://api.apiyi.com/v1/images/generations"
payload = {
"model": "seedream-5-0-260128",
"prompt": "Replace the clothing in image 1 with the outfit from image 2."
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'seedream-5-0-260128',
prompt: 'Replace the clothing in image 1 with the outfit from image 2.'
})
};
fetch('https://api.apiyi.com/v1/images/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.apiyi.com/v1/images/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'seedream-5-0-260128',
'prompt' => 'Replace the clothing in image 1 with the outfit from image 2.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apiyi.com/v1/images/generations"
payload := strings.NewReader("{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apiyi.com/v1/images/generations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/images/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}"
response = http.request(request)
puts response.read_body{
"model": "seedream-5-0-260128",
"created": 1768518000,
"data": [
{
"url": "https://ark-content-generation-v2-ap-southeast-1.tos-ap-southeast-1.bytepluses.com/.../image.png",
"b64_json": "<string>",
"size": "2048x2048"
}
],
"usage": {
"generated_images": 1,
"output_tokens": 6240,
"total_tokens": 6240
}
}Image Editing API Reference
Seedream image editing, multi-image fusion, and batch sequence generation API reference and live Playground — same generations endpoint, switched via the image array and sequential_image_generation parameter
curl --request POST \
--url https://api.apiyi.com/v1/images/generations \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "seedream-5-0-260128",
"prompt": "Replace the clothing in image 1 with the outfit from image 2."
}
'import requests
url = "https://api.apiyi.com/v1/images/generations"
payload = {
"model": "seedream-5-0-260128",
"prompt": "Replace the clothing in image 1 with the outfit from image 2."
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
model: 'seedream-5-0-260128',
prompt: 'Replace the clothing in image 1 with the outfit from image 2.'
})
};
fetch('https://api.apiyi.com/v1/images/generations', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.apiyi.com/v1/images/generations",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'model' => 'seedream-5-0-260128',
'prompt' => 'Replace the clothing in image 1 with the outfit from image 2.'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.apiyi.com/v1/images/generations"
payload := strings.NewReader("{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.apiyi.com/v1/images/generations")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.apiyi.com/v1/images/generations")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"model\": \"seedream-5-0-260128\",\n \"prompt\": \"Replace the clothing in image 1 with the outfit from image 2.\"\n}"
response = http.request(request)
puts response.read_body{
"model": "seedream-5-0-260128",
"created": 1768518000,
"data": [
{
"url": "https://ark-content-generation-v2-ap-southeast-1.tos-ap-southeast-1.bytepluses.com/.../image.png",
"b64_json": "<string>",
"size": "2048x2048"
}
],
"usage": {
"generated_images": 1,
"output_tokens": 6240,
"total_tokens": 6240
}
}/v1/images/edits endpoint. Editing, multi-image fusion, and batch sequence all run through POST /v1/images/generations. This page’s Playground hits the same endpoint as Text-to-Image — the only difference is the image and sequential_image_generation parameters in the body.- Single-image editing —
image: ["url"]+sequential_image_generation: "disabled" - Multi-image fusion —
image: ["url1", "url2", ...]+disabled - Batch sequence —
sequential_image_generation: "auto"+sequential_image_generation_options.max_images: N - Image-to-sequence — combine the two:
imagearray +auto+max_images
response_format: "url" mode, the Playground works fine (the response is just a temporary BytePlus TOS link). If you switch to response_format: "b64_json", the response contains a multi-MB base64 string and the browser Playground may show 请求时发生错误: unable to complete request — the request actually succeeded; the browser just can’t render such a long base64 string.Recommended workflow:- Just want to view the image? Keep the default
urlmode — the Playground returns the link directly (remember to download to your own storage within 24 hours). - Need b64_json? Copy the code sample below and run it locally — the code will decode and save the image to a file automatically.
- No multipart/form-data uploads — upload your images to OSS or a public image host first, then pass URLs in the
imagearray imageis a URL array, not a repeatedimage[]field (unlike OpenAI’smultipart/form-dataformat)- No
maskfield — Seedream does not support alpha-channel mask inpainting; the whole image is rewritten by the prompt - Hard limit on total count: input references + output ≤ 15 images
image array becomes the “image 1 / image 2 / image 3” referenced in the prompt. Make ordering explicit:Replace the clothing in image 1 with the outfit from image 2, keeping the lighting from image 3.English prompts work best (the model is trained primarily on English), but Chinese is also supported as long as the wording is unambiguous.
Code Examples
extra_body (important — don’t be misled into thinking it’s an extra nesting layer)image, sequential_image_generation, and watermark are not standard parameters of the OpenAI SDK’s images.generate(), so in the Python SDK you must put them inside extra_body to send them.But extra_body is just the SDK’s parameter container — its fields are flattened and merged into the top level of the request body, at the same level as model and prompt. The JSON that actually goes out is identical to the cURL example below (image sits at the top level); there is no real "extra_body": {...} nesting in the request.If you’re not using the OpenAI SDK and instead build the JSON directly (requests / fetch / etc.), do not write extra_body — just place image and the other fields at the same level as model.Python (OpenAI SDK · single-image editing)
from openai import OpenAI
client = OpenAI(
api_key="sk-your-api-key",
base_url="https://api.apiyi.com/v1"
)
resp = client.images.generate(
model="seedream-5-0-260128",
prompt="Generate a close-up image of a dog lying on lush grass.",
size="2K",
response_format="url",
# Fields in extra_body are flattened to the top level of the request body
# (same level as model) by the SDK — not an extra nesting layer
extra_body={
"image": ["https://your-oss.example.com/source-photo.png"],
"sequential_image_generation": "disabled",
"watermark": False,
}
)
print(resp.data[0].url)
Python (OpenAI SDK · multi-image fusion)
resp = client.images.generate(
model="seedream-4-5-251128",
prompt="Replace the clothing in image 1 with the outfit from image 2, keeping the lighting style of image 3.",
size="4K",
response_format="url",
extra_body={
"image": [
"https://your-oss.example.com/person.png",
"https://your-oss.example.com/outfit.png",
"https://your-oss.example.com/lighting-ref.png",
],
"sequential_image_generation": "disabled",
"watermark": False,
}
)
print(resp.data[0].url)
Python (OpenAI SDK · batch sequence)
resp = client.images.generate(
model="seedream-5-0-260128",
prompt=(
"Generate four cinematic sci-fi storyboard scenes:"
"Scene 1 — astronaut repairing a spacecraft;"
"Scene 2 — meteor strike in deep space;"
"Scene 3 — emergency dodge in zero gravity;"
"Scene 4 — astronaut returning to ship."
),
size="2K",
response_format="url",
extra_body={
"sequential_image_generation": "auto",
"sequential_image_generation_options": {"max_images": 4},
"watermark": False,
}
)
for item in resp.data:
print(item.url)
cURL (multi-image fusion)
curl -X POST "https://api.apiyi.com/v1/images/generations" \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-5-0-260128",
"prompt": "Replace the clothing in image 1 with the outfit from image 2.",
"image": [
"https://your-oss.example.com/person.png",
"https://your-oss.example.com/outfit.png"
],
"sequential_image_generation": "disabled",
"size": "2K",
"response_format": "url",
"watermark": false
}'
Node.js (fetch · batch sequence)
const resp = await fetch('https://api.apiyi.com/v1/images/generations', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer sk-your-api-key'
},
body: JSON.stringify({
model: 'seedream-5-0-260128',
prompt: 'A four-panel comic about a cat astronaut: launch, space walk, alien encounter, return home.',
size: '2K',
sequential_image_generation: 'auto',
sequential_image_generation_options: { max_images: 4 },
response_format: 'url',
watermark: false
})
});
const { data } = await resp.json();
data.forEach((item, i) => console.log(`#${i + 1}:`, item.url));
image array are URLs, the request body is only a few KB and BytePlus downloads your images directly from its Singapore region (verified: the fetching IP belongs to BytePlus, and the APIYI gateway is not involved).
When the entries are data:image/...;base64,... strings, a few high-resolution reference images easily push the body to 20 to 30 MB. That body must first be uploaded in full to the APIYI gateway and then forwarded to Singapore. When the cross-border upload is slow, it exceeds the provider ingress limit of 600 seconds for reading the request body and fails with 400 Error when parsing request.
The whole request fails and does not fall back to URL mode, because the gateway does not convert base64 into a downloadable link for you.- ✅ Host the images on your own object storage or image host and pass public, unauthenticated URLs that can be fetched with a plain GET; keep each image under about 10 MB
- ⚠️ If base64 is unavoidable, compress first: long edge within 2048 px, re-encode at quality 0.9, and keep the total under 6 MB for multiple images
- ❌ Do not send base64 bodies above 20 MB, and do not pass private-network addresses or links that require login (BytePlus returns
InvalidParameter: Error while downloadingwhen the fetch fails)
Parameter Reference
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
model | string | yes | — | seedream-5-0-260128 / seedream-4-5-251128 / seedream-4-0-250828 / seedream-5-0-pro-260628 (pro tier, $0.12/request) / seedream-5-0-flash-260915 (fast tier, $0.018/request, reference images free) |
prompt | string | yes | — | Editing / fusion / sequence instruction |
image | array of string | required for editing | — | Reference images as URLs or base64 data URIs (data:image/jpeg;base64,..., verified), up to 10 (per official 4.5 / 5.0-pro / 5.0-flash docs; an 11th returns 400 on 5.0-flash in our tests) |
sequential_image_generation | string | no | disabled | disabled for single output; auto for batch sequence. Not accepted by 5.0-pro / 5.0-flash: any value (including disabled) returns 400 — omit the parameter entirely with these models |
sequential_image_generation_options.max_images | integer | no | — | Effective only with auto. Subject to input + output ≤ 15. Also not accepted by 5.0-pro / 5.0-flash |
size | string | no | 2K | Preset tier or exact pixels — tier support varies by version (see Overview) |
response_format | string | no | url | url / b64_json |
output_format | string | no | jpeg | The 5.0 series supports png / jpeg; 4.5 / 4.0 only jpeg |
watermark | boolean | no | varies | Set false for commercial use (5.0-flash adds an “AI generated” watermark when omitted) |
stream | boolean | no | false | Streaming output, recommended for long prompts. Not accepted by 5.0-pro / 5.0-flash — returns 400 |
Count Constraints in Multi-image and Sequence Modes
| Scenario | Input image count | max_images | Actual output | Total constraint |
|---|---|---|---|---|
| Single-image editing | 1 | — | 1 | 2 ≤ 15 ✅ |
| Multi-image fusion | 3 | — | 1 | 4 ≤ 15 ✅ |
| Multi-image fusion + sequence | 3 | 4 | 4 | 7 ≤ 15 ✅ |
| Multi-image fusion + sequence | 10 | 6 | 6 | 16 > 15 ❌ rejected |
5.0 Flash Layer Separation (Transparent Layers)
seedream-5-0-flash-260915 can split a finished image into a background base plus separate elements on transparent layers, useful for re-layout, background swaps and asset reuse. Asking for a transparent background in the prompt does not produce an alpha channel, so use this for transparent assets.
curl -X POST "https://api.apiyi.com/v1/images/generations" \
-H "Authorization: Bearer sk-your-api-key" \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-5-0-flash-260915",
"prompt": "Split the image into a background and separate layers for each element",
"image": ["https://your-oss.example.com/poster.jpg"],
"layer_decomposition": true,
"size": "1K",
"output_format": "png",
"response_format": "url",
"watermark": false
}'
- With 1 reference image, the
dataarray returned 12 images: the first is the background base with the elements removed and filled in (file name ends in_base.png, RGB); the other 11 are RGBA transparent layers (from_layer_1.png), each holding one element cropped to its own size - About 78 seconds at 1K; the same request at 2K returned nothing after 15 minutes but was still billed $0.216 for 12 images. Use
1Kand set the client timeout to 300 seconds or more - Layer separation can fail: the same image once returned a 400 after about 60 seconds (
the image content could not be processed for layer decomposition). Failures are not billed, so just retry - The areas removed from the base are painted in by the model, so review them before commercial use
usage.generated_images was 12). The number of layers depends on the image content and cannot be set in advance, and the same image can split differently each time (one image gave 12 and then 14 images, billed $0.216 and $0.252), so budget for a dozen or more.Response Format
{
"model": "seedream-5-0-260128",
"created": 1768518000,
"data": [
{
"url": "https://ark-content-generation-v2-ap-southeast-1.tos-ap-southeast-1.bytepluses.com/seedream-5-0/.../scene-1.png",
"size": "2048x2048"
},
{
"url": "https://...scene-2.png",
"size": "2048x2048"
}
],
"usage": {
"generated_images": 2,
"output_tokens": 12480,
"total_tokens": 12480
}
}
data array length reflects actual output countsequential_image_generation: "disabled"→ single-elementdatasequential_image_generation: "auto"+max_images: N→ typically N elements (occasionally fewer if the prompt produces less)- Billing is by
usage.generated_images, not bymax_images
Authorizations
API Key obtained from APIYI Console
Body
Model ID
seedream-5-0-260128, seedream-5-0-lite-260128, seedream-4-5-251128, seedream-4-0-250828, seedream-5-0-pro-260628, seedream-5-0-flash-260915 Editing / fusion / sequence instruction. For multi-image scenarios, refer to images explicitly as 'image 1 / image 2'
"Replace the clothing in image 1 with the outfit from image 2."
Reference image URL array. Up to 10 images (per official 4.5 / 5.0-pro / 5.0-flash docs; an 11th returns 400 on 5.0-flash in our tests). Note: input + output count ≤ 15
10[
"https://your-oss.example.com/person.png",
"https://your-oss.example.com/outfit.png"
]
Generation mode switch. disabled = single output (default); auto = batch sequence, paired with max_images. Not accepted by 5.0-pro / 5.0-flash — any value returns 400
disabled, auto Batch sequence options. Effective only when sequential_image_generation=auto
Show child attributes
Show child attributes
Output size. Preset tiers (vary by version):
1K(4.0 / 5.0-pro / 5.0-flash) /1.5K(5.0-flash only) /2K(all) /3K(5.0 only) /4K(4.5, 4.0)
Or exact pixel size WxH, total pixels ∈ [1280×720, 4096×4096], aspect ratio ∈ [1/16, 16]
"2K"
url, b64_json Output format. The 5.0 series supports png/jpeg; 4.5/4.0 only jpeg
png, jpeg 5.0-flash only: pass 1 reference image to get a background base plus several RGBA transparent layers. Billed per output image (12 in one test); use size 1K and a timeout of 300 seconds or more
Streaming output. Recommended for long prompts and multi-image sequence scenarios. Not accepted by 5.0-pro / 5.0-flash (returns 400)
Response
Edited image generated successfully
"seedream-5-0-260128"
1768518000
Result array. disabled mode returns 1 element; auto mode typically returns max_images elements (may be fewer)
Show child attributes
Show child attributes
Billed by generated_images actual count, NOT by max_images
Show child attributes
Show child attributes
Was this page helpful?