magic·art
开发者文档 / IMAGE API 代码示例 ↗
BUILD SOMETHING IMAGINATIVE

图片 API 对接文档从灵感,到可交付的图像。

用一套清晰的接口完成文字生成、参考图编辑、异步交付与 CDN 分发。从第一次调用,到稳定集成,你需要的细节都在这里。

REST API JSON / Multipart 异步 & Webhook 公开图片上传 CDN 加速

开始接入

从一张图片开始,逐步接入上传、编辑和异步生成。

本文介绍 magic·art 图片接口。使用 HTTP + JSON 调用;文件上传使用 multipart/form-data。示例模型为 gpt-image-2,实际可用模型以接入方提供的模型列表为准。

场景 接口 返回方式
文生图 POST /v1/images/generations 同步 JSON、SSE 或异步任务
图生图 / 图片编辑 POST /v1/images/edits 同步 JSON、SSE 或异步任务
上传参考图 POST /v1/images/uploads 直接返回公开图片 URL
查询异步任务 GET /v1/images/tasks/{request_id} 任务状态及结果
获取模型列表 GET /v1/models 当前可用模型
Chat 格式生图 POST /v1/chat/completions Markdown 图片 / SSE

获取 Base URL 与 API Key

根据你使用的控制台,复制接口地址和完整密钥。下面两种界面选择对应的一种即可。

New API 控制台

  1. 进入左侧 API 密钥。
  2. 点击右上角 创建 API 密钥,按平台要求填写名称、分组及额度等信息并保存。已有可用密钥可直接使用。
  3. 在目标密钥右侧点击 … 更多菜单,选择复制连接信息,获取该密钥对应的接口地址和连接信息。
  4. 也可点击 API 密钥右侧的复制图标获取完整 Key。列表里的星号仅为脱敏显示,不是实际 Key。
New API:左侧 API 密钥、右上角创建 API 密钥,以及密钥行右侧的更多菜单位置
New API 操作位置示意 · 点击图片查看大图

Sub2API 控制台

  1. 进入左侧 API Keys。
  2. 点击右上角 Create API Key 创建密钥;已有密钥则找到对应行。
  3. 在列表上方 API Endpoints 区域点击地址旁的复制图标,获取 Base URL。
  4. 点击目标 API Key 旁的剪贴板图标,复制完整密钥。请确认所选分组与模型权限符合你的生图需求。
Sub2API:API Keys 菜单、Create API Key、API Endpoints 地址及 API Key 复制按钮位置
Sub2API 操作位置示意 · 点击图片查看大图

不同版本的菜单名称可能略有差异。Base URL 请以控制台的连接信息 / API Endpoints 为准,不要直接复制管理后台页面的网址。

地址与鉴权

所有示例只使用占位地址,请替换为分配给你的 API 地址。

Shell
export BASE_URL="https://api.example.com"
export UPLOAD_BASE_URL="https://uploads.example.com"
export API_KEY="YOUR_API_KEY"

BASE_URL 与 UPLOAD_BASE_URL 均不含末尾 /v1。若 SDK 要求填写 base_url,则使用 https://api.example.com/v1,不要重复拼接两次。

操作 是否需要 Key 说明
生图、编辑、模型列表 是 Authorization: Bearer YOUR_API_KEY
公开图片上传 否 无需 Authorization;携带的 Authorization 不影响公开上传
读取上传链接 / 生成图片链接 否 持有完整 URL 即可读取,链接应妥善保管
查询图片任务 否 持有完整任务 UUID 即可查询
取消 / 重试 / 重新提交任务 是 必须使用任务所属账号的 Key

查询可用模型

接入前先用 Key 验证连通性,再选择支持生成或编辑的模型。

GET /v1/models
cURL
curl "$BASE_URL/v1/models" -H "Authorization: Bearer $API_KEY"
JSON
{
  "object": "list",
  "data": [
    {
      "id": "gpt-image-2",
      "object": "model",
      "actions": [
        "generate",
        "edit"
      ]
    }
  ]
}

上例仅展示关键字段。generate 表示文生图能力,edit 表示图片编辑能力。模型可用性可能变化;中间接入平台也可能过滤模型或使用不同的能力字段,请以实际列表及平台配置为准。

文生图

根据文字描述生成图片。没有参考图时使用此接口。

POST /v1/images/generations
cURL
curl --max-time 420 "$BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: illustration-order-001" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "一只橘猫坐在窗边看雨,柔和自然光,水彩插画",
    "n": 1,
    "size": "1024x1024",
    "quality": "auto",
    "response_format": "url",
    "output_format": "png"
  }'

同步成功响应 · HTTP 200

JSON
{
  "created": 1790000000,
  "status": "completed",
  "stage": "completed",
  "request_id": "11111111-1111-4111-8111-111111111111",
  "data": [
    {
      "url": "https://api.example.com/v1/images/assets/22222222-2222-4222-8222-222222222222"
    }
  ]
}

data 是数组,不能假设永远只有一张图片。返回 usage 或 revised_prompt 时可按需记录,这些字段不保证每次都有。任务标识也会出现在响应头 X-Request-Id 中。

参数与尺寸

文生图和图生图共享大部分参数。不要把输出格式与响应格式混淆。

