画境 API 图片与视频开放接口
返回工作台

API 文档

画境生成开放接口。用 API Key 可调用文生图、图生图与 MiniMax H3 视频生成,额度与网页端共用同一个账户。

价格、模型、参数

接模型先看这几张表:价格、扣费、模型、请求参数、1K/2K。单价打开本页后会按当前站点配置刷新。程序里请再调 GET /v1/pricing,不要把数字写死。

文档地址就是 /docs/。本站支持图像生成和 MiniMax H3 视频生成。图像模型参数与价格见模型表;视频按时长和分辨率计价,参数见视频接口。

价格

余额单位是「分」。1 元 = 100 分,所以 0.5 分 = 0.005 元,1 分 = 0.01 元。下面数字是当前站点价格。

类型单价(分 / 张)折合人民币对应接口
文生图 1 0.01 元 POST /v1/images/generations
图生图 2.5 0.025 元 POST /v1/images/edits
图片超分(画布超分) 2K 1 · 4K 2 · 8K 4 分/张 按分辨率计费 POST /v1/images/upscale
MiniMax H3 视频按分辨率与时长计费POST /v1/videos/generations
查余额 / 模型 / 流水 / 健康检查 0 0 元 其余接口不扣费

图像扣费:按请求张数预扣并结算

同步图像请求按请求的 n 预扣;异步图像任务按站点配置的最多输出张数预扣。任务完成后按实际输出张数结算,多扣部分退回。上限为 3 张。

步骤发生什么举例(文生图,实际出 1 张)
1. 预扣 同步按 单价 × n;异步按 单价 × max_output_images 1 分 × 3 张 = 异步最多预扣 3 分
2. 出图 生成服务实际出了几张,就算几张 实际出了 1 张
3. 结算 多扣的立刻退回。响应里的 cost 是实花,balance 是结算后余额 退回 2 分,本次实花 1 分
失败 提示词被拒、超时、没节点、进程重启,预扣都会全额退 实花 0 分

所以流水里一次成功生成会看到两条:一条预扣、一条退差额。把两条加起来才是净花费。

MiniMax H3 视频按 分辨率单价 × 视频秒数 + 参考图单价 × 张数预扣;成功后按预扣额结算,失败全额退回。接口只返回本站费用与余额。

可用模型

请求里的 model 只接受下表 id。参数相同、价格相同,差别主要在出图像素。不填则用站点默认(当前 gpt-image-2.5)。GPT Image 2.5 当前默认使用 low 质量档。

请求里写 model界面显示名出图大概多大说明
gpt-image-2.5 GPT Image 2.5 2K,长边约 1920–2560,总像素约 370 万 站点模型标识。默认使用 low 质量档。
gpt-image-2.5-high GPT Image 2.5 high 固定 1K(画布原生画质) 走无限画布的生成链路(与网页画布同一接口 GenerateImage),不受 resolution 影响,永远出 1K。要 2K 请改用 gpt-image-2.5。
nano-banana-2 Nano Banana 2 默认 2048 × 2048 PNG 口语里的 Banana 2 / nano 2。
nano-banana-pro Nano Banana Pro 默认 2048 × 2048 PNG 口语里的 Banana Pro。旧值 nano-banana 会自动转到这里。
minimax-h3MiniMax H3视频模型使用 /v1/videos 接口;配置费率与参数见 GET /v1/videos/config

不要传这些

有人会写成结果正确写法
nano 报 unsupported_model nano-banana-2 或 nano-banana-pro
gpt image / gpt-image-1.5 报错(id 必须完全一致) gpt-image-2.5
sd2 / sd2.5 / Stable Diffusion 本站没有这些模型 改用上表之一
视频、语音、对话 Agent 不是图像模型 id 视频使用专用的 /v1/videos 接口

各模型共用的请求参数

参数必填取值说明
prompt 必填 文字,最长 12000 字 主体、场景、光线、镜头写清楚。服务端会自动加「生成图片:」前缀,你不用自己加。
model 可选 gpt-image-2.5 / gpt-image-2.5-high / nano-banana-2 / nano-banana-pro 不填用站点默认。填了不支持的值直接报错,不会悄悄换成别的模型。gpt-image-2.5-high 固定 1K。
ratio 可选 1:1 16:9 9:16 4:3 3:4 留空由模型自己决定。这是倾向性引导,不是硬裁切,出图可能略有偏差。
resolution 可选 1k / 2k,默认 2k 见下一张表。传 4k 不会报错,按 2k 出原图;要更高分辨率请走 图片超分(2K/4K/8K),不要传 resolution=4k。gpt-image-2.5-high 例外:忽略此参数,固定出 1K。
参考图 仅图生图必填 文件、data URL 或 https 图片地址,最多 max_reference_images 张(以 GET /v1/pricing 的实时值为准) 只出现在 POST /v1/images/edits。1 张走原生上传;多张走链接文本模式(服务端把每张图转成站内链接写进提示词)。超过上限才返回 too_many_reference_images。

resolution:1K 和 2K

传这个拿到什么格式什么时候用
2k 原图,约 2K–2.5K 无损 PNG 要成品就用这个,也是默认值
1k 长边压到 1024 的预览 有损 webp,体积大约是原图的 1/40 列表缩略、快速看效果。价格和 2K 相同
4k 已下线(普通出图接口) — 生成服务原生出图就到 2K–2.5K。继续传会回落到 2k

各比例大概尺寸(resolution=2k)

GPT Image 2.5(默认 low 档)实测。总像素大致固定,选宽幅不会让你多拿到画面,只是把同样多的像素铺成更宽的形状。Nano Banana 2 / Pro 默认是 2048 × 2048。

ratio2K 原图长边1K 预览
1:11920 × 192019201024 × 1024
4:32176 × 163221761024 × 768
16:92560 × 144025601024 × 576
3:41632 × 21762176768 × 1024
9:161440 × 25602560576 × 1024

其它上限

限制默认说明
单次最多出图3异步图像预扣上限;同步按请求的 n 预扣
图生图参考图按配置最多 max_reference_images 张,以接口实时值为准
同时进行的生成任务9999单用户并发,默认 9999
异步任务排队上限9999排队 + 进行中合计,默认 9999
单号同时出图1号池有空闲时一号一图;全忙才叠到同一号
客户端超时320 秒以上同步接口通常 1–5 分钟。异步提交立刻返回,轮询 /v1/images/tasks/:id 即可

网页端和 API 共用同一套价格、模型和参数。登录工作台也能直接出图;要接自己的系统,往下看鉴权和接口说明。

概览

本站同时提供两套开放协议,共用同一把 API Key、同一份余额和同一套模型,按你手上客户端支持的协议选一套即可:

  • OpenAI 兼容接口:全部在 /v1 下,请求与响应均为 JSON(图生图额外支持 multipart 上传),风格接近 OpenAI Images API,并兼容 CPA、NewAPI、Sub2 常见的 Bearer / x-api-key 鉴权、/v1/chat/completions 图片调用和 /api/v1 路径别名。
  • Gemini 原生接口:在 /v1beta/models/... 下,按 Google 官方 GenerateContent / Predict 协议收发,鉴权用 x-goog-api-key 或 ?key=,图片以 inlineData(base64) 返回。详见 Gemini 兼容接口。

中转兼容提示:OpenAI 类客户端 Base URL 可以填本站根地址、/v1 或 /api/v1,重复拼接成 /v1/v1/... 也会自动归一化。Gemini 类客户端 Base URL 填本站根地址即可(/v1beta/models/... 是 Gemini 原生协议,不再当作 OpenAI 路径别名)。两套协议都只支持本文档列出的模型,未知模型不会静默切换。

Base URL

https://your-domain.example/v1

本页所有示例里的地址已经自动替换成你当前访问的域名,复制下来就能直接跑,不用再手动改。

接口一览

5 分钟上手

  1. 创建密钥。登录网页端,进入「API 密钥」标签页,填个备注后点「创建密钥」。密钥形如 mk- 加 48 位十六进制字符,只显示这一次,请立刻保存。可以把密钥绑定到一个图像或视频模型,再把用途限制为文生图、图生图或视频生成。
  2. 确认有额度。调 GET /v1/balance 看看余额;没有的话用兑换码或在网页端充值。
  3. 发第一个请求。下面这条命令会生成一张图并返回可直接下载的 URL。
curl -X POST https://your-domain.example/v1/images/generations \
  -H "Authorization: Bearer mk-你的密钥" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "一只在草地上奔跑的柴犬,逆光,浅景深,35mm 胶片质感",
    "ratio": "16:9",
    "resolution": "2k"
  }'

返回:

{
  "ok": true,
  "images": ["https://.../a1b2c3.png"],
  "resolution": "2k",
  "model": "gpt-image-2.5",
  "cost": 0.5,
  "image_count": 1,
  "balance": 999,
  "session_id": "a8f3d2e1"
}

生成很慢,这是正常的。单次生成通常 1-5 分钟。同步接口会一直挂着直到出图,客户端超时请设到 320 秒以上。不想阻塞就用异步接口:提交立刻返回任务 id,再按 2-3 秒间隔轮询结果。

鉴权

