GPT Image 文生图 API
通过 BetterToken 的 OpenAI-compatible API 调用 GPT Image 生成图片,包含 API Key、Base URL、参数、Python、JavaScript 与错误处理。
POST /v1/images/generations
文生图接口使用 application/json 请求体。你提交提示词后,接口会同步等待生成完成,并在同一个响应的 data[].b64_json 中返回各张图片。
选择对应场景
- 根据文本生成并保存图片:继续使用本页。先运行下方
curl示例,再按照 保存返回图片 读取并解码data[]中的每张图片。 - 编辑已有图片:前往图片编辑 API,上传一张或多张参考图;需要局部编辑时可额外上传 mask。
- 选择模型、查看参数并估算预算:在模型广场核对当前可用 Model ID 和价格。完整工作流可阅读 GPT Image 2 指南。
使用 curl 快速调用
先将 YOUR_API_KEY 替换为你的 BetterToken API Key。一个 Key 可调用所有可用模型。以下请求将完整响应保存到 response.json,供后面的 Python 示例读取:
curl --max-time 300 -X POST "https://bettertoken.ai/v1/images/generations" \ -o response.json \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-image-2", "prompt": "A product photo of a green ceramic mug on a studio table", "size": "1024x1024", "n": 1, "response_format": "b64_json", "output_format": "png" }'推荐请求值
以下是起步建议,并非固定要求。建议先使用 n=1;接口接受 1 到 10 的整数,但实际返回图片数可能少于请求数。
{ "model": "gpt-image-2", "n": 1, "response_format": "b64_json", "output_format": "png"}| 参数 | 填写内容 | 作用 |
|---|---|---|
model | gpt-image-2、gpt-image-2.5-flare 或 gpt-image-2.5-sunburst | 选择模型广场中显示可用的 Model ID。ID 和参数合法不代表当前请求一定能使用该模型、尺寸或操作。 |
prompt | 文本描述 | 必填。描述主体、风格、构图和重要限制。 |
size | 省略、使用 auto 或提供如 1024x1024 的尺寸 | 请求输出尺寸和比例;实际交付尺寸可能不同。 |
n | 1 到 10 的整数 | 请求图片数上限。建议从 1 开始;实际返回数可能更少。 |
quality | gpt-image-2 支持 auto、low、medium、high;两个 2.5 模型还接受 xhigh、max | 可选质量偏好。省略或在 JSON 中设为 null 时使用默认值。参数被接受不保证画面质量随档位提高。 |
response_format | b64_json | 在 data[].b64_json 中以 base64 返回每张图片。 |
output_format | 例如 png | 请求输出格式。保存前根据文件字节识别实际格式,需要固定编码时按需转码。 |
实际返回图片数可能少于 n。请处理 data[] 中的每一项;建议使用 n=1 不代表服务端限制为一张。
推荐尺寸
size | 比例 | 适用场景 |
|---|---|---|
auto | 自动 | 自动选择尺寸 |
1024x1024 | 1:1 | 方图,通用头像、封面、素材图 |
1536x1024 | 3:2 | 横图,海报、banner、场景图 |
1024x1536 | 2:3 | 竖图,移动端封面、人物海报 |
1536x1152 | 4:3 | 标准横图,商品图、内容配图、横版素材 |
1152x1536 | 3:4 | 标准竖图,移动端封面、竖版海报、人物图 |
2048x2048 | 1:1 | 高清方图 |
2048x1152 | 16:9 | 高清横图 |
3840x2160 | 16:9 | 4K 横图 |
2160x3840 | 9:16 | 4K 竖图 |
表格列出常用示例,并非封闭清单。你可以省略 size 或设为 auto;JSON 中的 size: null 也会自动选择尺寸。显式宽高必须为正数且是 16 的倍数,各不超过 3840,宽高比不超过 3:1,像素总数为 655360 到 8294400。例如 2080x2080 是合法尺寸。请求尺寸表示目标,实际交付尺寸可能不同;请读取图片真实尺寸,不要强行裁切。
保存返回图片
成功响应为 OpenAI 兼容图片响应结构。下面的金额用于展示回执格式,不代表固定价格:
{ "created": 1710000000, "data": [ { "b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)", "revised_prompt": "Optional revised prompt" } ], "bettertoken_image_billing": { "currency": "CNY", "settled_amount": "0.15", "outputs": [ { "index": 0, "width": 1254, "height": 1254, "billing_resolution": "2K", "currency": "CNY", "amount": "0.15" } ] }}客户端应读取 data[].b64_json 并允许 revised_prompt 等额外字段。BetterToken 在根级 bettertoken_image_billing 对象中返回计费明细,其中 settled_amount 和每张图片的 amount 是十进制字符串,outputs[].index 从 0 开始。该对象中的实际交付尺寸和 billing_resolution 是本次请求计费结果的依据。
保存图片时按返回字节识别真实格式,再选择文件扩展名。以下标准库示例可识别 PNG、JPEG 和 WebP,无需新增依赖。
import base64import jsonfrom pathlib import Path
result = json.loads(Path("response.json").read_text(encoding="utf-8"))for index, item in enumerate(result["data"], start=1): encoded = item["b64_json"] if "," in encoded and "base64" in encoded.split(",", 1)[0]: encoded = encoded.split(",", 1)[1] image_bytes = base64.b64decode(encoded) if image_bytes.startswith(b"\x89PNG\r\n\x1a\n"): extension = "png" elif image_bytes.startswith(b"\xff\xd8\xff"): extension = "jpg" elif image_bytes.startswith(b"RIFF") and image_bytes[8:12] == b"WEBP": extension = "webp" else: raise ValueError("Unsupported image signature") Path(f"output-{index}.{extension}").write_bytes(image_bytes)JavaScript 示例(Node.js)
import { writeFile } from "node:fs/promises";
const response = await fetch("https://bettertoken.ai/v1/images/generations", { method: "POST", headers: { Authorization: "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ model: "gpt-image-2", prompt: "A green ceramic mug on a studio table", size: "1024x1024", n: 1, response_format: "b64_json", output_format: "png", }),});
if (!response.ok) { throw new Error(await response.text());}
const result = await response.json();const { data } = result;for (const [index, item] of data.entries()) { const b64Json = item.b64_json.replace(/^data:.*;base64,/, ""); const imageBytes = Buffer.from(b64Json, "base64"); let extension; if (imageBytes.subarray(0, 8).equals(Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]))) { extension = "png"; } else if (imageBytes[0] === 0xff && imageBytes[1] === 0xd8 && imageBytes[2] === 0xff) { extension = "jpg"; } else if (imageBytes.toString("ascii", 0, 4) === "RIFF" && imageBytes.toString("ascii", 8, 12) === "WEBP") { extension = "webp"; } else { throw new Error("Unsupported image signature"); } await writeFile(`output-${index + 1}.${extension}`, imageBytes);}若业务要求固定的 PNG、JPEG 或 WebP 编码,请在识别实际格式后按需转码;仅修改扩展名不会转换图片。
读取实际费用
bettertoken_image_billing 随生成结果一起返回,无需额外调用费用查询接口。
| 字段 | 含义 |
|---|---|
currency | 本次结算币种。不要假定始终为 USD 或 CNY。 |
settled_amount | 本次请求实际结算总额,使用十进制字符串表示。 |
requested_resolution | 根据请求识别的尺寸档位。 |
outputs[].index | 图片编号,从 0 开始,对应 data[]。 |
outputs[].width、height | 对应图片的实际宽、高,单位为像素。 |
outputs[].billing_resolution | 对应图片最终使用的计费档位。 |
outputs[].currency、amount | 对应图片的结算币种和金额。 |
请求尺寸与计费档位可能不同。例如,已有请求 1024×1024、实际返回 1254×1254 并按 2K 结算的结果。请读取回执中的实际金额;当前单价在模型广场查看。
下面的代码接在 Python 保存示例后使用。金额保留为字符串展示;需要计算时使用十进制类型,避免浮点误差。缺少回执时不能把费用记为零。
from decimal import Decimal
billing = result.get("bettertoken_image_billing")if billing is None: print("Billing receipt unavailable; check your usage records.")else: total = Decimal(billing["settled_amount"]) print(f"Total: {billing['currency']} {total}") for output in billing.get("outputs", []): print( f"Image {output['index'] + 1}: " f"{output['width']}x{output['height']}, " f"{output['billing_resolution']}, " f"{output['currency']} {output['amount']}" )响应流程
文生图接口是同步响应模式。客户端提交 POST /images/generations 后,应保持当前 HTTP 请求连接并等待服务端返回。生成成功时,每张图片都在同一响应的 data[].b64_json 中返回,并附有交付与计费明细。
文生图不会返回 task_id,也没有单独的状态查询接口或结果下载接口。不需要轮询任务状态,也不能通过额外的 /images/... URL 再获取结果。
超时、重试和计费
HTTP 客户端超时建议设置为数分钟。超时、断连或含义不明的 5xx 不能证明生成是否执行或计费;结算后写回结果时连接也可能失败,因此存在重复计费风险。不要自动重复生成或编辑 POST。先检查消费记录或请求日志,保留返回的 request ID,以及已收到时的 X-BetterToken-Image-Receipt 和 X-BetterToken-Billing-State 响应头。客户端自行生成的 request ID 不会让服务端具备幂等性;主动重发可能产生新请求和新费用。没有单独的状态查询接口。
先修正被拒绝的输入、认证或额度问题。只有确认 429 表示请求已被拒绝后,才可退避重试。不要把所有 5xx 或传输异常都视为可安全重试。
处理请求前,BetterToken 可能按最高适用单价乘以 n 预授权上限,再按实际交付图片结算。因此,余额可能足以支付实际交付的 1K 图片,却不足以通过这笔预授权;此时请求返回 403,且 error.code=insufficient_user_quota。根级 bettertoken_image_billing 返回最终 settled_amount、币种,以及每张图片的 amount、billing_resolution 和交付尺寸;金额为十进制字符串。实际交付数可能少于 n。
错误处理
错误响应通常是 JSON。展示错误时,建议按顺序读取:
error.messagemessage- HTTP status text
| HTTP 状态码 | 含义 | 建议处理 |
|---|---|---|
400 | 请求格式错误、缺少参数、JSON 解析失败、尺寸格式错误 | 检查请求体,不要自动重试。 |
401 | API Key 缺失或无效 | 检查 Authorization header。 |
402 或 403 | 额度或余额不足,包括余额冻结 | 检查 error.code 及账户额度/余额。403 且 error.code=insufficient_user_quota 表示余额可能低于预授权上限。 |
429 | 触发限速、并发限制或上游繁忙 | 确认请求已被拒绝后再退避重试。 |
5xx | 网关或上游服务异常 | 执行与计费状态可能未知。考虑主动重发前,先核对请求日志和消费记录。 |
接入检查清单
- Base URL 是
https://bettertoken.ai/v1。 - Header 包含
Authorization: Bearer sk-...。 - 请求使用
application/json。 - 选择当前请求可用的 Model ID:
gpt-image-2、gpt-image-2.5-flare或gpt-image-2.5-sunburst。 - 使用
response_format=b64_json;output_format只是请求值,保存时按字节识别格式。 n可设为1到10;建议使用1,实际返回数可能更少。size可省略、设为auto或填写有效尺寸;上表不是封闭清单。- 客户端能处理数分钟级别的生成耗时。
- 日志和报错截图中不会泄露 API Key 或完整 base64 图片内容。
相关文档
/v1/images/generations授权
Use your BetterToken API Key as a bearer token. Do not expose API keys in frontend browser code, screenshots, logs, tickets, or Git repositories.
请求体 application/json
GPT Image 模型 ID。一个 BetterToken API Key 可调用所有可用模型。
"gpt-image-2"省略或 auto 使用自动尺寸。WxH 的宽高必须为正数且均为 16 的倍数,单边不超过 3840,长短边比不超过 3:1,总像素为 655360~8294400。示例不是封闭枚举,例如 2080x2080 也符合几何约束。实际输出以解码尺寸为准;参数合法不保证有对应可用服务。
"1024x1024"["auto","1024x1024","2048x2048","2080x2080","3840x2160"]请求的输出格式,例如 png。保存时按实际图片字节识别 PNG、JPEG 或 WebP,再选择对应扩展名;需要固定编码时按需转码。
"png"画质选项:gpt-image-2 使用 auto、low、medium、high;两款 2.5 模型还接受 xhigh、max。省略时使用模型默认值;JSON null 按未填写处理,multipart 必须填写非空字符串。参数合法不保证当前有对应模型、尺寸和编辑组合的可用服务。参数接受不保证画面质量随档位提高。
"auto"响应
200BetterToken 扩展计费信息。按实际交付图片的像素与计费档位结算;请求档位不保证等于计费档位。金额是十进制字符串,以响应为准。
OpenAI 兼容图片响应。遍历 data[],读取每张图片的 b64_json,并允许 revised_prompt 等额外字段。实际交付数量可能少于请求数量。
1710000000Show child attributes
Optional revised prompt.
BetterToken 扩展计费信息。按实际交付图片的像素与计费档位结算;请求档位不保证等于计费档位。金额是十进制字符串,以响应为准。
Show child attributes
本次结算币种,不应假定为固定币种。
本次实际结算总额,十进制字符串;计算时使用十进制类型。
实际交付图片的编号、真实尺寸、计费档位和单张金额。index 从 0 开始,对应 data[] 中的图片。
对应图片的实际结算金额,十进制字符串。
根据请求识别的尺寸档位,可能与实际计费档位不同。
{
"created": 1710000000,
"data": [
{
"b64_json": "iVBORw0KGgoAAAANSUhEUgAA...(truncated)",
"revised_prompt": "<string>"
}
],
"bettertoken_image_billing": {
"currency": "<string>",
"settled_amount": "<string>",
"outputs": [
{
"index": 0,
"width": 1,
"height": 1,
"billing_resolution": "1K",
"currency": "<string>",
"amount": "<string>"
}
],
"partial": false,
"requested_resolution": "<string>"
}
}400请求格式错误、缺少参数、JSON 或 multipart 解析失败、尺寸格式错误。
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}401API Key 缺失或无效。
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}402额度或余额不足。
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}403余额或令牌额度不足,error.code 为 insufficient_user_quota。也可能不足以预占最高档单价乘图片数量上限的额度;按实际交付结算。结合 error.code 判断,不要只按 403 认定为权限错误。
{
"error": {
"code": "insufficient_user_quota",
"message": "Insufficient balance or token quota."
}
}429触发限速、并发限制或上游繁忙。
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}500网关或上游服务异常。
Show child attributes
"invalid request""invalid_request_error""invalid_request""insufficient quota"{
"error": {
"message": "invalid request",
"type": "invalid_request_error",
"code": "invalid_request"
},
"message": "insufficient quota"
}