参数 类型 / 默认 说明
model string · 建议必填 使用模型列表中的模型 ID。示例为 gpt-image-2
prompt string · 必填 非空文字描述;图生图请明确修改目标和需保留的内容
n integer · 1 支持 1–12;模型可能有更严格限制。请传合法整数,不依赖兼容回退
size string · 可选 像素尺寸如 1024x1024、1086x1448;或 auto;或预设比例 3:4
resolution string · 可选 比例预设分辨率,如 1k / 2k / 4k,须为已配置组合
aspect_ratio string · 可选 与 resolution 配合,例如 3:4。建议直接使用明确像素 size
output_resolution string · 可选 resolution 的兼容字段;同时提供时优先级更高
quality string · 可选 示例 auto;具体质量档位与效果由模型支持情况决定
response_format string · url url 返回链接;b64_json 返回原始 Base64 字符串
output_format string · 可选 png / jpeg / webp;jpg 等同 jpeg,大小写兼容;省略保留原图格式
stream boolean · false true 开启 SSE,成功图片以 Base64 返回
callback_url string · 可选 非流式请求携带此字段即进入异步模式;填写真实 HTTP(S) 回调地址
cdn_key string · 可选 已创建且授权的 CDN 交付 Key,例如 cdn_live_…;与 response_format=url 配合。详见 CDN 配置
client_reference string · 可选 业务关联标识,可在同步、异步受理和查询响应中读取;不替代幂等键
background / moderation / input_fidelity 模型扩展字段 可随请求传递;是否生效由模型决定,不代表网关保证支持所有取值
output_compression 当前不生效 不要依赖此参数控制文件压缩率

尺寸选择

JSON
{
  "size": "3:4",
  "resolution": "2K"
}

比例写在 size 时优先于 aspect_ratio;未给分辨率时按 1k 预设处理。显式像素尺寸或 auto 优先于预设字段。输出尺寸单边不超过 4096 像素,还受总像素上限约束;并非所有模型都支持每种尺寸。

预设映射以服务配置为准,历史预设可能是近似比例。需要明确画布尺寸时直接写 宽x高。未配置的比例组合会返回 400,不要假设支持任意比例或 8K。

尺寸速查与写法

14 种常用比例,覆盖 1K、2K 和 4K;超出当前接口限制的组合明确标注。

14 种比例 × 1K / 2K / 4K 对照表

下表来自当前已核对的尺寸预设。每个像素值都可以直接填写为 size;比例写法则配合 resolution 选择对应档位。K 是预设档位名称,不代表每种画布都严格等于 1024、2048 或 4096 像素。

比例 常见用途 1K size 2K size 4K size
1:1 方形头像 / 产品图 1024x1024 2048x2048 3840x3840
4:3 横向插画 / 展示图 1152x896 2048x1536 3840x2880
3:4 竖向海报 / 人像 896x1152 1536x2048 2880x3840
16:9 横屏封面 / 幻灯片 1536x864 2048x1152 3840x2160
9:16 竖屏封面 / 手机背景 864x1536 1152x2048 2160x3840
3:2 横向摄影 1536x1024 2048x1360 3840x2560
2:3 竖向摄影 1024x1536 1360x2048 2560x3840
5:4 横向商品展示 1280x1024 2560x2048 3840x3072
4:5 竖向商品 / 社媒图 1024x1280 2048x2560 3072x3840
21:9 宽幅场景 / 横幅 1792x768 2048x880 3840x1648
1:4 窄长竖幅 512x2048 1024x4096 暂不支持(超出单边限制)
4:1 窄长横幅 2048x512 4096x1024 暂不支持(超出单边限制)
1.414:1 近似 A 系列横向纸张 1440x1024 2048x1456 3840x2720
1:1.414 近似 A 系列纵向纸张 1024x1440 1456x2048 2720x3840

部分历史预设是近似比例,例如 1K 的 4:3 / 3:4;若业务要求严格比例,应使用明确像素尺寸并核验最终图片。模型仍可能对尺寸作适配,返回图片的真实宽高以实际文件为准。1:8 / 8:1 属于额外长幅预设,未纳入这 14 种常用比例,不能据此推断它们在所有档位都可用。

size 的三种正确写法

写法 请求片段 用途
明确像素(推荐) {"size":"1536x2048"} 宽 1536、高 2048;最直观,避免预设差异
比例 + 分辨率 {"size":"3:4","resolution":"2k"} 读取 2K / 3:4 预设
分辨率 + 比例字段 {"resolution":"2k","aspect_ratio":"3:4"} 与上一行对应相同预设
自动尺寸 {"size":"auto"} 让模型按其能力选择,不承诺固定宽高

同一比例的三档示例

JSON
[
  {
    "size": "3:4",
    "resolution": "1k"
  },
  {
    "size": "3:4",
    "resolution": "2k"
  },
  {
    "size": "3:4",
    "resolution": "4k"
  }
]

上面是三个独立请求的参数片段,不是一次提交三个尺寸的完整请求体。文生图 / 图生图 JSON 与 multipart 均可使用:

参数片段
# JSON 中填写
"size": "1536x2048"

# multipart 中填写
-F "size=3:4" -F "resolution=2k"
容易出错的写法 正确处理
size:"2k" / size:"4K" K 档位填 resolution,size 填像素或比例
size:"1536×2048" 使用小写英文字母 x:1536x2048,不使用乘号 ×
size:[1536,2048] size 是字符串,不是数组
size:"wide" 使用具体比例,例如 16:9
同时传多套冲突的尺寸字段 优先仅保留 size;显式像素 size 或 auto 优先
只给 aspect_ratio,不给 resolution 不能保证唯一匹配;同时给分辨率或直接给像素
输出比例不符合预期 不要依赖近似预设;明确宽高并检查下载后文件尺寸

上传参考图片

公开上传,无需 API Key。返回的 URL 可供同一或另一生图入口读取。

POST /v1/images/uploads 无需鉴权

方式一:multipart 文件上传

cURL
curl "$UPLOAD_BASE_URL/v1/images/uploads" \
  -F "file=@reference.png"

字段名必须为 file,一次只能上传一张。不要手工填写 multipart 的 Content-Type,cURL / SDK 会自动生成 boundary。系统依据文件实际字节识别格式,而非文件名。

方式二:直接发送图片字节

cURL
curl "$UPLOAD_BASE_URL/v1/images/uploads" \
  -H "Content-Type: image/jpeg" \
  --data-binary @reference.jpg