每个请求都要带上 API Key。/v1(OpenAI 协议)支持下面两种写法,任选其一,效果完全相同:

Authorization: Bearer mk-xxxxxxxxxxxxxxxx
x-api-key: mk-xxxxxxxxxxxxxxxx

/v1beta(Gemini 协议)额外支持官方 SDK 的两种写法;四种方式都指向同一把密钥、同一个账户,可以混用:

x-goog-api-key: mk-xxxxxxxxxxxxxxxx
?key=mk-xxxxxxxxxxxxxxxx

密钥的性质

  • 格式为 mk- + 48 位十六进制字符,共 51 个字符。
  • 服务端只保存 SHA-256 摘要,不存明文。密钥丢了没有任何找回途径,只能删掉重建。
  • 一个账户可以创建多个密钥,便于按用途区分和单独吊销。列表里只显示前 10 位加掩码,例如 mk-a1b2c3d********。
  • 删除(吊销)后立即失效,正在使用它的程序会开始收到 401 api_key_revoked。
  • 密钥代表账户全部权限,可以花掉账户余额。不要写进前端代码、不要提交进 Git 仓库。

按模型分开的密钥

创建密钥时可以绑定一个模型,这把密钥之后就只能调那一个模型。可绑定图像模型或 minimax-h3 视频模型;绑定视频模型后仅能调用视频接口。

密钥类型请求不带 model请求带别的 model
不限模型(默认)用站点默认模型照请求的模型执行
绑定 gpt-image-2.5用 gpt-image-2.5403 model_not_allowed
绑定 gpt-image-2.5-high用 gpt-image-2.5-high(固定 1K)403 model_not_allowed
绑定 nano-banana-2用 nano-banana-2403 model_not_allowed
绑定 nano-banana-pro用 nano-banana-pro403 model_not_allowed
绑定 minimax-h3视频接口使用 minimax-h3图像接口返回 403 model_not_allowed

绑定关系在 GET /v1/me 的 key.model 里能查到;GET /v1/models 对绑定过的密钥只会列出它能用的那一个模型,照着这个列表选模型就不会踩到 model_not_allowed。绑定只能在创建时指定,事后改不了——需要换模型就再建一把。

老密钥(这个功能上线之前创建的)一律算「不限模型」,行为和以前完全一致,不用改代码。

按用途分开的密钥

创建密钥时还可以限定用途。它和「绑定模型」相互独立,可以自由组合,比如「不限模型 + 仅图生图」。用途只能调用对应形态的接口,调另一种会返回 403 scope_not_allowed,不扣费。

用途文生图图生图视频生成
不限用途(默认,老 Key 等同)是是是
text 仅文生图是403 scope_not_allowed403 scope_not_allowed
edit 仅图生图403 scope_not_allowed是403 scope_not_allowed
video 仅视频生成403 scope_not_allowed403 scope_not_allowed是

文生图、图生图接口及 /v1/chat/completions、Gemini /v1beta 按图像请求形态判定用途;视频仅通过 /v1/videos 接口提交。绑定 minimax-h3 时,用途须为「不限用途」或 video;创建后不可修改,需要换用途就再建一把。

