curl --request POST \
--url https://api.aisa.one/v1/chat/completions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "seedream-4-5-251128",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "A cute red panda, ultra-detailed, cinematic lighting"
}
]
}
],
"n": 1
}
'{
"id": "chatcmpl-fcc86dfd-9424-9523-b0bd-cdf07383bee2",
"object": "chat.completion",
"created": 1776495713,
"model": "seedream-4-5-251128",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": [
{
"type": "image",
"image": "https://cdn.aisa.one/images/seedream/20260418-abc.png"
}
]
}
}
],
"usage": {
"prompt_tokens": 104,
"completion_tokens": 8,
"total_tokens": 112
}
}Image Generation via Chat
Image generation over the /v1/chat/completions route using OpenAI’s multimodal chat schema. As of July 28, 2026 the Wan 2.7 image models have moved to /v1/images/generations; seedream-4-5-251128 is the remaining model configured on this route.
curl --request POST \
--url https://api.aisa.one/v1/chat/completions \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"model": "seedream-4-5-251128",
"messages": [
{
"role": "user",
"content": [
{
"type": "text",
"text": "A cute red panda, ultra-detailed, cinematic lighting"
}
]
}
],
"n": 1
}
'{
"id": "chatcmpl-fcc86dfd-9424-9523-b0bd-cdf07383bee2",
"object": "chat.completion",
"created": 1776495713,
"model": "seedream-4-5-251128",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": [
{
"type": "image",
"image": "https://cdn.aisa.one/images/seedream/20260418-abc.png"
}
]
}
}
],
"usage": {
"prompt_tokens": 104,
"completion_tokens": 8,
"total_tokens": 112
}
}content array containing a text prompt, and AIsa returns generated images as {type: "image"} parts inside choices[].message.content[].
wan2.7-image and wan2.7-image-pro no longer serve this route — calling them here returns 400 model_route_not_supported. They now use POST /v1/images/generations and POST /v1/images/edits. seedream-5-0-260128 and gpt-image-2 are on /v1/images/generations as well.generateContent requests use /v1beta/models/{model}:generateContent.Supported models
| Model | Cost | Status |
|---|---|---|
seedream-4-5-251128 | $0.036 / request | Configured on this route; probes on July 28, 2026 returned 502 no available channel, so verify availability before building on it |
Request
The request schema is the samePOST /v1/chat/completions you already use for text — the only differences are which model you pass and how content is structured.
Critical rule: messages[].content must be an array of typed parts. Passing a plain string returns 400 invalid_parameter_error with the message "Input should be a valid list: messages[*].content".
curl -sS -X POST "https://api.aisa.one/v1/chat/completions" \
-H "Authorization: Bearer $AISA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seedream-4-5-251128",
"messages": [
{
"role": "user",
"content": [
{ "type": "text", "text": "A cute red panda, ultra-detailed, cinematic lighting" }
]
}
],
"n": 1
}'
from openai import OpenAI
client = OpenAI(base_url="https://api.aisa.one/v1", api_key="sk-aisa-...")
resp = client.chat.completions.create(
model="seedream-4-5-251128",
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "A cute red panda, ultra-detailed, cinematic lighting"}
],
}
],
n=1,
)
# Pull image URLs out of the response
for choice in resp.choices:
for part in choice.message.content:
if part["type"] == "image":
print(part["image"])
import OpenAI from "openai";
const client = new OpenAI({
baseURL: "https://api.aisa.one/v1",
apiKey: process.env.AISA_API_KEY,
});
const resp = await client.chat.completions.create({
model: "seedream-4-5-251128",
messages: [
{
role: "user",
content: [
{ type: "text", text: "A cute red panda, ultra-detailed, cinematic lighting" },
] as any,
},
],
n: 1,
});
const urls = resp.choices
.flatMap((c) => (c.message.content as any[]))
.filter((p) => p.type === "image")
.map((p) => p.image);
Request fields
| Field | Type | Required | Notes |
|---|---|---|---|
model | string | yes | seedream-4-5-251128 |
messages[].role | string | yes | user for the prompt turn |
messages[].content | array | yes | Must be an array, not a string |
messages[].content[].type | string | yes | text for prompt parts; image_url for image-to-image inputs |
messages[].content[].text | string | when type=text | The prompt |
messages[].content[].image_url.url | string | when type=image_url | Reference image URL |
n | integer | no | Number of images. Each is billed separately — pass 1 unless you want candidates |
Response shape
{
"id": "chatcmpl-fcc86dfd-...",
"object": "chat.completion",
"created": 1776495713,
"model": "seedream-4-5-251128",
"choices": [
{
"index": 0,
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": [
{ "type": "image", "image": "https://cdn.aisa.one/images/seedream/..." }
]
}
}
],
"usage": {
"prompt_tokens": 104,
"completion_tokens": 8,
"total_tokens": 112
}
}
- One choice per image. If
n=4, you get 4 entries inchoices. - Every
choice.message.contentis an array with a single{ "type": "image", "image": "..." }part. imageis a short-lived URL (download it soon) or base64 data, depending on your workspace configuration.usage.total_tokensreflects the small token cost of the request framing — billing is per-image at the rate in the table above, not per token.
Image-to-image
Prepend animage_url part to the content array and follow it with a text instruction. For the Wan models this workflow now lives on POST /v1/images/edits:
{
"model": "seedream-4-5-251128",
"messages": [
{
"role": "user",
"content": [
{ "type": "image_url", "image_url": { "url": "https://example.com/reference.jpg" } },
{ "type": "text", "text": "Transform into an oil painting in the style of Van Gogh" }
]
}
],
"n": 1
}
Why the playground shows the Chat Completions path
The playground sends exactly the samePOST /v1/chat/completions request the standard OpenAI Chat endpoint uses — only the model and content shape are tuned for images. Your existing OpenAI-compatible SDK code works without modification; just swap the model and content shape.
Common 4xx causes
400 invalid_parameter_error — Input should be a valid list: messages[*].content—contentwas passed as a string; wrap in an array of typed parts.400referencingmessages— you sent the Gemini-stylecontents/parts. Usemessageswith OpenAI multimodal parts.400 model_route_not_supported— the model does not serve this endpoint. The error body lists the routes it does serve;wan2.7-image,wan2.7-image-pro,seedream-5-0-260128, andgpt-image-2all belong on/v1/images/generations.502 no available channel— the route exists but the upstream has no capacity right now. Retry, or use an image model on/v1/images/generations.500 model_not_found— your workspace isn’t provisioned for this model family. Contact support.
Related
OpenAI Chat
Gemini generateContent
Media Gen skill
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
Image-generation model on the chat route. seedream-4-5-251128 is billed at $0.036 per request. Wan and gpt-image-2 models use /v1/images/generations instead.
seedream-4-5-251128 Conversation messages. Image prompts go in the last user message's content array as {type: "text"} parts.
Show child attributes
Show child attributes
Number of images to generate. Each image is billed separately; pass 1 unless you want candidates.
x >= 1Response
Images generated. Returned as Chat Completion with message.content[] image parts.