支持 image/png、image/jpeg、image/webp、image/gif。原始字节方式要求 Content-Type 与实际格式一致。GIF 接受为输入不表示输出支持动画。

成功响应 · HTTP 200

JSON
{
  "id": "33333333-3333-4333-8333-333333333333",
  "state": "ready",
  "url": "https://uploads.example.com/v1/images/uploads/44444444-4444-4444-8444-444444444444",
  "byte_size": 245760,
  "content_type": "image/png",
  "width": 1024,
  "height": 1024,
  "sha256": "示例:64位十六进制内容摘要"
}
字段 说明
url 可直接用于 images[].image_url;下载无需 Key
id 上传素材 ID;不是图片生成任务 ID,也不是生图账号的私有素材 ID
state ready 表示可用
byte_size 图片文件字节数
content_type 识别出的实际 MIME
width / height 像素宽高
sha256 图片内容摘要

跨入口与链接有效期

上传后,将完整 URL 原样传给生图入口。生图服务必须能从服务端下载该 URL;不需要两个入口共享 API Key 或存储。不要使用需要 Cookie、登录、Referer 防盗链或只能在你本机访问的地址。

上传文件沿用参考图存储与清理规则:默认保留 24 小时,按最初创建时间计算,实际删除受清理周期影响。同内容重复上传可能复用旧 URL,不会刷新保留时间。清理后链接返回 404。任务已成功导入的参考图独立保留,不会因公开上传文件随后到期而直接丢失。

图生图与多图编辑

把上传得到的 URL 与修改说明一起提交。最多 16 张参考图,可选 1 张蒙版。

POST /v1/images/edits
cURL
curl --max-time 420 "$BASE_URL/v1/images/edits" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: edit-order-001" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "将图1的人物放在图2的场景中,保留人物面部特征和服装",
    "images": [
      {"image_url": "https://uploads.example.com/v1/images/uploads/IMAGE_ID_1"},
      {"image_url": "https://uploads.example.com/v1/images/uploads/IMAGE_ID_2"}
    ],
    "n": 1,
    "size": "1086x1448",
    "output_format": "jpg",
    "response_format": "url"
  }'

直接上传文件编辑

cURL
curl --max-time 420 "$BASE_URL/v1/images/edits" \
  -H "Authorization: Bearer $API_KEY" \
  -F "model=gpt-image-2" \
  -F "prompt=保留人物,将背景替换为雪山" \
  -F "image[]=@person.png" \
  -F "image[]=@landscape.jpg" \
  -F "size=1024x1024" \
  -F "output_format=png"

可接受的 JSON 图片形式

形式 示例
URL 对象(推荐) {"image_url":"https://uploads.example.com/source.png"}
URL 字符串 "https://uploads.example.com/source.png"
嵌套 URL 对象 {"image_url":{"url":"https://uploads.example.com/source.png"}}
Data URL "data:image/png;base64,iVBORw0..."
Base64 对象 {"b64_json":"iVBORw0..."}
原始 Base64 "iVBORw0..."

图片字段兼容 images、image、image_url、image_urls、image[]、images[]。建议统一采用 images 数组,避免混用。多字段按上述顺序合并并去除跨字段重复地址;同一数组的顺序保留。

mask 可传单张 URL、Base64 对象或 multipart 文件。具体蒙版尺寸、透明区含义及编辑效果由模型决定。参考图和蒙版均需能下载并通过图片校验。

CDN 配置与接入

将生成结果交付到自己的存储和 CDN,改善终端用户下载大图的体验。

01 添加存储与访问域名 02 创建并授权 cdn_key 03 生图请求携带 cdn_key

接入 CDN 后,图片生成完成会先上传到你配置的存储,再返回 CDN 访问链接。这样终端用户不必反复从海外源站下载大图。CDN 加速的是图片分发,不会直接缩短模型的生成时间,也不会自动加速网站或 API 请求。

一、准备对象存储与访问域名

当前开放平台配置界面支持七牛云与雨云对象存储。其他 S3 兼容存储需由接入方确认配置支持,不能直接在生图请求里填写存储凭据代替。

  1. 在存储服务商创建 Bucket,准备具备目标目录上传权限的 Access Key / Secret Key。
  2. 绑定能公开读取图片的访问域名,并按服务商要求配置 DNS、回源与 HTTPS。
  3. 确认目标用户所在地区能稳定访问该域名。存储域名和 CDN 加速域名不是同一概念;只填写一个海外对象存储域名不保证国内下载加速。
  4. 配置合适的缓存与文件保留策略。若源 Bucket 私有,请由服务商 CDN 完成授权回源,并保证返回的最终 URL 可访问;本接口不自动给自定义 CDN 链接生成访问签名。

二、在开放平台添加 CDN 配置

CDN 接入开放平台:https://open.shagentai.com/ ↗。登录后进入 添加 CDN 配置,填写下列字段,再创建 CDN Key 并完成生图授权。

界面 / 字段 填写内容 注意事项
服务商 / provider 七牛云 qiniu 或雨云 rainyun 按真实存储服务商选择
配置名称 / name 例如“生产图片 CDN” 用于区分用途
Access Key / access_key 存储服务商 AK 不是生图 API Key,不要放进前端或生图请求
Secret Key / secret_key 存储服务商 SK 仅在可信配置页面填写;查询不回显明文
Bucket / bucket 图片存储空间名称 与密钥权限和 Region 一致
API Endpoint / endpoint 雨云对象存储的 API Endpoint 雨云必填;七牛由其上传区域机制处理,不填写任意 CDN 域名作为 Endpoint
Region / region 存储空间所在区域 按服务商实际配置填写;错误区域可能导致上传失败
公开访问域名 / domain https://cdn.example.com 仅域名 / origin,不带 /images 路径、查询参数、账号密码
Key Prefix / key_prefix generated 或 images 对象路径前缀在这里填写,不拼进 domain
HTTPS / use_https 建议开启 域名证书须有效;HTTPS 页面不要引用 HTTP 图片

