图像生成与编辑POST
文生图与图像编辑。生成结果保存到私有存储,返回 5 分钟内有效的下载链接,文件保留 30 天。
POST https://api.tokentosea.com/v1/images/generations
POST https://api.tokentosea.com/v1/images/edits
两个接口使用同一套请求字段,/v1/images/edits 额外需要参考图。TokenToSea 把通用字段转换成各厂商的原生格式,生成的图片转存到 TokenToSea 的私有对象存储,响应中只返回 TokenToSea 的签名下载链接,不暴露厂商的临时地址。
前提:全能密钥或模型密钥,账户可用余额足以覆盖本次预留。Python 示例需要 pip install requests,Node.js 示例需要 Node.js 18+(内置 fetch)。
支持的型号#
截至 2026-10-21,文生图 29 个型号、图像编辑 19 个型号。以 GET /v1/models 的 verified_endpoints 为准。
开放 /v1/images/generations 的型号(29)
| 服务商 | 型号 | 返回方式 |
|---|---|---|
| 千问 | qwen-image-2.0、qwen-image-2.0-2026-03-03、qwen-image-2.0-pro、qwen-image-2.0-pro-2026-03-03、qwen-image-2.0-pro-2026-04-22、qwen-image-2.0-pro-2026-06-22、qwen-image-2.1-pro、qwen-image-2.1-turbo、qwen-image-3.0、qwen-image-3.0-pro、wan2.6-t2i、wan2.7-image、wan2.7-image-pro、z-image-turbo | 同步 |
| 千问 | wan2.2-t2i-flash、wan2.2-t2i-plus、wan2.5-t2i-preview、wanx-v1、wanx2.0-t2i-turbo、wanx2.1-t2i-plus、wanx2.1-t2i-turbo | 异步(202) |
| 智谱 | cogview-3-flash、cogview-4、cogview-4-250304、glm-image | 同步 |
| MiniMax | image-01、image-01-live | 同步 |
| 豆包 | doubao-seedream-5-0-flash-260915、doubao-seedream-5-0-pro-260628 | 同步 |
开放 /v1/images/edits 的型号(19)
| 服务商 | 型号 | 返回方式 |
|---|---|---|
| 千问 | qwen-image-2.0、qwen-image-2.0-2026-03-03、qwen-image-2.0-pro、qwen-image-2.0-pro-2026-03-03、qwen-image-2.0-pro-2026-04-22、qwen-image-2.0-pro-2026-06-22、qwen-image-2.1-pro、qwen-image-2.1-turbo、qwen-image-3.0、qwen-image-3.0-pro、wan2.6-image、wan2.7-image、wan2.7-image-pro | 同步 |
| 千问 | wan2.5-i2i-preview、wanx2.1-imageedit | 异步(202) |
| MiniMax | image-01、image-01-live | 同步 |
| 豆包 | doubao-seedream-5-0-flash-260915、doubao-seedream-5-0-pro-260628 | 同步 |
两个接口都只支持 JSON 响应,"stream": true 返回 422 response_mode_not_verified。
请求体#
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model | string | 必填 | 型号 ID |
prompt | string | 必填 | 图像描述 |
n | integer | 可选 | 生成数量,默认 1。按张计费的型号按 n 预留费用;平台验收示例均为 1 |
size | string | 可选 | 尺寸。千问、智谱写作 宽x高(如 1024x1024;千问会自动转成厂商的 1024*1024);glm-image 示例使用 1280x1280;豆包 Seedream 使用 2K 等档位 |
seed | integer | 可选 | 随机种子(千问) |
negative_prompt | string | 可选 | 反向提示词(千问) |
prompt_extend | boolean | 可选 | 是否让厂商自动扩写提示词(千问)。z-image-turbo 的价格与此开关有关 |
watermark | boolean | 可选 | 是否添加厂商水印(千问、豆包) |
aspect_ratio | string | 可选 | 仅 MiniMax,默认 1:1 |
image | string | string[] | edits 必填 | 参考图 URL。MiniMax 把它作为人物主体参考(subject_reference);千问 wanx2.1-imageedit 作为待编辑底图 |
mask | string | 可选 | 仅 wanx2.1-imageedit:蒙版图 URL |
parameters | object | 可选 | 千问:其他厂商原生参数,合并进上游的 parameters |
provider_options | object | 可选 | 厂商原生扩展。千问可写 provider_options.parameters(合并进参数)、provider_options.function(wanx2.1-imageedit 的编辑功能,默认 description_edit);MiniMax 与豆包的其他原生字段直接写在请求体中 |
图片 URL 必须能被厂商公网访问。厂商的原生字段没有在上表列出的,可查阅厂商文档后直接加入请求体:智谱、豆包请求体原样转发(仅 model 固定、豆包强制 response_format: "url");MiniMax 强制 response_format: "url"。
响应#
同步型号返回 200:
{
"id": "…",
"model": "qwen-image-2.1-pro",
"data": [
{
"url": "https://tokentosea-media-cn-….cos.ap-nanjing.myqcloud.com/…?sign=…",
"asset_id": "asset_8c1f…(64 位十六进制)",
"mime_type": "image/png"
}
],
"usage": { "…": "厂商返回的用量" }
}| 字段 | 说明 |
|---|---|
data[].url | 私有存储的签名下载链接,最多 300 秒内有效。请立即下载或转存 |
data[].asset_id | 资产 ID。链接过期后用 GET /v1/assets/{asset_id}/download-url 重新获取;文件保留 30 天 |
data[].mime_type | 文件类型 |
usage / extra_info | 厂商返回的用量信息(如有) |
厂商为每张图片返回的其他字段(例如豆包的 size)会保留在 data[] 中;b64_json 不会返回,图片一律以链接形式提供。
异步型号返回 202 和结果信封(status: "upstream_pending")。平台每 5 秒查询一次厂商任务,完成后把图片转存并结算;用 GET /v1/results/{key} 或 GET /v1/tasks/{id} 轮询,完成后 output 与上面的同步响应相同。转存尚未完成时同步型号也可能返回 202,处理方式相同。
示例#
文生图#
REQUEST_KEY="$(uuidgen)"
curl https://api.tokentosea.com/v1/images/generations \
-H "Authorization: Bearer $TOKENTOSEA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $REQUEST_KEY" \
-d '{
"model": "qwen-image-2.1-pro",
"prompt": "A red cube on a white table, soft studio light.",
"n": 1,
"size": "1024x1024"
}'import os
import time
import uuid
import requests
API = "https://api.tokentosea.com/v1"
HEADERS = {"Authorization": "Bearer " + os.environ["TOKENTOSEA_API_KEY"]}
request_key = str(uuid.uuid4())
response = requests.post(
API + "/images/generations",
headers={**HEADERS, "Idempotency-Key": request_key},
json={
"model": "qwen-image-2.1-pro",
"prompt": "A red cube on a white table, soft studio light.",
"n": 1,
"size": "1024x1024",
},
timeout=600,
)
if response.status_code == 202: # 异步型号或转存未完成:按同一个键轮询
while True:
time.sleep(5)
result = requests.get(API + "/results/" + request_key, headers=HEADERS, timeout=30).json()
if result["status"] == "succeeded":
body = result["output"]
break
if result["status"] == "failed":
raise RuntimeError(result.get("error"))
else:
response.raise_for_status()
body = response.json()
image = body["data"][0]
with open("image.png", "wb") as file: # 链接 300 秒内有效,立即下载
file.write(requests.get(image["url"], timeout=120).content)
print("saved image.png, asset_id =", image["asset_id"])import { randomUUID } from 'node:crypto';
import { writeFile } from 'node:fs/promises';
const API = 'https://api.tokentosea.com/v1';
const headers = { Authorization: `Bearer ${process.env.TOKENTOSEA_API_KEY}` };
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
const requestKey = randomUUID();
const response = await fetch(`${API}/images/generations`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json', 'Idempotency-Key': requestKey },
body: JSON.stringify({
model: 'qwen-image-2.1-pro',
prompt: 'A red cube on a white table, soft studio light.',
n: 1,
size: '1024x1024',
}),
});
let body;
if (response.status === 202) { // 异步型号或转存未完成:按同一个键轮询
for (;;) {
await sleep(5000);
const result = await (await fetch(`${API}/results/${requestKey}`, { headers })).json();
if (result.status === 'succeeded') { body = result.output; break; }
if (result.status === 'failed') throw new Error(JSON.stringify(result.error));
}
} else {
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
body = await response.json();
}
const image = body.data[0];
const file = await fetch(image.url); // 链接 300 秒内有效,立即下载
await writeFile('image.png', Buffer.from(await file.arrayBuffer()));
console.log('saved image.png, asset_id =', image.asset_id);图像编辑#
curl https://api.tokentosea.com/v1/images/edits \
-H "Authorization: Bearer $TOKENTOSEA_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d '{
"model": "qwen-image-2.1-pro",
"prompt": "把桌面换成木纹,保持立方体不变。",
"image": "https://example.com/source.png",
"n": 1,
"size": "1024x1024"
}'import os
import uuid
import requests
IMAGE_URL = "https://example.com/source.png" # 厂商需能公网访问
response = requests.post(
"https://api.tokentosea.com/v1/images/edits",
headers={
"Authorization": "Bearer " + os.environ["TOKENTOSEA_API_KEY"],
"Idempotency-Key": str(uuid.uuid4()),
},
json={
"model": "qwen-image-2.1-pro",
"prompt": "把桌面换成木纹,保持立方体不变。",
"image": IMAGE_URL,
"n": 1,
"size": "1024x1024",
},
timeout=600,
)
response.raise_for_status()
print(response.status_code, response.json())import { randomUUID } from 'node:crypto';
const IMAGE_URL = 'https://example.com/source.png'; // 厂商需能公网访问
const response = await fetch('https://api.tokentosea.com/v1/images/edits', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TOKENTOSEA_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': randomUUID(),
},
body: JSON.stringify({
model: 'qwen-image-2.1-pro',
prompt: '把桌面换成木纹,保持立方体不变。',
image: IMAGE_URL,
n: 1,
size: '1024x1024',
}),
});
console.log(response.status, await response.json());返回 202 时按文生图示例的方式轮询。
错误#
| 状态码 | code | 原因与处理 |
|---|---|---|
422 | response_mode_not_verified | 图像接口不支持流式,去掉 stream |
422 | endpoint_not_verified | 该型号未开放所调用的接口(例如只支持文生图的型号调用了 edits) |
422 | image_reference_required、duplicate_image_reference | MiniMax:image 为空或非字符串;同时传了 image 与 subject_reference |
400 | main_wallet_authorization_failed | 请求条件(例如 prompt_extend、图层拆分)在该型号的价格表中没有对应规则 |
4xx | provider_http_<状态码> | 厂商拒绝(例如尺寸不受支持、内容审核未通过),message 为厂商描述,未扣费 |