密钥不能用于管理后台。/api/admin/* 只接受管理员的浏览器会话,API Key 无法访问,也无法查看或修改其他用户的数据。

鉴权失败

HTTP/1.1 401 Unauthorized

{ "error": { "code": "invalid_api_key", "message": "无效的 API Key" } }

密钥格式对但已被删除时返回的是 api_key_revoked,用来和「打错字 / 用了别站的密钥」区分开。两种都不要重试。

额度与计费

账户余额和所有价格对外统一以「分」为单位(响应里的 balanceUnit: "fen")。1 元 = 100 分。允许出现 0.5 这样的半分,因为内部按半分存储以避免四舍五入误差。

扣费流程

图像请求按上方规则预扣并结算:同步请求按 n,异步任务按最多输出张数;视频任务按总费用预扣。完整对照表见开头的扣费表。

步骤公式举例(文生图 1 分/张,最多 3 张,实际出 1 张)
预扣同步图像:单价 × n;异步图像:单价 × max_output_images最多先扣 3 分
结算单价 × 实际张数,多扣的退回退 2 分,实花 1 分

响应里的 cost 是实际花费,balance 是结算后的余额。不要看预扣瞬间的余额。

失败一定会全额退款。不管是提示词被拒、没有可用节点、生成服务超时还是服务端崩溃重启,预扣的额度都会退回。服务启动时会扫描所有未结算的预扣并退还,所以进程被杀掉也不会吞钱。

哪些接口花钱

接口计费
POST /v1/images/generations按文生图单价 × 实际出图张数
POST /v1/images/edits按图生图单价 × 实际出图张数(通常比文生图贵)
POST /v1/images/generations-async / edits-async与对应同步接口相同;提交时检查余额,任务开始执行时预扣
POST /v1/videos/generations视频费率 × 秒数 + 参考图费率 × 图片数;提交时预扣,失败全额退款
其余所有接口免费,只受速率限制

实时单价通过 GET /v1/pricing 或 GET /v1/balance 获取,不要在代码里写死——管理员随时可以调价,站点搞活动时价格还会临时下调。

通用约定

请求

  • 除图生图的 multipart 形式外,请求体一律为 JSON,需要带 Content-Type: application/json。
  • 普通接口请求体上限 128 KB;/v1/images/edits、/v1/images/edits-async 和所有 /v1beta/models/*(Gemini 协议,参考图以 base64 内联)放宽到 30 MB。
  • 未知字段会被忽略,不会报错。

成功响应

查询类和同步出图带 ok: true,HTTP 状态码 200。异步提交返回 202,任务成败看响应里的 status。

错误响应

/v1 下的错误结构统一,error 恒为对象,永远有 code 和 message 两个字段:

{
  "error": {
    "code": "insufficient_credits",
    "message": "余额不足:最多需要 3 分,当前 1 分",
    "hint": "(可选)仅部分错误会带,给出可操作的修复建议"
  },
  "balance": 1
}

两个生成接口在出错时会额外返回 balance,方便你直接判断是不是余额问题,不用再多发一次查询。

请按 code 判断错误类型,不要匹配 message。message 是给人看的中文提示,措辞会随版本变化;code 才是稳定契约。

以上是 /v1 的错误信封。/v1beta(Gemini 协议)遵循 Google 官方结构 { "error": { "code": 400, "message": "...", "status": "INVALID_ARGUMENT" } }:code 是 HTTP 数字、status 是枚举字符串,没有 type / param。详见 Gemini 兼容接口。

时间与金额字段

字段形态含义
created_at / last_used_at 等Unix 毫秒时间戳(整数)。JavaScript 里 new Date(v) 直接可用。
cost / balance / delta以「分」为单位,可能带一位小数。
cost_units / delta_units内部半分单位的整数值,一般不用关心。

图片 URL 的有效期

返回的是站内代理地址 /img/...,不是生成服务的原始直链。请尽快下载转存到自己的存储;长期引用本站 URL 可能因缓存过期而失效。

速率限制

限流按 API Key 计算(没带密钥时退化为按 IP)。触发后返回 429:

{ "error": { "code": "rate_limited", "message": "API 调用过于频繁,请降低速率" } }
范围默认额度环境变量
全部 /v1 与 /v1beta 接口9999 次 / 分钟RL_API
POST /v1/redeem(叠加)30 次 / 10 分钟RL_REDEEM

响应头带标准的 RateLimit-* 字段(draft-7),可以据此做退避。这些额度由部署方在环境变量里配置,自建实例可以自行调高。

被限流挡掉的请求也会记进调用历史,所以到底是哪个时段、哪把密钥撞上了限流,翻 GET /v1/usage 就能看出来,不用自己在客户端埋点。

并发上限

限流之外还有同时进行的生成任务上限,这是另一套机制:

  • 单用户默认 9999 路并发生成。实时值见 GET /v1/pricing 的 limits.max_concurrent_per_user;视频配置也会返回此值。
  • 全站默认 9999 路并发生成。同步接口只有撞上这个天花板才返回 503 busy;异步会留在队列里等空位。
  • 异步排队 + 进行中默认最多 9999 个,见 limits.max_open_async_tasks。只有碰到这个数字才会 429 too_many_tasks。

图像批量任务和视频任务走异步接口轮询。网页端每次提交一个视频任务,需要多个视频时可继续新建任务;API 可并发提交。超过并发上限的任务自动排队。

文生图

POST /v1/images/generations 需要密钥 消耗额度

根据文字提示词生成图片。同步接口,等到出图才返回,通常耗时 1-5 分钟。

请求参数(JSON)

参数类型说明
prompt 必填 string 图片描述。描述越具体结果越稳定,建议写清主体、场景、光线、镜头和风格。服务端会自动加上「生成图片:」前缀以确保走生图模式,你不需要自己加。最长 12000 字,超了返回 prompt_too_long。
ratio 可选 string 画面比例,可传 1:1、16:9、9:16、4:3、3:4 或任意合法的 宽:高。服务端会把比例作为生成意图传给生成服务,并在响应的 requested_ratio / normalized_ratio 中分别返回请求值和实际三档画幅。
size / output_size / dimensions 可选 string 兼容 CPA、NewAPI、Sub2 常见字段,例如 1008x1344。服务端接受 64–16384 的宽高且总像素不超过 64MP;生成服务原生仍只有 1024x1024、1536x1024、1024x1536,不会把任意尺寸伪装成原生输出。响应会带 requested_size、normalized_size。
resolution 可选 string 输出分辨率,默认 2k,非法值静默回落到 2k。
  • 2k —— 原图,2K-2.5K,无损 PNG。长边随比例在 1920~2560 之间浮动(见下表),总像素固定在约 370 万。
  • 1k —— 预览图,长边压到 1024 的有损 webp,体积约为原图的 1/40,适合列表缩略和快速预览。
原有的 4k 已下线:生成服务原生出图就到 2K-2.5K,那一档只是让 CDN 把同一张原图重新编码后发一遍,尺寸一个像素都没变、还多了一道有损压缩,画质反而比 2k 差。继续传 4k 不会报错,会回落到 2k,也就是拿到更好的那一张。
model 可选 string 生图模型,可选 gpt-image-2.5、gpt-image-2.5-high、nano-banana-2 或 nano-banana-pro。旧值 gpt-image / gpt-image-2.0 / image2.0 会自动兼容到 gpt-image-2.5;旧值 nano-banana 会当作 nano-banana-pro。留空使用站点默认模型;填了不支持的值会直接报错而不是回落,避免你以为用上了实际没用上。密钥绑定了模型时留空即用绑定的那个,填别的会返回 403 model_not_allowed。注意 gpt-image-2.5-high 走画布链路,固定出 1K,resolution 参数对它无效。

关于比例和自定义尺寸:生成协议没有独立的比例字段,服务端会把请求比例追加到提示词末尾,因此比例是倾向性引导而非硬裁切。当传入 size=1008x1344 这类自定义尺寸时,服务端保留请求意图,同时选择最接近的真实画幅;不会返回不存在的 1008x1344 原生输出。

各比例的实际出图尺寸

下面是实测数据(resolution=2k)。注意总像素是固定的,约 370 万——模型按固定像素预算出图,再按比例摊开,所以选宽幅并不会让你多拿到画面,只是把同样多的像素铺成更宽的形状。

ratio原图尺寸长边总像素1k 档对应尺寸
1:11920 × 19201920369 万1024 × 1024
4:32176 × 16322176355 万1024 × 768
16:92560 × 14402560369 万1024 × 576
3:4 / 9:16对应横版的转置1632 / 1440同上768 × 1024 / 576 × 1024

上面是 GPT Image 2.5 的 low 档实测。Nano Banana 2 / Pro 默认原生 2048 × 2048 PNG。提示词里明确写 4K / 4096 时,交付文件可以到 4096×4096,但模型侧仍按 2048 出图,多半是沙箱放大,不是模型原生 4K。换算成印刷尺寸,按 300 DPI 计算长边约 16~21 厘米,做屏幕内容、社媒图和网页配图绰绰有余;要出大幅面海报则需要自行做超分。

响应字段

字段类型说明
okboolean恒为 true
imagesstring[]图片直链数组,顺序即生成顺序。至少一张,否则本次会按失败处理并退款。
resolutionstring实际使用的分辨率
modelstring实际使用的模型 id
costnumber本次实际扣费(分),已按出图张数结算完毕
image_countnumber出图张数,等于 images.length
balancenumber结算后的账户余额(分)
session_idstring本次生成的会话标识,排查问题时可提供给管理员

示例

curl -X POST https://your-domain.example/v1/images/generations \
  -H "Authorization: Bearer mk-你的密钥" \
  -H "Content-Type: application/json" \
  --max-time 330 \
  -d '{
    "prompt": "极简主义产品摄影:一只哑光黑陶瓷咖啡杯放在浅灰水泥台面上,柔和顶光,阴影干净,高级商业质感",
    "ratio": "1:1",
    "resolution": "2k",
    "model": "gpt-image-2.5"
  }'

可能的错误

状态码code含义与处理
400missing_promptprompt 为空或只有空白字符
400prompt_too_longprompt 超过 12000 字,不扣费
400unsupported_modelmodel 不在支持列表里,先查 /v1/models
400prompt_rejected提示词未通过内容审核,不扣费。响应带 hint 说明如何修改
401invalid_api_key密钥不存在
401api_key_revoked密钥已被删除,重新创建一把
402insufficient_credits余额不足以覆盖预扣金额,先充值
403model_not_allowed这把密钥绑定的是别的模型,不扣费。响应带 hint 指出该换哪把密钥
403scope_not_allowed这把密钥限定了用途(文生图 / 图生图 / 视频),调了不匹配的接口,不扣费。响应带 hint
429rate_limited超出速率限制,退避后重试
429too_many_requests你的并发生成数已达上限,等前面的任务完成
503no_channel暂无空闲生成节点,已全额退款,稍后重试
503busy全站并发已满,已全额退款,稍后重试
500generation_failed生成服务失败或超时,已全额退款

内容审核

提示词在扣费和调用生成服务之前会先过一遍本地检查,命中直接拒绝,不产生任何费用。规则刻意收得很窄,需要两个独立信号同时出现才会命中,正常创作类提示词不会被误伤。拦截的是:涉及未成年人的性化内容、真实人物的裸露内容、露骨色情、武器爆炸物制作方法、毒品制作方法,以及站点管理员自定义的禁用词。

{
  "error": {
    "code": "prompt_rejected",
    "message": "提示词未通过内容审核(露骨色情内容)",
    "hint": "提示词可能触发了内容审核。建议去掉真人姓名、品牌标识、暴力或成人相关描述后重试。"
  },
  "balance": 1000
}

本地检查放行不代表一定能出图,生成服务还有自己的审核。服务拒绝时同样返回 prompt_rejected,同样不扣费。

图生图

POST /v1/images/edits 需要密钥 消耗额度

带参考图生成新图片。同步接口,耗时与文生图相当。支持 multipart 文件上传和 JSON 两种传图方式。

方式一:multipart/form-data(推荐)

直接上传本地文件,不用做 base64 编码,请求体也小得多。

字段类型说明
image 必填file参考图文件。字段名也可以用 images 或 image[],效果相同。
prompt 必填string希望如何改动或参考这张图
ratio / resolution / model 可选string与文生图完全一致
curl -X POST https://your-domain.example/v1/images/edits \
  -H "Authorization: Bearer mk-你的密钥" \
  --max-time 330 \
  -F "image=@./reference.png" \
  -F "prompt=保持人物姿势不变,把背景换成黄昏海滩,增加暖色边缘光" \
  -F "resolution=2k"

方式二:JSON

适合图片来自远程 URL 或已经是 base64 的场景。以下字段任选一个:

字段类型说明
imagestringdata URL,形如 data:image/png;base64,iVBORw0...
image_urlstring公网可访问的图片 URL,服务端会代为下载
imagesstring[]多张 data URL(受参考图数量上限约束)
image_urlsstring[]多张图片 URL(同上)
filename / filenames 可选string / string[]指定上传文件名,不填会自动生成
mime 可选string指定 MIME 类型,一般不需要,服务端会从图片内容嗅探
curl -X POST https://your-domain.example/v1/images/edits \
  -H "Authorization: Bearer mk-你的密钥" \
  -H "Content-Type: application/json" \
  --max-time 330 \
  -d '{
    "image_url": "https://example.com/reference.jpg",
    "prompt": "转换成水彩插画风格,保留构图",
    "ratio": "4:3"
  }'

参考图上限以 max_reference_images 的实时值为准。1 张走原生上传;多张会自动切换为链接文本模式——服务端把每张图转成站内链接写进提示词(如「图一链接:…」「图二链接:…」),由生成服务据此读取,不占用单号上传配额。超过上限才返回 too_many_reference_images。

图片要求

  • 支持 PNG、JPEG、WebP、GIF、BMP。服务端按文件头嗅探真实类型,改扩展名骗不过去。
  • 单张不超过 20 MB;JSON 方式整个请求体不超过 30 MB;多张参考图总大小不超过 30 MiB(超了返回 reference_images_too_large)。
  • 用 image_url 时目标必须是公网地址。指向 127.0.0.1、内网段、云元数据地址(169.254.169.254)等一律被拒绝,这是防 SSRF 的硬性限制,DNS 解析后的真实 IP 也会检查。

响应字段

比文生图多四个字段,其余相同:

字段类型说明
modestring恒为 "image_to_image"
reference_countnumber本次实际使用的参考图数量
reference_link_modeboolean是否走了链接文本模式(多张参考图改写提示词时为 true)
finalTextstring模型返回的文字说明,可能为空字符串
{
  "ok": true,
  "mode": "image_to_image",
  "images": ["https://.../edited.png"],
  "finalText": "已将背景替换为黄昏海滩。",
  "resolution": "2k",
  "model": "gpt-image-2.5",
  "reference_count": 2,
  "reference_link_mode": true,
  "cost": 1.5,
  "image_count": 1,
  "balance": 996.5,
  "session_id": "b7c1e9f4"
}

额外的错误

除文生图那张表里的全部错误外,还可能出现:

状态码code含义
400missing_image没有提供任何参考图
400too_many_reference_images参考图数量超过 max_reference_images
400invalid_image不是可识别的图片格式、下载失败,或 URL 指向内网地址
400LIMIT_FILE_SIZE单张参考图超过 20 MB
413payload_too_largeJSON 请求体超过 30 MB
413reference_images_too_large多张参考图总大小超过 30 MiB

异步出图

POST /v1/images/generations-async 需要密钥 消耗额度

参数与同步文生图完全相同,但请求立刻返回任务 id,不等出图。适合 HTTP 超时较短、或要一次提交多张的对接方。

没有 webhook。提交后请轮询 GET /v1/images/tasks/:id,建议间隔 2-3 秒,直到 status 变成 succeeded 或 failed。图生图对应 POST /v1/images/edits-async,multipart / JSON 字段与同步图生图相同。

curl -X POST https://your-domain.example/v1/images/generations-async \
  -H "Authorization: Bearer mk-你的密钥" \
  -H "Content-Type: application/json" \
  -d '{"prompt": "一只在草地上奔跑的柴犬", "resolution": "2k"}'

HTTP 202:

{
  "ok": true,
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "queued",
  "kind": "text",
  "model": "gpt-image-2.5",
  "ratio": "",
  "resolution": "2k",
  "created_at": 1730000000000,
  "started_at": null,
  "finished_at": null
}
字段说明
id任务 id,后续查询用它
statusqueued 排队 / running 出图中 / succeeded 成功 / failed 失败
kindtext 文生图,edit 图生图

提交时只做参数校验、内容审核和余额软检查,不预扣。真正占并发槽和预扣发生在任务开始跑的时候,规则与同步接口相同。失败全额退款。

每个账号同时处于 queued + running 的任务默认最多 9999 个。并发生成默认 9999 路;槽满或暂时没有空闲节点时,任务留在队列,不会因此标失败。

状态码code含义
400missing_prompt 等与同步接口相同的参数/审核错误,不会创建任务
402insufficient_credits提交时余额已不够覆盖预扣
429too_many_tasks该账号未完成的异步任务已达上限

查询异步任务

GET /v1/images/tasks/:id 需要密钥

用提交时拿到的 id 查询状态。只能查自己账号的任务,别人的 id 与不存在一样返回 404 not_found。查询本身不扣费。

curl https://your-domain.example/v1/images/tasks/task_xxxxxxxxxxxxxxxxxxxxxxxx \
  -H "Authorization: Bearer mk-你的密钥"

成功时除任务字段外,还带与同步接口同形的 images(站内 /img/...)、cost、balance、session_id:

{
  "ok": true,
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "succeeded",
  "kind": "text",
  "model": "gpt-image-2.5",
  "ratio": "",
  "resolution": "2k",
  "created_at": 1730000000000,
  "started_at": 1730000000500,
  "finished_at": 1730000120000,
  "images": ["/img/xxxxxxxx"],
  "cost": 1,
  "image_count": 1,
  "balance": 997,
  "session_id": "g_a1b2c3d4e5f6g7h8"
}

失败时 HTTP 仍是 200,看 status: "failed" 和 error:

{
  "ok": true,
  "id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
  "status": "failed",
  "kind": "text",
  "error": {
    "code": "no_channel",
    "message": "服务暂时不可用(暂无空闲生成节点),已退还余额"
  }
}

进程重启后:进行中的任务会标为 interrupted;排队中的文生图会接着跑;图生图参考图只存在内存里,重启后排队中的图生图会变成 task_expired,需要重新提交。

MiniMax H3 视频生成

POST/v1/videos/generations需要视频用途密钥

异步创建 MiniMax H3 视频任务,返回 202 和任务编号。网页端和 API 共用任务队列、账户余额与并发限制。

字段:model 可省略(默认 minimax-h3);prompt 必填;duration_seconds 为 5–15 秒整数;resolution 为 768p 或 1080p(默认 768p);aspect_ratio 为 16:9 或 9:16(默认 16:9)。最多 9 张 PNG、JPG、WebP 或 GIF 参考图,单张不超过 20 MiB、合计不超过 30 MiB。

JSON:参考图用 URL 或 data URL

curl -X POST https://your-domain.example/v1/videos/generations \
  -H "Authorization: Bearer mk-视频密钥" \
  -H "Content-Type: application/json" \
  -d '{"model":"minimax-h3","prompt":"黄昏海边,一辆复古摩托车驶过,电影镜头","duration_seconds":8,"resolution":"768p","aspect_ratio":"16:9","reference_images":["https://example.com/reference.jpg"]}'

multipart/form-data:上传参考图文件

curl -X POST https://your-domain.example/v1/videos/generations \
  -H "Authorization: Bearer mk-视频密钥" \
  -F 'prompt=黄昏海边,电影镜头' -F 'duration_seconds=8' \
  -F 'resolution=768p' -F 'aspect_ratio=16:9' -F 'reference_images=@reference.jpg'

提交响应中的 cost / reserved_cost 单位为本站分。成功任务的 cost 是最终本站费用;失败任务的 cost 为 0,reserved_cost 已退回。结果中的 video_url 是本站播放地址。

{"ok":true,"id":"task_xxx","status":"queued","model":"minimax-h3","prompt":"黄昏海边","duration_seconds":8,"resolution":"768p","aspect_ratio":"16:9","reference_count":1,"cost":8,"reserved_cost":8,"progress":0,"stage":"queued","progress_message":"等待生成","created_at":1760000000000}

费率与并发

GET /v1/videos/config 返回当前视频费率、参数与并发上限;GET /v1/pricing 的 video_h3 也包含该配置。本站计价公式是「分辨率每秒单价 × 秒数 + 参考图单价 × 图片数」。pricing.reference_enabled 表示是否开启参考图加价;关闭时 reference_fen 为 0,参考图不额外收费。每秒和每张单价支持自定义小数,任务总费用四舍五入到 0.5 分,以响应中的 cost 为准。分辨率费率为 0 时暂停该分辨率的任务提交。

curl https://your-domain.example/v1/videos/config -H "Authorization: Bearer mk-视频密钥"

查询视频任务

GET/v1/videos/tasks需要视频用途密钥

列出当前账户最近任务,并返回生成中、排队数量和余额。

curl https://your-domain.example/v1/videos/tasks -H "Authorization: Bearer mk-视频密钥"

轮询单个任务:GET /v1/videos/tasks/:id。状态为 queued、running、succeeded 或 failed。成功响应包含 video_url、generation_id、费用与余额;失败响应含 error 并自动全额退款。服务重启后排队任务继续执行,重启时中断的运行任务退款并标记失败。

视频任务会出现在工作台左侧任务列表中,完成后可在「生成历史」播放、下载并查看费用。API Key 选择 minimax-h3 或不限模型,用途设为「仅视频生成」或「不限用途」。

图片超分

POST /v1/images/upscale 需要密钥

把一张已有图片交给图片超分服务放大到指定分辨率,不改构图、不重新生成,等价于网页端「无限画布」里对图片点「超分」。

一次只处理 1 张图,按分辨率单价 × 1 张计费(当前 2K 1 分 / 4K 2 分 / 8K 4 分,以 GET /v1/pricing 的 canvas_upscale 为准)。

字段类型说明
image 必填string图片来源:https 直链、data:image/...;base64,...,或本站 /img/<id> / /reference-images/... 地址
image_url / images 可选string与 image 等价;一次仍只能传 1 张,多传报 too_many_images
resolution 可选string2k · 4k(默认) · 8k,其它值按 4k 处理

也支持 OpenAI 风格 multipart:image=<file> + resolution。

curl -X POST "{BASE}/v1/images/upscale" \
  -H "Authorization: Bearer mk-xxx" \
  -H "Content-Type: application/json" \
  -d '{"image":"https://example.com/in.png","resolution":"4k"}'
{
  "ok": true,
  "mode": "canvas_upscale",
  "resolution": "4k",
  "images": ["https://.../img/xxxxxxxx"],
  "cost": 2,
  "image_count": 1,
  "balance": 998
}

返回的 images 是本站 /img/<id> 镜像地址,仍受保存期约束(测试样本会换主机校验,请及时下载到本地)。

Gemini 兼容接口

面向 Gemini 官方 SDK、Vertex AI SDK,以及 Cherry Studio、NewAPI 等支持 Gemini 协议的客户端。把 Base URL 指向本站根地址、填上你的 API Key,就能按 Google 官方 GenerateContent / Predict 协议出图。请求、响应、错误都是标准 Gemini 形状,没有私有扩展。

与 OpenAI 接口的关系:两种协议是同一套后端的两张皮——同一把 Key、同一份余额、同一套模型与计费。用哪套只取决于客户端支持哪套,随时可以混着用。

端点一览

方法路径说明
POST/v1beta/models/{model}:generateContent文生图 / 图生图,同步返回
POST/v1beta/models/{model}:streamGenerateContent?alt=sse同上,按 SSE 分片返回
POST/v1beta/models/{model}:predictImagen 风格,结果在 predictions[]
POST/v1beta/models/{model}:countTokens本地估算 token 数,不扣费
GET/v1beta/models可用模型列表
GET/v1beta/models/{model}单个模型信息

鉴权

下面三种写法任选其一,都指向同一把 mk- 密钥:

x-goog-api-key: mk-xxxxxxxxxxxxxxxx
?key=mk-xxxxxxxxxxxxxxxx
Authorization: Bearer mk-xxxxxxxxxxxxxxxx

缺少或无效的密钥返回 401 UNAUTHENTICATED。

模型名映射

URL 里的 {model} 既可以直接写本站模型 id,也可以写 Gemini / Imagen 的官方模型名,服务端会自动映射:

客户端传的模型名实际使用
gpt-image-2.5 / gpt-image-2.5-high / nano-banana-2 / nano-banana-pro对应本站模型,原样使用
gemini-2.5-flash-image、gemini-3-pro-image-preview、imagen-4.0-generate-001 等nano-banana-pro
名字里含 nano-banana-2nano-banana-2
其它无法识别的名字回落到 nano-banana-pro(不报 404,方便客户端换预览版模型名)

与 OpenAI 侧一致:如果这把密钥绑定了某个模型,映射后与绑定不一致会返回 403 PERMISSION_DENIED;如果密钥限定了用途而本次请求形态不匹配,同样返回 403 PERMISSION_DENIED。

请求体

标准 Gemini contents[].parts[]:文本部分即提示词;inlineData(base64)或 fileData.fileUri(公网 https 链接)会作为参考图走图生图。也支持 Imagen 的 instances[].prompt。

参数位置取值
画面比例generationConfig.imageConfig.aspectRatio;也读 generationConfig.aspectRatio 和 Imagen 的 parameters.aspectRatio1:1、16:9、9:16、4:3、3:4 等
分辨率generationConfig.imageConfig.imageSize;也读 generationConfig.imageSize 和 Imagen 的 parameters.sampleImageSize1K:有损 webp 预览,约几十 KB;2K:无损 PNG 原图,默认,base64 可达数 MB。4K 及以上回落到 2K
出图张数generationConfig.candidateCount(:predict 读 parameters.sampleCount)1 ~ max_output_images

分辨率别漏传。不传 imageSize 时按 2K 原图出(与 OpenAI 侧默认一致),返回的 inlineData 是数 MB 的 PNG;只要缩略图请显式传 "imageSize": "1K",体积小很多、返回也更快。

{
  "contents": [
    { "role": "user", "parts": [ { "text": "一只在草地上奔跑的柴犬,逆光,浅景深" } ] }
  ],
  "generationConfig": {
    "candidateCount": 1,
    "imageConfig": { "aspectRatio": "16:9", "imageSize": "2K" }
  }
}

:generateContent 示例

curl -X POST "https://your-domain.example/v1beta/models/gemini-2.5-flash-image:generateContent" \
  -H "x-goog-api-key: mk-你的密钥" \
  -H "Content-Type: application/json" \
  --max-time 600 \
  -d '{"contents":[{"parts":[{"text":"一只在草地上奔跑的柴犬,逆光,浅景深"}]}],"generationConfig":{"candidateCount":1,"imageConfig":{"aspectRatio":"16:9","imageSize":"2K"}}}'

响应是标准 Gemini 结构,图片以 base64 内联在 inlineData 里,一张图一个 candidate:

{
  "candidates": [
    {
      "content": { "role": "model", "parts": [ { "inlineData": { "mimeType": "image/png", "data": "iVBORw0KGgo..." } } ] },
      "finishReason": "STOP",
      "index": 0,
      "safetyRatings": []
    }
  ],
  "modelVersion": "nano-banana-pro",
  "responseId": "resp_xxxxxxxx",
  "usageMetadata": { "promptTokenCount": 0, "candidatesTokenCount": 1, "totalTokenCount": 1 }
}

把 inlineData.data 做 base64 解码即得到图片字节,mimeType 给出真实类型:image/png 是 2K 原图、image/webp 是 1K 预览。本站不返回 fileData.fileUri,图片一律内联 base64。

:streamGenerateContent 与 :predict

流式:Gemini SDK 默认请求 :streamGenerateContent?alt=sse。服务端在生成完成后按 SSE 下发 data: {...} 分片,每张图一个 chunk,最后一个 chunk 带 "finishReason": "STOP"。不带 alt=sse 时返回 JSON 数组(与官方行为一致)。

curl -N -X POST "https://your-domain.example/v1beta/models/gemini-2.5-flash-image:streamGenerateContent?alt=sse" \
  -H "x-goog-api-key: mk-你的密钥" \
  -H "Content-Type: application/json" \
  --max-time 600 \
  -d '{"contents":[{"parts":[{"text":"赛博朋克城市夜景,写实"}]}]}'

Imagen 风格::predict 用 instances[].prompt 入参,结果在 predictions[].bytesBase64Encoded:

{
  "predictions": [
    { "bytesBase64Encoded": "iVBORw0KGgo...", "mimeType": "image/png" }
  ]
}

错误信封与常见错误

/v1beta 的错误遵循 Google 官方结构,与 /v1 不同:

{
  "error": {
    "code": 400,
    "message": "contents 中必须包含提示词(text part 或 instances[].prompt)",
    "status": "INVALID_ARGUMENT"
  }
}
HTTPstatus典型场景
400INVALID_ARGUMENT没有提示词、提示词未通过审核、参考图无法识别、请求体过大
401UNAUTHENTICATED缺少或无效的 API Key
402FAILED_PRECONDITION余额不足,无法预扣
403PERMISSION_DENIED密钥绑定了别的模型,或密钥用途与本次请求不匹配
404NOT_FOUND路径或动作不存在
429RESOURCE_EXHAUSTED超出速率限制或并发上限
500INTERNAL生成失败或服务端错误(预扣已全额退回)
503UNAVAILABLE暂无空闲生成节点(预扣已全额退回)

超时提示:同步出图通常 1-5 分钟,请把客户端(以及 generateContent 的 HTTP 超时)设到 320 秒以上。一次请求多张图用 candidateCount;批量出图仍建议走 OpenAI 异步接口,Gemini 协议没有异步版本。

早先 /v1beta 曾整体作为 OpenAI 协议的路径别名(等价于 /v1)。现在 /v1beta/models/* 已是 Gemini 原生入口;其它 /v1beta/* 路径(如 /v1beta/images/generations)仍按旧规则归一化到 /v1,只把 Base URL 设成 /v1beta 的老配置不受影响。

查询余额

GET /v1/balance 需要密钥

查询当前余额和实时价格。生成前先调这个可以避免因余额不足白等一次请求。

curl https://your-domain.example/v1/balance \
  -H "Authorization: Bearer mk-你的密钥"
{
  "ok": true,
  "credits": 998.5,
  "pricing": {
    "text": { "halfFen": 1, "fen": 0.5, "yuan": 0.005 },
    "edit": { "halfFen": 3, "fen": 1.5, "yuan": 0.015 },
    "upscale4k": null,
    "maxOutputImages": 3,
    "balanceUnit": "fen",
    "promo": false
  }
}
字段说明
credits当前余额(分)
pricing.text文生图单价。fen 是对外单位,yuan 是元,halfFen 是内部半分单位
pricing.edit图生图单价,结构同上
pricing.upscale4k已下线,恒为 null(旧版 2K→4K 修复的加价字段,保留兼容)。要放大请用图片超分
pricing.maxOutputImages单次最多出图张数,也是预扣的倍数
pricing.promo站点是否处于活动期。为 true 时价格和各项上限可能临时放宽

账户信息

GET /v1/me 需要密钥

查询密钥所属账户的基本信息。可用来验证密钥是否有效、属于哪个账户。

curl https://your-domain.example/v1/me \
  -H "Authorization: Bearer mk-你的密钥"
{
  "ok": true,
  "username": "alice@example.com",
  "email": "alice@example.com",
  "credits": 998.5,
  "credit_unit": "fen",
  "created_at": 1754870400000,
  "key": { "label": "生产环境-banana", "model": "nano-banana-2", "scope": null }
}

email 在纯用户名注册的账户上为 null。key 描述当前密钥:model 为 null 表示不限模型;scope 为 null 表示不限用途,也可能是 text、edit 或 video。

使用兑换码

POST /v1/redeem 需要密钥

用兑换码给当前账户充值。兑换码由管理员发放,一码只能用一次。

请求参数(JSON)

参数类型说明
code 必填string兑换码。大小写不敏感,首尾空格会自动去掉。
curl -X POST https://your-domain.example/v1/redeem \
  -H "Authorization: Bearer mk-你的密钥" \
  -H "Content-Type: application/json" \
  -d '{"code": "FL53HIJDSTQF"}'
{ "ok": true, "added": 100, "balance": 1098.5 }
状态码code含义
400missing_codecode 为空
400invalid_code兑换码不存在
400code_already_used该兑换码已被使用过
429rate_limited兑换过于频繁(防爆破,默认 10 分钟 30 次)

并发提交同一个兑换码只会有一次成功入账,其余返回 code_already_used,不会重复加钱。

模型列表

GET /v1/models 需要密钥

列出这把密钥能用的模型和默认模型。不限用途密钥会同时看到图像模型与 MiniMax H3;video 用途密钥只列视频模型。

{
  "ok": true,
  "models": [
    { "id": "gpt-image-2.5",   "label": "GPT Image 2.5" },
    { "id": "gpt-image-2.5-high", "label": "GPT Image 2.5 high" },
    { "id": "nano-banana-2", "label": "Nano Banana 2" },
    { "id": "nano-banana-pro", "label": "Nano Banana Pro", "type": "image" },
    { "id": "minimax-h3", "label": "MiniMax H3", "type": "video" }
  ],
  "default_model": "gpt-image-2.5",
  "key_model": null
}

生成接口的 model 参数只接受这里列出的 id。label 是给界面显示用的名字。

key_model 是当前密钥绑定的模型,不限模型时为 null。绑定过的密钥这里只会返回那一个模型,default_model 也跟着变成它:

{
  "ok": true,
  "models": [ { "id": "nano-banana-2", "label": "Nano Banana 2" } ],
  "default_model": "nano-banana-2",
  "key_model": "nano-banana-2"
}

价格与限制

GET /v1/pricing 需要密钥

一次性拿到所有价格和参数上限。写客户端时建议启动时调一次并缓存几分钟,而不是把这些值硬编码。

{
  "ok": true,
  "pricing": {
    "text": { "halfFen": 1, "fen": 0.5, "yuan": 0.005 },
    "edit": { "halfFen": 3, "fen": 1.5, "yuan": 0.015 },
    "upscale4k": null,
    "maxOutputImages": 3,
    "balanceUnit": "fen",
    "promo": false
  },
  "canvas_upscale": { "2k": 1, "4k": 2, "8k": 4 },
  "video_h3": {
    "model": "minimax-h3",
    "durations": [5,6,7,8,9,10,11,12,13,14,15],
    "resolutions": ["768p", "1080p"],
    "aspect_ratios": ["16:9", "9:16"],
    "pricing": { "rate_fen_per_second": { "768p": 0, "1080p": 0 }, "reference_enabled": false, "reference_fen": 0 },
    "concurrency_limit": 9999,
    "max_open_tasks": 9999
  },
  "limits": {
    "max_output_images": 3,
    "max_reference_images": 30,
    "max_concurrent_per_user": 9999,
    "max_open_async_tasks": 9999,
    "max_repair_per_token": 1,
    "max_inflight_per_token": 1,
    "resolutions": ["1k", "2k"],
    "ratios": ["1:1", "16:9", "9:16", "4:3", "3:4"],
    "upscale4k": false,
    "deliveries": []
  }
}
字段说明
limits.max_output_images单次最多出图张数,预扣金额 = 单价 × 该值
limits.max_reference_images图生图单次参考图上限,以账户实时配置为准
limits.max_concurrent_per_user你能同时跑几个生成任务,默认 9999
limits.max_open_async_tasks异步接口同时处于排队+进行中的任务上限,默认 9999
limits.resolutionsresolution 参数的合法取值
limits.ratiosratio 参数的合法取值,另外允许留空
canvas_upscale图片超分各分辨率单价(分/张):2k / 4k / 8k,对应 POST /v1/images/upscale
video_h3MiniMax H3 参数、本站费率、参考图费与并发上限
limits.max_inflight_per_token单个服务节点同时执行的任务上限
limits.max_repair_per_token与 max_inflight_per_token 相同,兼容旧字段,默认 1

健康检查

GET /healthz 免鉴权

服务存活探针。注意路径不在 /v1 下,也不需要密钥,适合给负载均衡或监控用。

{ "ok": true, "uptime": 86400.5, "inflight": 2 }
字段说明
uptime进程已运行秒数
inflight当前全站正在进行的生成任务数。接近全站上限(默认 9999)时新请求会收到 503 busy

生成记录

GET /v1/generations 需要密钥

按时间倒序返回本账户的历史生成记录,包含失败的任务。

查询参数

参数说明
limit 可选返回条数,默认 30,最大 100。非法或超范围的值会回落到默认/上限,不报错。
curl "https://your-domain.example/v1/generations?limit=5" \
  -H "Authorization: Bearer mk-你的密钥"
{
  "ok": true,
  "generations": [
    {
      "id": 42,
      "prompt": "一只在草地上奔跑的柴犬",
      "ratio": "16:9",
      "resolution": "2k",
      "model": "gpt-image-2.5",
      "cost": 1,
      "cost_units": 2,
      "status": "success",
      "duration_ms": 42318,
      "duration_sec": 42.3,
      "created_at": 1754870400000,
      "images": ["https://.../a1b2c3.png"]
    },
    {
      "id": 43,
      "prompt": "海边日落时的帆船",
      "ratio": "16:9",
      "resolution": "768p",
      "model": "minimax-h3",
      "cost": 15,
      "cost_units": 30,
      "status": "success",
      "duration_ms": 128000,
      "duration_sec": 128.0,
      "created_at": 1754870500000,
      "images": [],
      "video_url": "https://your-domain.example/media/video/43/SIGNATURE",
      "videos": ["https://your-domain.example/media/video/43/SIGNATURE"],
      "video_duration_seconds": 10
    }
  ],
  "speed": {
    "count": 40,
    "avg_duration_ms": 38200,
    "avg_duration_sec": 38.2,
    "by_resolution": {
      "1k": { "label": "1K", "count": 5, "avg_duration_ms": 12100, "avg_duration_sec": 12.1 },
      "2k": { "label": "2K", "count": 30, "avg_duration_ms": 28400, "avg_duration_sec": 28.4 },
      "hd4k": { "label": "4K", "count": 5, "avg_duration_ms": 61000, "avg_duration_sec": 61.0 }
    }
  }
}

status 为 "success" 或 "failed"。失败记录的 cost 恒为 0(已退款),images 为空数组。model 是这次实际使用的模型,这个字段上线之前的老记录为 null。duration_sec 是任务耗时(秒,一位小数)。视频记录使用 video_url 和 videos 返回站内播放地址,并通过 video_duration_seconds 标出片长;每条记录中的 cost 是本站实际消耗。speed 是本账户成功出图的平均时速:avg_duration_sec 为全部平均,by_resolution 按 1k / 2k / hd4k(4K)分类。

历史里的图片和视频地址都是站内播放/读取地址。请按接口返回的地址读取媒体文件;视频费用和状态可直接在同一条记录里核对。

调用历史

GET /v1/usage 需要密钥

返回 /v1 下的逐次调用记录,成功和失败都记。默认只看当前这把密钥,用来核对某一路服务、某一个模型到底调了多少、错在哪。

查询参数

参数说明
limit 可选返回条数,默认 50,最大 200
scope 可选默认 key,只返回当前密钥的记录;传 account 返回本账户所有密钥的记录
curl "https://your-domain.example/v1/usage?limit=20" \
  -H "Authorization: Bearer mk-你的密钥"
{
  "ok": true,
  "scope": "key",
  "summary": {
    "days": 7,
    "total": 128,
    "succeeded": 124,
    "failed": 4,
    "images": 131,
    "cost": 141.5,
    "cost_units": 283,
    "avg_duration_ms": 38120,
    "avg_duration_sec": 38.1,
    "by_resolution": {
      "1k": { "label": "1K", "count": 8, "avg_duration_ms": 12100, "avg_duration_sec": 12.1 },
      "2k": { "label": "2K", "count": 110, "avg_duration_ms": 28400, "avg_duration_sec": 28.4 },
      "hd4k": { "label": "4K", "count": 10, "avg_duration_ms": 61000, "avg_duration_sec": 61.0 }
    }
  },
  "calls": [
    {
      "id": 9012,
      "api_key_id": 7,
      "api_key": "mk-a1b2c3d********",
      "key_label": "生产环境-banana",
      "method": "POST",
      "path": "/v1/images/generations",
      "model": "nano-banana-2",
      "status": 200,
      "ok": true,
      "error_code": null,
      "cost": 1,
      "cost_units": 2,
      "image_count": 1,
      "duration_ms": 42318,
      "duration_sec": 42.3,
      "created_at": 1754870400000
    },
    {
      "method": "POST",
      "path": "/v1/images/generations",
      "model": "gpt-image-2.5",
      "status": 403,
      "ok": false,
      "error_code": "model_not_allowed",
      "cost": 0,
      "image_count": 0,
      "reference_count": 0,
      "duration_ms": 3,
      "duration_sec": 0,
      "created_at": 1754870300000
    }
  ]
}
字段说明
summary近 7 天的汇总:调用次数、成功/失败数、出图张数、总花费(分)。平均时速见 avg_duration_sec(全部)和 by_resolution(1K / 2K / 4K)
okHTTP 状态码是否 2xx,等价于 status >= 200 && status < 300
error_code失败时的 error.code,成功为 null
reference_count本次调用服务端实际收到的参考图张数(图生图 / 超分 / chat / Gemini 带图请求会有具体数字)。null 表示该接口不带参考图。用来核对「少了图二」是客户端没把图传上来,还是系统丢图
model本次用的模型;被 model_not_allowed 拒掉时记的是它想调用的那个,方便定位是哪段代码传错了。不涉及模型的接口为 null
cost这次调用的实际花费(分)。不计费的接口恒为 0
duration_sec服务端处理耗时(秒,一位小数),含等待生成完成的时间。兼容字段 duration_ms 是同一数值的毫秒
by_resolution成功出图按分辨率分类的平均时速。键为 1k / 2k / hd4k,值为 avg_duration_sec 和 count

被限流挡掉的 429 也会记进来,所以速率调优可以直接看这里。记录保留 30 天,更早的会被自动清理——需要长期留存请自行定期拉走。

用已删除的密钥发请求同样会记在它名下(401 api_key_revoked),方便定位「哪台机器上还有个旧脚本在跑」。完全不认识的密钥无从归属,不会记录。

额度流水

GET /v1/ledger 需要密钥

按时间倒序返回额度变动明细,包括注册赠送、充值、兑换、扣费和退款。

查询参数

参数说明
limit 可选返回条数,默认 50,最大 200
{
  "ok": true,
  "ledger": [
    { "delta": -1.5, "delta_units": -3, "reason": "文生图 预扣最多 3 张", "balance_after": 998.5, "created_at": 1754870400000 },
    { "delta": 1,    "delta_units": 2,  "reason": "按实际输出张数退回差额", "balance_after": 999.5, "created_at": 1754870460000 },
    { "delta": 100,  "delta_units": 200,"reason": "兑换码充值 FL53HIJDSTQF", "balance_after": 1099.5, "created_at": 1754870500000 }
  ]
}

delta 为正表示入账,为负表示扣费;balance_after 是该笔变动之后的余额。一次生成通常对应两条记录——一条预扣、一条退差额,这是计费流程的正常表现,不是重复记账。

无限画布

登录网页端后,工作台顶部的「无限画布」标签页。这是一块没有边界的平面,用来把多轮尝试铺开摆在一起看,而不是像生成历史那样挤成一列。画布本身是网页端功能,但画布上的图片超分已开放接口(见 图片超分);画布上出图和在「开始生成」页出图走的是同一套计费,单价一样。

基本操作

操作怎么做
平移在空白处按住拖动
缩放滚轮或触控板双指,以光标为锚点;也可以点工具栏的 − / +。范围 10%~400%
看全部点「回到中心」,会自动缩放到刚好装下画布上所有图并居中
全屏点「全屏」铺满整个窗口,Esc 退出
移动 / 缩放单张图拖图片本体移动;选中后拖右下角的小方块等比缩放。松手才写库,拖动过程不会一直发请求
删除悬停图片点「删除」,或选中后按 Delete / Backspace

就地生成

在画布任意空白处双击,原地弹出输入框,填提示词、选模型比例和分辨率,出的图就落在你双击的位置。生成过程中该位置显示进度占位,不阻塞你继续在别处双击排下一张——多个任务可以同时跑(默认并发 9999,见 /v1/pricing 的 limits.max_concurrent_per_user)。一次出多张时会沿横向依次排开,不会叠在一起。

Ctrl(Mac 上 Cmd)加 Enter 可以直接提交,Esc 关掉输入框。

基于已有图片再生成

悬停任意图片,右上角出现「再生成」,点开的输入框会带上这张图作为底图,模型和比例默认沿用原图。这走的是图生图那条路,等价于把原图当参考图重新出一张,但不需要你先下载再上传——服务端本地就存着这张图的字节,直接拿来用。

由此产生的新图会带一个「改自上一张」的角标,点角标会把视野移到它的来源图并高亮。多轮迭代因此会在画布上自然形成一条看得见的链路,这也是画布相对生成历史的主要价值:你能看出第 7 张是从第 3 张分叉出来的。

导入历史图片

点工具栏「导入历史图片」,弹窗里以缩略图列出你最近的生成记录,勾选想要的,或者用「全选」一次带走。已经在画布上的会置灰并标注「已在画布」,不会重复导入。确认后按网格铺在当前视口左上角附近。

图片会过期,记得下载

画布上的图和生成历史引用的是同一批文件,同样受保存期约束(当前 3 天,到期从服务器彻底删除)。到期后画布上对应的卡片会变成「图片已过期」的占位,这是不可恢复的。所以画布适合承载当次或近几天的创作过程,不要当成长期作品库。

悬停图片点「下载」即可存到本地,这是唯一能长期保住图的办法。

另外每个账号的画布最多放 500 张图,超出会提示先删一些。

错误码总表

按 error.code 处理,不要匹配 message。

状态码code含义建议处理
400missing_prompt缺少提示词修正请求
400prompt_too_long提示词超过 12000 字截断后重试
400missing_code缺少兑换码修正请求
400missing_image图生图未提供参考图修正请求
400unsupported_model模型不在支持列表查 /v1/models
400prompt_rejected提示词未通过审核不要重试,改提示词
400invalid_image图片无法识别、下载失败或指向内网换一张图或换公网 URL
400too_many_reference_images参考图超量减少张数
400too_many_images图片超分一次传了多张图只传 1 张
400invalid_code兑换码不存在核对兑换码
400code_already_used兑换码已使用换一个码
400invalid_json请求体不是合法 JSON检查序列化
400LIMIT_FILE_SIZE单张图片超过 20 MB压缩后重传
401invalid_api_key密钥不存在不要重试,检查密钥
401api_key_revoked密钥已被删除不要重试,重新创建一把
402insufficient_credits余额不足不要重试,先充值
402minimum_balance_required常规模式下文生图发起前余额低于门槛(limits.min_text_balance_fen)不要重试,先充值
403model_not_allowed密钥绑定了别的模型不要重试,换对应模型的密钥
403scope_not_allowed密钥用途不匹配(文生图 / 图生图 / 视频生成)不要重试,换用途匹配的密钥
413payload_too_large请求体超限改用 multipart 上传
413reference_images_too_large多张参考图总大小超过 30 MiB压缩或减少参考图
429rate_limited超出速率限制指数退避后重试
429too_many_requests你的并发生成数已满等待在跑的任务完成,或改用异步接口排队
429too_many_tasks未完成的异步任务已达上限等已提交的任务结束再提交
404not_found异步任务不存在或不属于当前账号核对任务 id 和密钥
500generation_failed生成失败,已退款可重试
500no_output本次未产出图片,已退款可重试
500generation_stall生成服务长时间无进度,已换号重试或退款可重试
500generation_timeout生成超时,已退款可重试
500node_transport_failed与生成节点连接失败,已换号重试或退款可重试
500internal_error服务端内部错误可重试,持续出现请联系管理员
503no_channel暂无空闲生成节点,已退款稍后重试
503busy全站并发已满,已退款稍后重试
503upscale_failed图片超分失败(暂无可用画布节点等)稍后重试

重试建议

  • 可以重试:generation_failed、no_channel、busy、internal_error、rate_limited、too_many_requests。建议指数退避,首次等 5 秒起步。
  • 不要重试:所有 400 类错误、invalid_api_key、api_key_revoked、model_not_allowed、insufficient_credits。重试只会白白消耗速率配额。

完整示例

依赖 requests(pip install requests)。包含超时设置、错误分类和自动重试。

import time
import requests

BASE = "https://your-domain.example"
API_KEY = "mk-你的密钥"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}

# 生成最长 5 分钟,超时必须给够,否则会掐断服务端还在正常处理的请求
TIMEOUT = (10, 330)  # (连接超时, 读取超时)

RETRYABLE = {"generation_failed", "no_channel", "busy", "internal_error", "rate_limited"}


class ApiError(Exception):
    def __init__(self, code, message):
        super().__init__(f"[{code}] {message}")
        self.code = code


def generate(prompt, ratio="", resolution="2k", model=None, max_retries=3):
    payload = {"prompt": prompt, "ratio": ratio, "resolution": resolution}
    if model:
        payload["model"] = model

    for attempt in range(max_retries):
        response = requests.post(
            f"{BASE}/v1/images/generations",
            headers={**HEADERS, "Content-Type": "application/json"},
            json=payload,
            timeout=TIMEOUT,
        )
        data = response.json()
        if response.ok:
            return data

        error = data.get("error", {})
        code = error.get("code", "unknown")
        if code not in RETRYABLE or attempt == max_retries - 1:
            raise ApiError(code, error.get("message", "未知错误"))
        time.sleep(5 * (2 ** attempt))  # 5s, 10s, 20s


def edit(image_path, prompt, **kwargs):
    with open(image_path, "rb") as handle:
        response = requests.post(
            f"{BASE}/v1/images/edits",
            headers=HEADERS,
            files={"image": handle},
            data={"prompt": prompt, **kwargs},
            timeout=TIMEOUT,
        )
    data = response.json()
    if not response.ok:
        error = data.get("error", {})
        raise ApiError(error.get("code", "unknown"), error.get("message", ""))
    return data


if __name__ == "__main__":
    balance = requests.get(f"{BASE}/v1/balance", headers=HEADERS, timeout=30).json()
    print(f"当前余额 {balance['credits']} 分,文生图单价 {balance['pricing']['text']['fen']} 分")

    result = generate("雪后的京都清水寺清晨,薄雾,暖色灯笼", ratio="16:9")
    print(f"花费 {result['cost']} 分,余额 {result['balance']} 分")
    for index, url in enumerate(result["images"]):
        image = requests.get(url, timeout=60)
        with open(f"output_{index}.png", "wb") as handle:
            handle.write(image.content)
        print(f"已保存 output_{index}.png")

Node.js 18+ 自带 fetch,无需额外依赖。注意必须显式放宽超时,否则默认设置会提前中断。

const fs = require("node:fs");

const BASE = "https://your-domain.example";
const API_KEY = "mk-你的密钥";

const RETRYABLE = new Set(["generation_failed", "no_channel", "busy", "internal_error", "rate_limited"]);
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

async function call(path, options = {}) {
  // 生成最长 5 分钟,给到 330 秒留出余量
  const response = await fetch(BASE + path, {
    ...options,
    headers: { Authorization: `Bearer ${API_KEY}`, ...options.headers },
    signal: AbortSignal.timeout(330000),
  });
  const data = await response.json();
  if (!response.ok) {
    const error = new Error(data.error?.message || "请求失败");
    error.code = data.error?.code || "unknown";
    throw error;
  }
  return data;
}

async function generate(prompt, options = {}, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      return await call("/v1/images/generations", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ prompt, ...options }),
      });
    } catch (error) {
      if (!RETRYABLE.has(error.code) || attempt === maxRetries - 1) throw error;
      await sleep(5000 * 2 ** attempt);
    }
  }
}

async function edit(imagePath, prompt, options = {}) {
  const form = new FormData();
  form.append("image", new Blob([fs.readFileSync(imagePath)]), imagePath.split(/[\\/]/).pop());
  form.append("prompt", prompt);
  for (const [key, value] of Object.entries(options)) form.append(key, value);
  return call("/v1/images/edits", { method: "POST", body: form });
}

(async () => {
  const { credits, pricing } = await call("/v1/balance");
  console.log(`当前余额 ${credits} 分,文生图单价 ${pricing.text.fen} 分`);

  const result = await generate("赛博朋克风格的东京街头,雨夜,霓虹倒影", { ratio: "16:9", resolution: "2k" });
  console.log(`花费 ${result.cost} 分,余额 ${result.balance} 分`);

  for (const [index, url] of result.images.entries()) {
    const image = await fetch(url);
    fs.writeFileSync(`output_${index}.png`, Buffer.from(await image.arrayBuffer()));
    console.log(`已保存 output_${index}.png`);
  }
})().catch(error => {
  console.error(`失败 [${error.code}]: ${error.message}`);
  process.exit(1);
});

需要 curl 和 jq。演示生成后直接下载所有图片。

#!/usr/bin/env bash
set -euo pipefail

BASE="https://your-domain.example"
API_KEY="mk-你的密钥"

# 先看余额
curl -sS "$BASE/v1/balance" -H "Authorization: Bearer $API_KEY" | jq

# 生成图片。--max-time 必须大于服务端 5 分钟的生成上限
response=$(curl -sS -X POST "$BASE/v1/images/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  --max-time 330 \
  -d '{"prompt": "北欧极简客厅,自然光,原木家具", "ratio": "4:3"}')

if [ "$(echo "$response" | jq -r '.ok // false')" != "true" ]; then
  echo "失败: $(echo "$response" | jq -r '.error.code'): $(echo "$response" | jq -r '.error.message')" >&2
  exit 1
fi

echo "花费 $(echo "$response" | jq -r '.cost') 分,余额 $(echo "$response" | jq -r '.balance') 分"

# 下载全部结果
echo "$response" | jq -r '.images[]' | while IFS= read -r url; do
  filename="output_$(date +%s)_$RANDOM.png"
  curl -sS -o "$filename" "$url"
  echo "已保存 $filename"
done

常见问题

价格、1K/2K、模型参数在哪看?

就在本页最上面的表格。图像价格与参数,以及视频费率、积分估算,可从 GET /v1/pricing 或 GET /v1/videos/config 获取。

有没有 SD2、SD2.5,或者视频?

图像模型包括 gpt-image-2.5、gpt-image-2.5-high、nano-banana-2 和 nano-banana-pro;视频模型是 minimax-h3,通过 /v1/videos 异步生成。旧值 gpt-image 会自动兼容到 gpt-image-2.5。

各模型的参数一样吗?价格一样吗?

生图参数一样:prompt / model / ratio / resolution,图生图再加参考图。计费只有文生图、图生图两档,不按模型加价。唯一例外是 gpt-image-2.5-high:它走无限画布的 GenerateImage 链路,画质固定 1K,resolution 传什么都没用;需要 2K 请用 gpt-image-2.5 或 Nano Banana 系列。

想要 4K / 8K 怎么办?

普通出图接口最高就是 2K 原图(传 resolution=4k 会回落到 2k)。要放大到 4K / 8K 请用 POST /v1/images/upscale:它把一张已有图片按原比例超分到指定分辨率、不改构图,按分辨率计费(2k / 4k / 8k,实时价格见 GET /v1/pricing 的 canvas_upscale)。

请求一直卡着不返回,是挂了吗?

大概率没挂。生成是同步的,正常就要 1-5 分钟。请确认客户端读取超时设到了 320 秒以上。如果你在 nginx 之类的反向代理后面,代理的 proxy_read_timeout 也要一起调大,否则会被代理提前掐断。单个节点卡住或一直没进度时,服务端会自动换号重试,不必自己连打。

能异步提交、轮询取结果吗?

可以。调 POST /v1/images/generations-async(文生图)或 POST /v1/images/edits-async(图生图),拿到 id 后按 2-3 秒间隔轮询 GET /v1/images/tasks/:id,直到 status 为 succeeded 或 failed。没有 webhook。同步接口仍然可用,超时请继续设到 320 秒以上。

用 OpenAI / NewAPI 的聊天接口怎么调?

现在支持图片模型的 POST /v1/chat/completions 兼容入口。把文字消息合并成提示词即可文生图;消息里的 image_url、image 部分会进入图生图。接口返回标准 choices,同时附带图片 data 数组。需要更完整的图片参数时,也可以直接调用 /v1/images/generations 或 /v1/images/edits。

用 Gemini SDK、Cherry Studio 的 Gemini 渠道怎么接?

Base URL 填本站地址(例如 https://your-domain.example),API Key 填你在这里创建的 mk- 密钥,模型名写 gemini-2.5-flash-image 之类的官方名即可,也可以直接写本站模型 id。协议走 /v1beta/models/...,完整说明见 Gemini 兼容接口。注意 /v1beta 现在是 Gemini 原生协议,不要再给 OpenAI 类客户端填这个地址——那类客户端请填根地址、/v1 或 /api/v1。

为什么请求刚发出去余额就掉了一大截?

那是图像预扣。同步图像按 n、异步图像按最多输出张数预扣,完成后按实际张数结算。视频任务按时长与参考图费预扣。以响应里的 cost 和 balance 为准。

失败了会退款吗?

会,而且是全额。所有失败路径都退款,包括进程被杀这种极端情况——服务下次启动时会扫描未结算的预扣并退还。

图片链接过一段时间就 403 / 404 了?

返回的是站内代理地址 /img/...,不是生成服务的原始直链。请尽快下载转存到你自己的对象存储;长期引用本站 URL 可能因缓存过期而失效。

ratio 或 size 设了但出图比例不太对?

生成协议没有独立的比例参数,服务端会把请求比例作为提示词意图传过去,并选择最接近的真实画幅,因此不是硬裁切。CPA、NewAPI、Sub2 常见的 size、output_size、dimensions 字段都支持,例如 1008x1344;响应会返回 requested_* 和 normalized_* 字段,分别说明请求值和归一化值。

图生图能一次传多张参考图吗?

能。上限以 GET /v1/pricing 返回的 max_reference_images 为准。传多张时服务端自动走链接文本模式,把每张图转成站内链接写进提示词;超过上限才返回 too_many_reference_images。

密钥能创建几个?弄丢了怎么办?

数量不限,建议按用途分开建,方便单独吊销。明文只在创建时显示一次,服务端只存摘要,丢了无法找回,删掉重建即可。

怎么把几个模型的用量分开统计?

给每个模型各建一把绑定该模型的密钥,然后用 GET /v1/usage 分别看各自的调用次数和花费。这么做还顺带上了一道保险:绑定 nano-banana-2 的密钥不可能因为哪里传错参数就跑去调 gpt-image-2.5。

已经在用的密钥能改绑定的模型吗?

不能,绑定只在创建时确定。这是有意的——中途改绑定会让历史记录变得没法解释:同一把密钥前后调的是两个模型,按密钥做的用量统计就对不上了。换模型请新建一把,旧的确认没人用了再删。

调用历史能留多久?能导出吗?

默认保留 30 天,之后自动清理。要长期留存就定期拉 GET /v1/usage?scope=account 存到自己那边;单次最多返回 200 条,按 created_at 自行去重即可。

API 能管理其他用户或改站点配置吗?

不能。API Key 只能操作它所属的那个账户。管理类接口 /api/admin/* 只认管理员的浏览器会话。

为什么 /v1/ledger 里一次生成有两条记录?

一条是预扣,一条是按实际张数退回差额,属于正常的两阶段记账。把两条加起来才是这次生成的净花费。