保存后在 我的 CDN 配置 中核对 Bucket、访问域名及启用状态;这一步保存配置,不代表上传链路已验证成功。

三、创建 CDN Key 并授权

  1. 进入 创建 CDN Key,选择刚才保存的 CDN 配置,填写 Key 名称并创建。
  2. 在 我的 CDN Key 中复制生成的 cdn_live_… 标识。
  3. 让接入方将该 CDN Key 授权给你的生图账号 / 接入链路。创建 Key 不等于完成生图授权;未经授权会返回 cdn_key_not_authorized。
  4. 先发起 n=1 的小尺寸图片验证请求,确认成功响应 data[].url 指向自己的 CDN 域名,并实际下载检查图片。

四、文生图携带 CDN Key

cURL
curl --max-time 420 "$BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: cdn-generation-001" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "白色背景的陶瓷花瓶产品摄影",
    "n": 1,
    "size": "1024x1024",
    "response_format": "url",
    "output_format": "jpeg",
    "cdn_key": "cdn_live_YOUR_CDN_KEY"
  }'

图生图携带 CDN Key

cURL
curl --max-time 420 "$BASE_URL/v1/images/edits" \
  -H "Authorization: Bearer $API_KEY" \
  -F "model=gpt-image-2" \
  -F "prompt=保留产品主体,将背景替换为浅灰色" \
  -F "image=@reference.png" \
  -F "size=1024x1024" \
  -F "response_format=url" \
  -F "output_format=jpeg" \
  -F "cdn_key=cdn_live_YOUR_CDN_KEY"

JSON 图生图同样在请求顶层加 cdn_key,不要放在 images 数组元素内。异步模式在同一请求增加 callback_url 即可;建议配合 URL 响应使用:

JSON
{
  "model": "gpt-image-2",
  "prompt": "一只坐在花园里的橘猫",
  "size": "1024x1024",
  "output_format": "jpeg",
  "cdn_key": "cdn_live_YOUR_CDN_KEY",
  "callback_url": "https://your-app.example.com/webhooks/images",
  "client_reference": "cdn-order-001"
}

五、确认交付结果

任务通常经过 queued → running / generating → running / delivering → completed。配置 CDN 后,只有图片全部上传成功,才进入 completed 并返回 CDN URL;生成耗时与 CDN 上传耗时要分别观察。

JSON
{
  "status": "completed",
  "data": [
    {
      "url": "https://cdn.example.com/generated/11111111-1111-4111-8111-111111111111/0"
    }
  ]
}

上例只展示关键字段。URL 可能没有文件扩展名,以 Content-Type 为准。目标对象路径一般为 {key_prefix}/{request_id}/{图片序号},重试同一图片交付会复用该路径。

情况 说明与处理
返回的仍是源图片地址 确认使用 response_format=url、cdn_key 在请求顶层、接入层未丢字段,并使用新的幂等键提交新的测试请求
出现 cdn_key_not_authorized 请接入方完成授权;不要无限重试同一未授权 Key
生成结束但一直 delivering 检查 AK/SK、Bucket、区域、Endpoint、对象上传权限与连通性;图片上传仍未完成
上传成功但 CDN 链接 403 / 404 检查 DNS、域名绑定、回源授权、路径前缀、防盗链和缓存;不要立即重新生图
CDN 交付失败 / delivery_review 保留 request_id,请接入方核查交付;修复后重试交付,不必盲目重新生成
Base64 / SSE 仍然很慢 图片字节仍要通过 API 响应传到客户端;要让浏览器直接走 CDN,使用 url 响应并加载返回的 URL

异步任务

先受理,再通过轮询或回调获取结果。适合长任务和业务后端。

01 POST + callback_url 02 收到 202 / request_id 03 轮询或接收回调
cURL
curl "$BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: async-order-001" \
  -d '{
    "model": "gpt-image-2",
    "prompt": "极简白色陶瓷花瓶产品摄影",
    "n": 1,
    "size": "1024x1024",
    "output_format": "webp",
    "callback_url": "https://your-app.example.com/webhooks/images",
    "client_reference": "order-001"
  }'

受理响应 · HTTP 202

JSON
{
  "request_id": "11111111-1111-4111-8111-111111111111",
  "id": "11111111-1111-4111-8111-111111111111",
  "status": "queued",
  "stage": "queued",
  "offline_task": true,
  "status_url": "https://api.example.com/v1/images/tasks/11111111-1111-4111-8111-111111111111",
  "task_url": "/v1/tasks/11111111-1111-4111-8111-111111111111",
  "client_reference": "order-001"
}

保存 request_id、status_url 和业务关联信息。202 仅代表任务已受理,不代表图片生成成功。图生图同样支持 callback_url,包括 JSON 与 multipart 请求。

查询与任务状态

优先使用受理响应返回的 status_url,尤其在多入口部署时。

GET /v1/images/tasks/{request_id} 无需鉴权
cURL
curl "$BASE_URL/v1/images/tasks/$REQUEST_ID"
JSON
{
  "request_id": "11111111-1111-4111-8111-111111111111",
  "parent_request_id": null,
  "created": 1790000000,
  "status": "completed",
  "stage": "completed",
  "gateway_status": "completed",
  "offline_task": true,
  "status_url": "https://api.example.com/v1/images/tasks/11111111-1111-4111-8111-111111111111",
  "client_reference": "order-001",
  "data": [
    {
      "url": "https://api.example.com/v1/images/assets/22222222-2222-4222-8222-222222222222"
    }
  ],
  "final_status": "success"
}
status 含义 客户端处理
queued 等待执行 继续等待
running 生成中或交付中 继续等待;stage 可为 generating / delivering
completed 成功 读取 data[].url 并保存图片
failed 失败或需要人工检查 记录 error,不要无限轮询或盲目重新生图
cancelled 已取消 停止轮询

HTTP 200 表示查询成功,不代表生图成功;必须检查 status。失败时会有 error 对象。gateway_status 是更细的诊断状态,业务逻辑以 status 为主。offline_task:true 是查询响应标记,不用于区分最初是否同步提交。

建议每 2–5 秒查询一次并设置总等待上限;遇到短暂网络错误或繁忙响应逐步退避。任务需在创建它的入口查询,不能任意更换 BASE_URL;图片下载链接则可以跨入口使用。

回调通知与验签

接收终态通知,按事件 ID 去重,尽快返回 2xx。

回调以 HTTP POST 发送 JSON。回调可能重复或迟到,网络成功也不等于你的业务事务成功。先持久化事件再异步处理,避免长时间占用回调连接。

JSON
{
  "event_id": "55555555-5555-4555-8555-555555555555",
  "event": "image.completed",
  "request_id": "11111111-1111-4111-8111-111111111111",
  "status": "completed",
  "offline_task": true,
  "data": [
    {
      "url": "https://api.example.com/v1/images/assets/22222222-2222-4222-8222-222222222222"
    }
  ],
  "usage": null,
  "error": null,
  "completed_at": 1790000060
}
字段 / Header 说明
event image.completed / image.failed / image.cancelled
event_id / X-Image-Event-Id 事件去重键;重试保持事件身份
request_id 关联创建任务时保存的业务订单
data 成功图片列表;失败或取消可能为空
error 失败提示可能为字符串或 null,不要假设与轮询 error 结构一致
usage 可能为 null,仅在上游提供时存在有效统计
X-Image-Timestamp 启用签名时提供的秒级 Unix 时间戳
X-Image-Signature 启用签名时为 v1= 后接 HMAC-SHA256 十六进制摘要

验签公式(签名功能需预先配置)

Formula
HMAC_SHA256(secret, timestamp + "." + raw_request_body)
Python
import hashlib
import hmac
import time

def verify_callback(raw_body: bytes, timestamp: str, signature: str,
                    secret: str) -> bool:
    try:
        if abs(int(time.time()) - int(timestamp)) > 300:
            return False
    except (TypeError, ValueError):
        return False
    expected = "v1=" + hmac.new(
        secret.encode(), timestamp.encode() + b"." + raw_body,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature or "")

必须使用原始 HTTP body 字节验签,不要先解析 JSON 再重新序列化。签名为可选能力:未配置回调签名密钥时,只发送事件 ID,不发送签名头。签名密钥不等于 API Key。未启用签名时,可在收到通知后主动查询 status_url 确认状态,再执行业务入账。

回调失败会按服务策略有限次数重试,达到上限后不再自动发送。业务应保留轮询兜底;回调失败不自动表示图片生成失败。client_reference 不保证包含在回调体内,请自行按 request_id 关联。

结果、Base64 与流式响应

根据应用场景选择传输方式,及时将成功图片保存到自己的存储。

Base64 响应

设置 response_format:"b64_json"。同步成功时 data[].b64_json 是不带 Data URL 前缀的字符串。

Python
import base64
from pathlib import Path
# 当请求 output_format="png" 时
Path("result.png").write_bytes(base64.b64decode(result["data"][0]["b64_json"]))

文件后缀应与实际输出格式一致。不要仅凭 URL 后缀判断格式,公开图片链接可能没有扩展名;以响应 Content-Type 或实际字节为准。异步轮询与回调使用 URL,不依赖提交时的 response_format 返回 Base64。

SSE 图片生成

cURL
curl -N --max-time 420 "$BASE_URL/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"gpt-image-2","prompt":"海边日出","stream":true,"output_format":"png"}'
SSE
: working

data: {"b64_json":"iVBORw0...","type":"image_generation.completed","created_at":1790000060}

data: [DONE]

图生图完成类型为 image_edit.completed。等待期间发送保活注释,图片完成后才返回完整结果,不是逐像素预览。流式会强制使用 Base64,忽略 response_format=url。客户端须按 SSE 空行边界解析事件,不要把每个 TCP 分片直接当作完整 JSON。

连接建立后的失败使用 event: error + error JSON,并发送 [DONE]。因此即使初始 HTTP 为 200,也需要检查流中的错误。断流后使用请求 ID 查询结果。

Chat 格式兼容

已有 Chat Completions 客户端也可以提交图片任务。

POST /v1/chat/completions
JSON
{
  "model": "gpt-image-2",
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "将人物背景替换为海边,保留服装和面部特征"
        },
        {
          "type": "image_url",
          "image_url": {
            "url": "https://uploads.example.com/source.png"
          }
        }
      ]
    }
  ],
  "size": "1024x1024",
  "output_format": "png",
  "stream": false
}

没有图片内容时执行文生图,有 image_url 时执行图生图。普通响应在 choices[0].message.content 返回 Markdown 图片;多张图合并在一条 assistant 回复中。支持 system / developer / user / assistant 消息,最多 128 条,至少一条 user 消息及非空描述。

JSON
{
  "object": "chat.completion",
  "choices": [{
    "index": 0,
    "message": {"role": "assistant", "content": "![image](https://api.example.com/v1/images/assets/IMAGE_ID)"},
    "finish_reason": "stop"
  }]
}

上例仅展示关键字段。stream:true 返回 chat.completion.chunk 和 [DONE],生成完成后发送完整图片 Markdown,图片使用 Base64 Data URL。它不是通用文字聊天服务,不支持工具调用、音频或异步 callback;异步请使用 Images 接口。不会伪造 token usage。

幂等、取消与重试

把“查已有结果”与“重新生成一张图”区分开。

幂等提交

在创建请求添加 Idempotency-Key,建议使用业务请求 UUID。相同账号、相同键、相同接口及相同请求内容复用已有任务;同一键修改内容会冲突。不要每次网络重试都生成新键。没有 Idempotency-Key 时可使用 X-Request-Id 作为兼容键;都不提供则自动产生新键。

操作 路径 语义
取消 POST /v1/images/tasks/{id}/cancel 仅排队任务可取消,已运行不可强行中断
恢复 / 重试交付 POST /v1/images/tasks/{id}/retry 用于恢复待检查任务或图片交付;不用于重发已完成任务的失败回调。不是重新生图接口,状态不支持时返回冲突
重新生成 POST /v1/images/tasks/{id}/resubmit 明确创建新任务,使用新的幂等键;可能产生新的用量
cURL
curl -X POST "$BASE_URL/v1/images/tasks/$REQUEST_ID/resubmit" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"idempotency_key":"new-generation-order-002"}'

结果不明的任务不能直接当作失败重新生成。先查状态,必要时联系接入支持。素材已过期的旧任务可能无法重新提交,需要重新上传并创建请求。上述修改接口需要任务所属账号的 Key。

错误处理

同时记录 HTTP 状态、error.code、error.message 和请求 ID。

JSON
{
  "error": {
    "message": "图片格式无效或尺寸超过限制,请检查上传文件",
    "type": "invalid_request_error",
    "param": null,
    "code": "invalid_image"
  }
}
HTTP 常见原因 处理建议
400 参数、图片格式、内容策略或上游明确失败 阅读具体 code / message,修改输入再重试;不是所有 400 都只是客户端拼写错误
401 Key 缺失或错误 核对 Authorization 与接入账号
404 模型 / 任务 / 图片不存在或已过期 检查入口地址、ID、模型列表与链接有效期
409 幂等冲突、素材未就绪、任务状态不允许操作 核对原请求与当前任务状态
413 请求体或单文件超出限制 减小输入;优先 URL 方式,避免 Base64 膨胀
415 不支持的上传 Content-Type 使用支持的图片 MIME 或 multipart
408 / 504 请求读取、图片读取或同步等待超时 若已受理,先查 request_id,避免重复生成
466 服务暂不可用(兼容状态码) 退避重试或查询已有任务
477 上游 / 结果处理失败(兼容状态码) 保留具体错误和 request_id 后排查
488 并发 / 队列限额(兼容状态码) 降低并发并指数退避
499 访问限制(兼容状态码) 检查账号权限与资源归属

中间接入层可能返回标准 429 / 502 / 503 等状态。不要只接受固定的 4xx / 5xx 列表;所有非 2xx 都应读取响应体并作失败处理。部分错误的 param 不存在或为 null。

error.code 说明
invalid_output_format 仅支持 png / jpeg / jpg / webp
source_fetch_failed / source_network_not_authorized 服务端无法下载输入图片或来源不允许
exactly_one_file_required 公开上传必须且仅有一个 file 字段
image_content_type_mismatch 声明 MIME 与文件字节不一致
asset_size_limit / request_too_large 文件或请求体过大
asset_not_found 图片不存在或已清理
task_still_running_query_by_request_id 同步等待结束,但任务可能仍在运行
content_policy_violation 模型策略拒绝;请修改描述或参考图

完整接入示例

服务端先上传参考图,再异步编辑并轮询。示例不包含任何真实地址或密钥。

Python · requests

安装 requests,并配置 BASE_URL、UPLOAD_BASE_URL、API_KEY、CALLBACK_URL 环境变量。CALLBACK_URL 应指向你真实可用的回调服务。下面的轮询即使收到回调也可作为兜底。

Python
import os, time, uuid
from pathlib import Path
import requests

base = os.environ["BASE_URL"].rstrip("/")
upload_base = os.environ["UPLOAD_BASE_URL"].rstrip("/")
headers = {"Authorization": "Bearer " + os.environ["API_KEY"]}

with open("reference.png", "rb") as f:
    r = requests.post(upload_base + "/v1/images/uploads",
                      files={"file": ("reference.png", f, "image/png")},
                      timeout=(10, 120))
r.raise_for_status()
image_url = r.json()["url"]

# 将 request_key 保存到业务数据库;同一次提交重试须复用此键和请求体。
request_key = str(uuid.uuid4())
payload = {
    "model": "gpt-image-2", "prompt": "保留主体,将背景替换为森林",
    "images": [{"image_url": image_url}], "n": 1,
    "size": "1024x1024", "output_format": "png",
    "callback_url": os.environ["CALLBACK_URL"],
    "client_reference": "order-001"
}
r = requests.post(base + "/v1/images/edits", json=payload,
                  headers={**headers, "Idempotency-Key": request_key},
                  timeout=(10, 120))
r.raise_for_status()
if r.status_code != 202:
    raise RuntimeError("Expected async acceptance: " + r.text)
accepted = r.json()
status_url = accepted["status_url"]  # 保存它,不要换到另一入口查询
print("request_id:", accepted["request_id"])

deadline = time.monotonic() + 900
while time.monotonic() < deadline:
    time.sleep(3)
    try:
        r = requests.get(status_url, timeout=(10, 30))  # 不需要 API Key
    except (requests.Timeout, requests.ConnectionError):
        continue
    if r.status_code in (429, 466, 477, 488, 502, 503, 504):
        time.sleep(5)
        continue
    r.raise_for_status()
    task = r.json()
    if task["status"] == "completed":
        for i, item in enumerate(task["data"]):
            image = requests.get(item["url"], timeout=(10, 120))
            image.raise_for_status()
            Path(f"result-{i}.png").write_bytes(image.content)
        break
    if task["status"] in ("failed", "cancelled"):
        raise RuntimeError(task.get("error") or task["status"])
else:
    raise TimeoutError("本地等待结束,任务未必失败;继续使用已保存的 status_url 查询")

JavaScript · Node.js 20+ · 上传后同步编辑

JavaScript
import { readFile, writeFile } from "node:fs/promises";

const base = process.env.BASE_URL.replace(/\/$/, "");
const uploadBase = process.env.UPLOAD_BASE_URL.replace(/\/$/, "");
const form = new FormData();
form.append("file", new Blob([await readFile("reference.png")],
  { type: "image/png" }), "reference.png");

async function jsonResponse(response) {
  const text = await response.text();
  if (!response.ok) throw new Error(`HTTP ${response.status}: ${text}`);
  return JSON.parse(text);
}
const uploaded = await jsonResponse(await fetch(uploadBase + "/v1/images/uploads", {
  method: "POST", body: form, signal: AbortSignal.timeout(120000)
}));
const requestKey = crypto.randomUUID(); // 持久化;网络重试时复用
const response = await fetch(base + "/v1/images/edits", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": requestKey
  },
  body: JSON.stringify({
    model: "gpt-image-2", prompt: "保留主体,背景改为蓝天",
    images: [{ image_url: uploaded.url }], n: 1,
    size: "1024x1024", output_format: "png", response_format: "url"
  }),
  signal: AbortSignal.timeout(420000)
});
console.log("request_id:", response.headers.get("x-request-id"));
const result = await jsonResponse(response);
for (const [index, image] of result.data.entries()) {
  const download = await fetch(image.url, { signal: AbortSignal.timeout(120000) });
  if (!download.ok) throw new Error(`Download HTTP ${download.status}`);
  await writeFile(`result-${index}.png`, Buffer.from(await download.arrayBuffer()));
}

下载速度与访问排查

生成快但图片显示慢,通常需要把生成阶段与图片传输阶段分开诊断。

阶段 1 排队与模型生成 阶段 2 上传 / 图片下载 阶段 3 浏览器解码与显示

为什么显示生成 40 秒,图片却几分钟才出现?

生成耗时不等于页面可见耗时。图片生成完成、API 返回 URL、浏览器下载完大图,是不同的时间点。若任务已经 completed、图片 URL 已返回,但页面继续转圈或缓慢加载,优先检查图片下载链路;如果状态仍是 generating / delivering,则还可能在生成或上传,不能一概归因于浏览器下载。

时间示例
页面完整可见时间 ≈ 排队 + 生成 +(可选 CDN 交付)+ 图片下载 + 解码 / 渲染

示例:生成 40 秒,图片文件 15 MB,实际下载速度只有 100 KB/s
仅下载就约需 150 秒,再加生成约 190 秒,页面可能 3 分钟以上才显示完整图片。

以上是说明时间差的示例,不是测速结果或服务时限承诺。接口返回 URL 很快,不意味着对应图片字节也已传到浏览器;Base64 响应还会增加约三分之一的传输体积。

海外链路的三种接入方式

方式 适合谁 怎么做 / 局限
稳定的海外代理线路 本地调试、浏览器访问或低频使用 让网页与图片请求实际走稳定海外线路。只给 API 请求配代理、图片仍直连,页面依然可能加载很慢;浏览器代理不一定影响服务器、SDK 或 cURL
海外服务器接收并转存 后端批量处理、任务系统 用海外后端接收回调并主动下载图片,保存到自己的存储 / CDN。只在海外接收包含 URL 的回调,不会自动让国内浏览器下载变快
对接用户就近访问的 CDN 面向终端用户的网站 / 应用 使用 cdn_key 或自己的转存流程,让浏览器加载 CDN URL。选择目标地区连通性好的 CDN;首次回源仍可能较慢

服务链路包含海外资源,部分地区直连可能不稳定。需要正常访问速度时,优先使用稳定的海外代理线路,或将调用与接收部署在海外服务器。面向大量终端用户时,更适合把最终图片交付到可稳定访问的 CDN。

区分慢在哪里

观察结果 更可能的阶段 下一步
任务仍 queued 排队 降低突发并发,继续轮询
任务仍 generating 模型生成 检查任务状态和错误,等待或联系接入方
任务 delivering CDN 上传 / 交付 核对存储配置、上传网络及服务端日志
JSON 已返回 URL,图片 GET 很久才结束 下载链路 切换代理 / 海外服务器测速,检查 CDN
图片 GET 完成后仍卡顿 客户端解码 / 渲染 降低同时加载张数、检查超大图与内存占用,使用缩略图预览
只首次访问 CDN 图片慢 缓存未命中或回源慢 检查缓存规则与回源链路,不用重新生成图片

下载测速示例(不会触发生图)

cURL
curl -L --max-time 180 -o /dev/null -sS \
  -w 'HTTP=%{http_code} DNS=%{time_namelookup}s CONNECT=%{time_connect}s TTFB=%{time_starttransfer}s TOTAL=%{time_total}s BYTES=%{size_download} SPEED=%{speed_download}B/s\n' \
  "$IMAGE_URL"

在本地直连、代理线路、海外服务器分别测试同一张图片。TTFB 是到首字节的累计时间,TOTAL 是整次下载时间;这条命令测的是下载,不包含浏览器解码。公开图片 URL 不需要生图 API Key,不要将 Key 发给图片域名。

网站打不开或访问卡顿

先尝试稳定海外代理线路访问,确认代理不仅开启,而且覆盖目标网页与图片请求。若更换线路后恢复,通常与当前直连网络或跨境链路有关。若代理和海外服务器访问也失败,应检查网站状态、DNS、TLS 证书、403 访问拦截或 5xx 服务错误,不能把所有故障都视为“缺少代理”。

网页能打开但图片卡,重点检查图片请求;网页本身打不开,先检查网页域名。CDN 接入只影响配置的图片分发,不会自动解决控制台页面、登录请求或 API 本身的网络问题。

接入检查与常见问题

上线前,用最小请求逐步验证整个链路。

  1. 使用正确的 BASE_URL 和 Key 拉取 /v1/models。
  2. 以 n=1 完成一次文生图,确认 data 中的图片可下载。
  3. 免 Key 上传 PNG,确认返回的 URL 可由服务器访问。
  4. 将 URL 放入 images 数组调用 edits,验证图生图。
  5. 配置真实回调地址,保存 202 中的 request_id 与 status_url。
  6. 验证成功、失败、超时后的轮询及回调去重。
  7. 以同一幂等键重发同一请求,确保业务不会重复创建任务。
  8. 保存最终图片到自己的存储,不长期依赖临时链接。
  9. 配置 CDN 时确认 cdn_key 已授权,并验证返回域名、实际下载和 Content-Type。
  10. 分别在本地、代理线路与海外服务器检查图片下载,区分生成、传输和解码耗时。
  11. 按尺寸表验证需要的比例,避开明确标为不支持的组合。
上传和生图可以使用不同的地址吗?

可以。上传链接只要能被生图服务从服务端公开访问即可;上传无需生图 Key。任务查询则应使用创建任务时返回的 status_url。

收到 202,为什么还没有图片?

202 表示受理。等待 status=completed 后读取 data;或处理 image.completed 回调。HTTP 200 的任务查询也可能是 running 或 failed。

可以不提供 callback_url,直接 async=true 吗?

当前 Images 接口通过 callback_url 开启异步。没有此字段且 stream=false 时会同步等待。请配置真实回调地址,再使用轮询作为结果读取或兜底。

为什么 URL 在浏览器能打开,图生图却失败?

浏览器可能带了登录 Cookie,或源站有防盗链、IP 限制。确认无需任何认证即可 GET 到实际图片字节,而非 HTML 页面;检查图片是否过期、格式和大小是否合规。

超时后可以立即重新生成吗?

先使用 request_id 查询。超时只意味着客户端没有及时拿到结果,任务可能仍在执行。没有拿到任务 ID 时,复用原幂等键及请求体,避免换键产生重复任务。

网页文档会存储我的 Key 或发送测试请求吗?

不会。此页只提供说明和代码复制,不收集 API Key,也不会自动调用生成或上传接口。

为什么图片下载很慢,必须用代理吗?

海外资源在部分网络直连速度较差。可用稳定海外代理线路改善本地访问,或由海外后端下载后转存 CDN。是否必须用代理取决于实际链路;面向用户的产品建议提供可就近访问的 CDN 链接。详见下载排查。

为什么生图只要 40 秒,网页却几分钟才渲染?

生成时间通常不包含浏览器下载和解码。任务已完成后,低速下载大图可能花数分钟。先看图片请求的 TOTAL、下载字节数与速度;若图片已下载完才卡,再查浏览器内存和渲染性能。

网站打不开、网站卡顿怎么办?

先尝试稳定海外代理,确认网页请求确实走代理。若仅直连慢,重点处理网络线路;若海外线路也不通,检查 DNS、证书、HTTP 状态及服务可用性。不要反复刷新或重复提交生图来测试网站。

创建 CDN Key 后为什么还是不能用?

需确认 CDN 配置启用、Key 启用,以及接入方已给生图账号授权。出现 cdn_key_not_authorized 时先处理授权;存储密钥正确也不能替代这一步。

用了 CDN,为什么第一次访问还是慢?

第一次可能需要回源;跨区域网络、源站带宽与文件大小仍影响速度。确认返回的是自己的 CDN 域名,并检查缓存命中情况。只填海外存储原始域名,不一定获得就近加速。

能用 CDN 加快模型生成吗?

CDN 主要改善生成结果的下载与分发,不直接缩短模型生成。配置 CDN 还会增加一次交付步骤;应分别衡量生成时间、CDN 上传时间与最终用户下载时间。

4K 必须写 4096x4096 吗?

不是。4K 是档位名称,当前正方形预设为 3840x3840,不同比例宽高不同。请按14 种比例表选择,不要把 size 写成字符串 4k。

为什么 1K 的 3:4 不是严格 3:4?

历史预设映射为 896x1152,是近似比例。需要严格画布比例时写明确像素尺寸,例如 768x1024,并确认模型输出尺寸;不要只依据预设标签推断最终宽高。

为什么生成后又上传到我的 CDN,链接没有 .png?

对象按任务 ID 与图片序号保存,URL 不必带文件扩展名。浏览器依赖 Content-Type 识别格式。下载保存时根据实际类型设置文件名即可。

返回 b64_json 会比 URL 更快吗?

不一定。Base64 体积通常比原始图片大约三分之一,还需解析与解码。面向浏览器展示时,URL + CDN 更容易缓存和按需加载。

上传 URL 过期后,换一个生图接口就能恢复吗?

不能。链接过期是素材已经清理,需要重新上传原文件。跨入口只改变谁下载图片,不会恢复已删除素材;同内容重复上传也不承诺刷新旧素材的保留时间。

浏览器报 CORS,但后端调用正常怎么办?

检查实际接入地址是否允许你的网页来源和请求头;图片 CDN 的下载 / Canvas 使用也可能需要单独配置 CORS。建议用自己的后端调用生图接口,不要为了调试把 Key 暴露到网页源码。

提示 401、额度不足或模型不存在怎么办?

401 核对 Key 和 Base URL 是否来自同一平台;额度与分组限制到控制台查看;模型不存在先请求 /v1/models。不要把分组显示名、模型别名或截图中的脱敏 Key 直接用于请求。

回调收不到,可以直接重新生图吗?

先用 status_url 查询已有任务。检查回调地址连通性、HTTPS、接口是否接受 POST,以及是否快速返回 2xx。回调中断不表示图片生成失败,重复生成可能产生额外用量。