MJ Image API
使用 API Key 异步提交图片任务,再查询结果。图片结果返回 URL,不返回 Base64。提交成功只表示已受理,不表示图片已经可以下载。
文档核对日期:2026-11-14。请求契约以当前服务为准;上游模型、套餐和资源可用性仍可能变化。以下参数和功能“实测”主要指 2026-11-13 的生产接口验收,不是性能承诺或所有参数组合的穷举。
- 历史归属:已记录归属的任务按 Key 限制;历史未归属任务目前可能被其他有效 Key 读取。尚不能承诺严格的历史作品隔离,这是当前实现缺陷。
- 四周扩图:本轮
v8.2 + zoomFactor=2虽返回任务 ID,观察约 17 分 35 秒仍未取得结果。改画幅zoomFactor=100已完成,二者不能混为一谈。 - 区域重绘:
inpaint本轮已产出四张结果;遮罩区域保持、边界和保真效果尚未完整验收。
上游公开图片可能通过浏览器直接访问,但这不替代本服务下载接口的验收,也不能把服务 API Key 发送给第三方图片域名。此页只描述对外接入;未列入清单的路径、额外字段或任意动作类型不构成稳定公开承诺。
快速开始
1. 准备 API Key 和运行环境
联系服务提供方取得以 mj_live_ 开头的 API Key。保存在调用程序的环境变量中,不写入网页前端、URL 或公开仓库。本页示例 Key 全是占位值,执行前必须替换。
# Bash:后续 curl 示例使用 Bash 的换行和引号语法
export MJ_API_KEY='mj_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# 安装 Python 示例所需依赖
python -m pip install requests
# PowerShell:设置环境变量;不要直接复制 Bash 的反斜杠换行
$env:MJ_API_KEY = 'mj_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
# 使用 curl 时可显式调用 curl.exe,避免旧版 PowerShell 的同名命令别名
2. 检查连接和读取权限
curl --fail-with-body {BASE}/health \
-H "Authorization: Bearer $MJ_API_KEY"
{"service":"mj-lite-service","version":"0.2","ok":true,"accounts":1,"docs":"/docs"}
ok=true 说明这次服务请求和认证成功,不保证生成容量、上游登录状态、套餐能力或图片下载都正常。仅有 submit 权限的 Key 不能通过需要 read 的健康检查。
3. 提交任务
curl --fail-with-body -X POST {BASE}/api/submit \
-H "Authorization: Bearer $MJ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"mode":"relaxed","action":{"t":"imagine","prompt":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2"}}'
收到 job_id 和 job.media_url 后,任务进入异步处理;提交接口不会等待图片完成。此请求会创建真实任务并使用上游资源,不要把网络超时后的重发当作安全重试。没有固定完成时间,设置合理的等待窗。
4. 查询图片结果
# 用真实响应中的 job.media_url 替换下方路径;建议每 10–20 秒查询一次
curl --fail-with-body {BASE}/api/media/ee4c507f-521a-4ce0-888c-16aa71df6f63 \
-H "Authorization: Bearer $MJ_API_KEY"
当 archive_status=ready,整组图片的 URL 均已可用;处理中也可先下载 images 中 status=ready 的图片。详见结果字段与状态。不必先等 /api/gallery 列表出现,再来查询结果。
5. 使用返回的 URL 下载
# 替换为本次响应中的 images[0].download_url;这次请求不要附加 API Key
curl --fail-with-body 'https://images.example.com/result-0.png?token=replace-with-current-response' -o result-0.png
download_url 返回图片文件;thumb_url 和 preview_url 用于预览。URL 有有效期,到期后重新查询,使用新的完整 URL。
公开能力清单
“已产出”表示记录和结果图片均观察到;“可传”仅表示接口能表达该请求;“未测”不等于不支持。
| 方法 | 路径 | 用途 / 权限 | 本轮状态 |
|---|---|---|---|
| POST | /api/submit | 生成与二次操作 / submit | 多种动作已产出;扩图组合仍异常;视频本轮未测 |
| POST | /api/upload | Base64 图片上传 / submit | PNG 上传成功,返回 short_url |
| POST | /api/mask | PNG 遮罩上传 / submit | 成功返回 mask_url,随后 inpaint 已产出 |
| GET | /api/media/{jobId} | 图片结果状态、元数据与下载 URL / read | 与生成记录分开;只有 ready 的结果附下载地址 |
| POST | /api/media/{jobId}/archive | 历史结果准备或失败重试 / submit | 只允许自己的任务;不重新生成 |
| GET | /api/jobs | 最近任务原始记录 / read | 查询通过;没有单任务终态查询语义 |
| GET | /api/gallery | 最近作品卡片 / read | 查询通过;历史隔离有前述例外 |
| GET | /api/thumb/{jobId}/{index} | 原始图片 / 缩略图 / 视频封面 / read | 图片就绪返回 302 下载 URL;未就绪返回 202,视频范围另述 |
| GET | /api/image/{jobId}/{index} | 图片下载 / read | 结果 ready 后 302 到原始 PNG 的 URL;推荐直接使用 media 接口返回的 download_url |
| GET | /api/credits | 共享 GPU 额度快照 / read | 查询通过,不是 Key 剩余请求次数 |
| GET | /api/queue | 共享队列计数 / read | 查询通过,不是某个任务的状态 |
| GET | /health | 连通性与认证 / read | 通过,不代表全链路健康 |
认证与权限
Authorization: Bearer mj_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
认证方案名不区分大小写,示例统一使用 Bearer;它与 Key 之间保留一个空格。Key 本身区分大小写。请求头名称遵循 HTTP 的不区分大小写规则。
| 权限 | 允许的公开操作 | 注意 |
|---|---|---|
read | 健康、列表、额度、队列、取图 | 不包含生成任务 |
submit | 提交任务、图片上传、遮罩上传 | 不自动附带 read;若需查询结果,申请同时具备两项权限的 Key |
已记录归属的任务应只允许对应 Key 读取;历史未归属任务目前存在放行例外。不要把本页当作历史数据已严格隔离的证明。提交响应当前也可能带额外账号身份字段:不应依赖或继续传播这些字段,响应脱敏尚未统一。
配额、并发和数据大小
| 限制 | 当前行为 |
|---|---|
| Key 每日次数 | 按已认证的 HTTP 请求计数,不是只按生成次数。列表轮询、健康检查、取图和部分被拒绝的已认证请求也会计入。限额由服务方配置,0 表示不限。 |
| 每日重置 | UTC 00:00 切换日期;北京时间为 08:00。不是每次首次调用后滚动 24 小时。 |
| 图片速率 | 图片接口还有独立的短时间速率限制,可能返回 429 与 JSON retry_after 秒数。它与每日次数不是同一种限制,实际值由服务配置决定。 |
| 并发 | 由所用上游账号、套餐和当前队列决定,不承诺固定并发数。收到任务 ID 后仍可能排队。不要用并发轮询代替并发生成。 |
| GPU 额度 | fast 会使用快速资源;relaxed 受套餐、队列和上游规则约束。Key 请求次数、GPU 时间和队列长度是三种不同的量。 |
| 图片上传大小 | 建议原始图片不超过 18 MiB。当前应用解码后上限为 20 MiB,但请求体上限为 25 MiB;Base64 膨胀后无法保证 20 MiB 文件能通过入口。 |
| 大小换算 | 1 MiB = 1,048,576 字节。Base64 长度为 4 × ceil(原始字节数 / 3),另加 JSON、文件名和 data URL 前缀。原始文件接近 18.75 MiB 时就可能超出当前请求体上限。 |
| 上传失败 | 413 可能来自请求入口,也可能来自应用,响应可能不是 JSON。不要只检查解码后的文件大小。 |
轮询建议从 10~20 秒间隔开始,并按 Key 的请求预算调整。例如每 5 秒轮询 10 分钟就约需 120 次请求,尚未计算提交和下载;每日上限较低时会先触发 429。不要为了等待结果反复提交同一任务。
任务生命周期、超时与重试
- 提交未确认:请求超时或连接断开,不确定上游是否已经创建任务。不要立即重新 POST。
- 已受理:HTTP 200 且有
job.job_id,只证明本次受理响应成功,不证明生成完成。 - 列表可见:在
/api/jobs或/api/gallery找到对应 ID,证明已有结果记录;仍需检查结果数量和图片可读性。 - 图片已就绪:GET job.media_url 的 archive_status=ready 表示整组结果 URL 可用;处理中 images 中 status=ready 的图片可先下载。
- 下载已验证:请求 download_url 成功,Content-Type 为图片且内容可解码,文件长度与 sha256 校验通过,才说明这次文件获取成功。
- 观察窗内未确认:列表和队列都找不到任务时,状态仍可能未知。队列为 0 不等于成功,也不能据此编造 failed 或 completed。
上面的名称是接入方观察阶段,不是服务已实现的一组状态枚举。当前没有可靠的按任务 ID 查询终态、进度百分比、开始时间、完成时间或失败原因的独立公开接口;也没有 webhook / 回调。
建议对 GET 使用有限的等待窗;明确的认证和权限错误立即处理,429 按实际原因等待,短暂网络失败可在总截止时间内重试。不要把所有 403/404 都当成“稍后重试”。任务的外部观察耗时包含排队、生成、记录传播、图片就绪和轮询,不能当作纯 GPU 时间。
POST /api/submit:公共提交契约
| 字段 | 类型 / 是否必填 | 取值、默认与含义 |
|---|---|---|
mode | string / 否 | 默认 relaxed。公开约定值只有 fast、relaxed;不要传 null、空字符串或其他大小写。它是公共速度选项,不是文生图专属字段。 |
action | object / 是 | 包含下方某个动作的完整字段,至少有字符串 t。不要把此页未列出的任意 t 当成已支持功能。 |
{"mode":"relaxed","action":{"t":"imagine","prompt":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2"}}
{"ok":true,"job":{"job_id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","media_url":"/api/media/ee4c507f-521a-4ce0-888c-16aa71df6f63","job_type":"v8-2_diffusion","event_type":"diffusion","is_queued":false,"softban":false,"flags":{"mode":"relaxed","visibility":"public"},"meta":{"width":1344,"height":896,"batch_size":4,"parent_id":null,"parent_grid":null}},"attempts":[]}
| 响应字段 | 说明 |
|---|---|
ok | 这次提交返回成功;不是完成状态。 |
job.job_id | 用于关联、轮询和后续动作的任务 ID。示例为 UUID;不要将它当 API Key。 |
job.media_url | 本任务结果查询路径,例如 /api/media/{jobId}。请求时携带自己的 API Key。结果响应直接包含 archive_status、images,不需要先查作品列表。 |
job.job_type / event_type | 上游实际选择的模型或动作信息。用于核对,不把当前列表当作永久完整枚举。 |
job.flags | 可用于核对实际受理的 mode 与可见性。缺失字段不应自行补造成上游已确认的事实。 |
job.meta | 受理时的预计尺寸、结果张数和父任务。最终以结果记录和实际资源为准。 |
attempts | 可能出现的此前尝试与错误,不保证只有空数组;失败响应也可能用这个字段。字段可能带额外信息,不要依赖其未列出的内容。 |
快速 / 慢速适用与验证矩阵
下列所有动作都可在公共请求层传 mode="fast" 或 mode="relaxed";能表达不等于上游一定接受或完成。套餐、模型、源任务和当前资源仍会约束实际执行。
| 功能 | fast | relaxed | 2026-11-13 证据边界 |
|---|---|---|---|
| 普通 imagine | 已产出 | 已产出 | 一次快速约 14.47 秒;一次 v8.2 慢速约 42.62 秒,不是固定 SLA 或相同工作负载的严格性能比较 |
| URL、多图、风格、角色、指令式提示词 | 接口可传,未单独实测 | 已产出 | 不能把普通快速文生图成功推广为所有参考组合已验证 |
| upscale | 接口可传,未单独实测 | 两档已产出 | 本轮只覆盖 v8.2 源图的细腻 / 创意放大 |
| vary | 接口可传,未单独实测 | 两档已产出 | 轻微 / 强烈变体均有四张结果 |
| reroll | 接口可传,未单独实测 | 已产出 | 整组重绘 |
| remix | 接口可传,未单独实测 | 已产出 | 选择一张源图,不代表只输出一张 |
| outpaint | 接口可传,未单独实测 | 100 改画幅完成;2 扩图未确认完成 | 必须区分两个请求组合 |
| inpaint | 接口可传,未单独实测 | 已产出 | 遮罩编辑效果尚未完整验收 |
| video | 历史记录可用;本轮未测 | 上游套餐限制;本轮未测 | 历史 standard 套餐拒绝 relaxed 视频,需 fast;完整当前兼容性未重新核验 |
--fast、--relax、--turbo:旧验证记录发现它们会改变账号默认速度,影响后续任务,并出现外层 mode 与账号状态不一致。遇到这种情况联系服务方核对,不在循环中反复改速度参数。八种动作与完整请求
公共规则:id 是源任务 ID;index 是源任务结果的零基索引,必须满足 0 ≤ index < 源结果张数。普通四张结果是 0、1、2、3,放大后只有一张时只能取 0。输入选一张、输出一张是两件不同的事,最终读取 batch_size 和资源数组长度。
1. imagine:生成
| 字段 | 规格 |
|---|---|
t | 必填 string,固定 imagine |
prompt | 必填 string,文字、图片 URL 与兼容参数。没有已公开的稳定最大字符数;过长文本可能被上游拒绝,不保证任意长度。 |
{"mode":"fast","action":{"t":"imagine","prompt":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2"}}
普通生成本轮输出四张;不同模型或后续动作的张数必须以实际结果为准。显式写版本更利于复现,省略版本时由上游当前默认决定,不承诺永久默认 v8.2。
2. upscale:细腻 / 创意放大
| 字段 | 规格 |
|---|---|
t | 固定 upscale |
id / index | 必填 string / integer,选择一张已有结果 |
type | 必填 string,必须匹配源模型,不能只写 subtle 或 creative |
| 源模型 | 细腻 type | 创意 type | 证据 |
|---|---|---|---|
| v8.2 | v8r2_2x_subtle | v8r2_2x_creative | 本轮均产出一张,1344×896 到 2688×1792 的尺寸记录 |
| v8.1 | 完整当前枚举未重新确认 | 完整当前枚举未重新确认 | 不要直接把 v8.2 前缀套到 v8.1 |
| v7 | v7_2x_subtle | v7_2x_creative | 历史记录,本轮未测 |
| v6.1 | v6r1_2x_subtle | v6r1_2x_creative | 历史记录,本轮未测 |
| v6 / niji 6 / niji 7 | 本页未确认 | 本页未确认 | 不凭模型相似推断前缀 |
{"mode":"relaxed","action":{"t":"upscale","type":"v8r2_2x_subtle","id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
创意放大将 type 改为 v8r2_2x_creative。模型不匹配可能被上游拒绝,历史错误如 v7 2x upscale is not supported by this model。本轮两档均已产出,不代表所有模型枚举已经覆盖。
3. vary:变体
| 字段 | 规格 |
|---|---|
t | 固定 vary |
id / index | 必填,选择源结果 |
strong | 必填 boolean,false 为轻微,true 为强烈,不使用字符串 true 或 false |
v8_1_hd / v8_2_hd | 普通用法显式传 null;历史已识别 true,但高清变体分支本轮未测,不承诺 true 适用于所有源模型 |
{"mode":"relaxed","action":{"t":"vary","strong":false,"v8_1_hd":null,"v8_2_hd":null,"id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
强烈变体只把 strong 改为 true。本轮每次输出四张新结果,继承和归一化后的参数应再查最终 full_command 或 command。
4. reroll:整组重绘
| 字段 | 规格 |
|---|---|
t | 固定 reroll |
id | 必填源任务 ID |
newPrompt | 本页示例必填完整提示词与参数,不依赖空值继承 |
index | 不需要;这是对整组重新生成 |
{"mode":"relaxed","action":{"t":"reroll","newPrompt":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2","id":"ee4c507f-521a-4ce0-888c-16aa71df6f63"}}
5. remix:改词重生
| 字段 | 规格 |
|---|---|
t | 固定 remix |
id / index | 必填,指定一张源结果 |
newPrompt | 必填 string,写完整新描述及需要的参数 |
strong | boolean,true / false;本轮实测 true,false 分支未单独重新验证 |
{"mode":"relaxed","action":{"t":"remix","strong":true,"newPrompt":"a copper teapot on a pale marble table --ar 3:2 --v 8.2","id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
本轮选一张源图后输出了四张新图。不要把“单张源输入”解释为“固定单张输出”。上游某些编辑结果可能限制后续 remix;本轮没有覆盖全部父任务类型。
6. outpaint:扩图 / 改画幅
| 字段 | 规格 |
|---|---|
t | 固定 outpaint |
id / index | 必填源任务及索引 |
newPrompt | 必填完整描述;改画幅时加目标 --ar |
zoomFactor | integer。历史曾观察 1、2、3、4、10、100 被受理;这不是这些值都已完成的保证。传 1.5 的历史错误为 Malformed request。完整稳定值域未确认。 |
{"mode":"relaxed","action":{"t":"outpaint","newPrompt":"a ceramic teapot on a wooden table --ar 9:16","zoomFactor":100,"id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
改画幅已产出:本轮 100 + --ar 9:16 得到 816×1456 的尺寸记录。尺寸会按模型约束调整,不保证像素比完全精确。
{"mode":"relaxed","action":{"t":"outpaint","newPrompt":"a ceramic teapot on a wooden table","zoomFactor":2,"id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
7. inpaint:区域重绘
先上传与源图对应的 PNG 遮罩取得 mask_url,再提交这个动作。两个请求都需要 submit 权限。不能把 Base64 直接当成 maskUrl。
| 字段 | 规格 |
|---|---|
t | 固定 inpaint |
newPrompt | 必填 string,编辑指令 |
maskUrl | 必填 string,使用 /api/mask 实际返回的 mask_url;注意大小写不同 |
id / index | 对应上传遮罩时的 job_id / image_num |
{"mode":"relaxed","action":{"t":"inpaint","newPrompt":"replace the teapot with a copper kettle","maskUrl":"https://storage.example.com/replace-with-uploaded-mask.png","id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","index":0}}
示例 maskUrl 是占位地址,必须替换为真实上传响应,不能原样使用。本轮 v8.2 源图、1344×896 遮罩、慢速模式约 84.58 秒后观察到四张结果。旧的“此动作完全不可用”判断与这次结果不符;本轮只确认产出,未完整确认透明/颜色语义和区域保真。其他模型、快速模式和更多遮罩条件未测。
8. video:图生视频与延长
本轮未测视频。下面保留历史接入记录,并明确未验证的边界。不要把它与本轮图片验收混成一次全量通过。
| 字段 | 规格 |
|---|---|
t | 固定 video |
videoType | 四个已记录值见下表;不包含已确认可用的首尾帧或循环类型 |
parentJob | object,job_id 是源图或源视频 ID,image_num 是有效零基索引 |
animateMode | 历史接口只接受 auto;不是 low 或 high |
newPrompt | string,可为空;运动幅度可写 --motion low 或 --motion high |
stitch | 普通示例传 null;其他取值未公开确认 |
| videoType | 用途 |
|---|---|
vid_1.1_i2v_480 | 图片生成 480 视频,值里没有 p |
vid_1.1_i2v_720 | 图片生成 720 视频,套餐和资源需满足条件 |
vid_1.1_i2v_extend_480 | 延长 480 源视频 |
vid_1.1_i2v_extend_720 | 延长 720 源视频 |
{"mode":"fast","action":{"t":"video","videoType":"vid_1.1_i2v_480","stitch":null,"newPrompt":"--motion low","parentJob":{"job_id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","image_num":0},"animateMode":"auto"}}
{"mode":"fast","action":{"t":"video","videoType":"vid_1.1_i2v_extend_480","stitch":null,"newPrompt":"--motion high","parentJob":{"job_id":"ef5afc90-d951-48ae-92f1-a2c487d62914","image_num":0},"animateMode":"auto"}}
第二个示例的 parentJob 必须是真实源视频,不可照抄示例 UUID。历史 standard 套餐的 relaxed 视频被拒,原错误为 Relax mode for video is limited to Pro and Mega plans。完整当前套餐支持情况、延长次数和最长时长未重新确认。
视频的父任务已带图,不要再在 newPrompt 放图片 URL;历史错误为 Can't use an Image Prompt with a parent job。视频 turbo 的历史错误为 Turbo mode isn't supported for video jobs。首尾双帧、循环与额外视频张数未列为当前已验证能力。
提示词参数:范围、默认与证据
参数写在 prompt 或该动作的 newPrompt 内。不能同时用 --v 和 --niji。未指定的参数可能取上游默认或父任务参数,本服务没有为下表每个参数设固定默认。保留最终 command / full_command 来核对归一化结果。
| 参数 / 别名 | 取值与边界 | 说明 / 验证 |
|---|---|---|
--ar / --aspect | 正数宽:高。常用:1:1、5:4、4:3、3:2、16:9、2:1、21:9、4:5、3:4、2:3、9:16、1:2、9:21 | 历史上限约 14:1 至 1:14,15:1、100:1 曾钳制;HD 历史上限约 4:1 至 1:4,超限可能报错。实际按模型分辨率调整。本轮 3:2、2:3、9:16 已观察。 |
--v / --version | 本页确认模型值:8.2、8.1、7、6.1、6 | 本轮均有生成记录。7 常归一化为 7.0;省略时取上游当前默认,不承诺服务永久固定模型。 |
--niji | 6、7 | 本轮两者均产出,与 --v 二选一。 |
--hd / --sd | 无值开关;不要同时传两者 | v8.2 的 hd 已观察 2048×2048,sd 为标准模式;v8.1 本轮测了 sd,hd 仅有历史记录。其他模型没有本轮成功证据。 |
--raw | 无值开关 | 减少默认风格干预;本轮 v8.2、v6.1 请求保留,其他版本按矩阵。 |
--tile | 无值开关 | 本轮 v8.2 与 hd 组合产出 2048×2048 图。接缝质量没有做像素级验收,其他组合未全测。 |
--stylize / --s | 历史参考范围 0–1000 | 本轮测了 250、150;缺省跟随上游。不是把整个范围和所有模型都重新穷举过。 |
--chaos / --c | 历史参考范围 0–100 | 本轮测了 15、10,控制结果变化程度。 |
--weird / --w | 历史参考范围 0–3000 | 本轮 v8.2 的 100 保留并产出;各模型有效范围未全测。 |
--quality / --q | v7 历史值 1、2、4;v6.1 历史值 0.5、1、2 | 本轮 v7 测 2、4,v6.1 测 0.5。v8.1/8.2 历史记录会静默丢弃,不是 v8 质量开关,v8 使用 hd。默认 1 曾从命令中省略。 |
--stop | 历史参考范围 10–100 | 本轮仅 v6.1 的 80 完成;v7/v8 历史记录为不兼容。其他模型未重新核验。 |
--exp | 完整稳定值域未确认;本轮值 10 | v7 的 10 与 quality 4 一起产出。旧记录也识别 v8,但不能把“整数”或一个成功值说成无限范围。 |
--no | 排除词字符串,逗号或上游支持的分隔方式 | 如 --no text, watermark。本轮与其他参数组合产出;不是保证所有被排除元素绝对消失。 |
--seed | 推荐使用 0–4294967295 的整数 | 本轮测了 271828、123。旧记录观察 0、4294967295、-1 被受理,不代表负数是推荐用法或任意大整数都有效;同 seed 也不保证跨模型或跨动作像素相同。 |
--sref | 一个或多个公开图片 URL,用空格分隔 | 本轮单图与两图成功。统一最大数量未确认,不把某个界面限制当 API 限制。 |
--sw | 历史参考范围 0–1000 | 本轮 200 成功,控制风格参考强度。缺省由上游决定。 |
--sv | 历史解析过整数 1–7,但每个模型只支持子集 | 本轮 v8.2 只确认 --sv 6 成功。旧记录 v8.2 拒绝 1–5、7 为 Unsupported Style Reference version,0、8 为 Invalid value。其他版本当前子集未重新确认。 |
--iw | 历史参考范围 0–3 | 本轮 v7 的 1.5 与单图、多图、组合参考均成功;不能推断所有版本使用同一范围。 |
--cref | 本轮确认单张公开图片 URL | v6.1 与 niji 6 成功;数量上限与其他版本条件未全测。 |
--cw | 历史参考范围 0–100 | 本轮值 100。历史语义为 0 更偏脸部、100 包含更多外观;本轮使用物体素材,不构成人脸一致性验收。 |
--oref | 本轮确认单张公开图片 URL | v7 的 Omni 参考已产出;旧记录 v8.1/8.2、niji 7 不兼容。不能把 v7 写法原样套到所有版本。 |
--ow | 旧记录参考范围 0–1000,本轮值 400 | 与 oref 搭配;完整当前边界、默认和语义未重新核验。 |
--public / --stealth | 无值开关,不同时传 | public 本轮保留且记录为公开。stealth 历史需 Pro / Mega;当前 standard 测试条件不支持成功路径。API 数据归属与 MJ 公共可见性不是同一概念。 |
--profile / --p | 上游真实个性化代码或受支持的用户标识 | 依赖先在上游配置该模型的个性化档案,本轮未提供成功路径所需代码。不从已脱敏的作品响应里假设能取得用户标识,联系服务提供方确认。 |
--motion | low、high | 视频提示词参数的历史记录,本轮未测;与 animateMode 字段不是同一个参数。 |
完整模型列表与验证范围
表中“未测”不表示不支持。“历史”不是本轮重新验证;对完整合法值域尚未确认的参数,保留未知,不编造最大值。
| 能力 | v8.2 | v8.1 | v7 | v6.1 | v6 | niji 6 | niji 7 |
|---|---|---|---|---|---|---|---|
| 基础生成 | 已测 | 已测 | 已测 | 已测 | 已测 | 已测 | 已测 |
| fast 普通生成 | 已测 | 未测 | 未测 | 未测 | 未测 | 未测 | 未测 |
| quality | 历史静默丢弃 | 历史静默丢弃 | 2、4 已测 | 0.5 已测 | 未测 | 未测 | 未测 |
| stop | 历史拒绝 | 历史拒绝 | 历史拒绝 | 80 已测 | 未测 | 未测 | 未测 |
| hd / sd | 均已测 | sd 已测、hd 历史 | 历史不适用 | 历史不适用 | 未测 | 未测 | 未测 |
| 图片 URL + iw | 指令式图片输入已测 | 未测 | 单图、两图已测 | 未测 | 未测 | 未测 | 未测 |
| sref / sw | 已测 | 未测 | 已测 | 未测 | 未测 | 未测 | 未测 |
| sv 当前支持子集 | 6 已测 | 未确认 | 未确认 | 未确认 | 未确认 | 未确认 | 未确认 |
| cref / cw | 旧记录不兼容 | 旧记录不兼容 | 使用 oref | 已测 | 未测 | 已测 | 旧记录不兼容 |
| oref / ow | 旧记录不兼容 | 旧记录不兼容 | 已测 | 旧记录不兼容 | 未测 | 未测 | 旧记录不兼容 |
| 图片 + 指令式提示词 | 已产出,不证明独立 Edit Model 路由 | 旧记录 | 未单独确认 | 未测 | 未测 | 未测 | 未测 |
组合、继承与不支持项
| 组合 / 参数 | 记录与边界 |
|---|---|
| 垫图 + sref + oref + ar | v7 本轮已产出;URL 输入会被上游转换为 s.mj.run 短链,这是正常归一化,不是图片被丢弃。 |
| oref + quality | 历史观察 quality 被静默剥离,任务仍可能产出;不要把受理当成质量参数生效。 |
| hd + tile | v8.2 本轮产出 2048×2048;接缝效果未完整验收。 |
| hd + 超宽 ar | 历史超过 4:1 可能报错,例如 wider than 4:1 are not supported with --hd。 |
| v 与 niji | 二选一,不要同时使用。 |
| 后续动作的 newPrompt | 可能继承或归一化父任务参数;要复现时显式给需要的参数,再核对结果 command。prompt 有参数不等于上游实际执行了全部参数。 |
--edit | 旧网页请求观察会被静默剥离,不是本服务已确认的 Edit Model 开关。图片 + 指令式提示词仍使用 imagine,不据此承诺独立模型路由、固定最多四图或结果不能 remix。 |
--repeat / --r | 旧网页接口记录为 Unrecognized parameter(s)。要多次生成可由调用方逐次提交,但每次都创建独立任务。 |
--bs | v7/v8 历史记录不接受自定义批量。不能用它承诺任意输出张数。 |
--loop / --end | 视频 loop 历史报 Unrecognized parameter(s),end 历史被静默剥离。本轮未重新测试,不能宣称循环或首尾帧已支持。 |
--moodboard | 旧记录不接受该命名参数;不把任意情绪板 ID 当 profile code。其他情绪板接入方式未在本页提供稳定契约。 |
| Pan、Describe、Blend、Retexture | 没有在当前公开清单中确认可用的独立请求流程;不能因上游存在相近界面就宣称本服务已经实现。 |
参考图:直接 URL 与上传后引用
支持直接传图片 URL,不必先转 Base64。只有本地文件、调用方内存图片或需要自行读取的受限图片,才先上传换短链。服务不提供“给 /api/upload 一个 url 并代下载”的能力。
| 用途 | URL 放置方式 | 本轮证据 |
|---|---|---|
| 构图 / 内容垫图 | 放在 action.prompt 最前面、文字之前;多个地址用空格分隔 | v7 单图、两图、组合参考已产出 |
| 风格参考 | --sref 后放一个或多个 URL,再配 --sw | v8.2 单图、v7 多图已产出 |
| Omni 参考 | v7 用 --oref URL 和 --ow | 单图、组合已产出 |
| 旧版角色参考 | v6.1 / niji 6 用 --cref URL 和 --cw | 两种模型已产出 |
本轮参考素材为测试物体图片,不代表已量化验收真人面部一致性。单图、多图的全量数量上限未确认;本页已测的是一张和两张,不保证任意张数。
直接 URL 的八组完整请求
以下 JSON 均发送到 POST /api/submit,带 Authorization 和 Content-Type。images.example.com 是示例域名,必须换成 MJ 能读取的真实图片地址。没有单独的 image_url 或 reference_urls 生成字段。
1. 单张垫图
{"mode":"relaxed","action":{"t":"imagine","prompt":"https://images.example.com/reference.jpg a teapot in a sunlit studio --iw 1.5 --ar 3:2 --v 7"}}
2. 多张垫图
{"mode":"relaxed","action":{"t":"imagine","prompt":"https://images.example.com/subject.jpg https://images.example.com/scene.jpg a collection of teapots on a shelf --iw 1.5 --v 7"}}
3. 单张风格参考
{"mode":"relaxed","action":{"t":"imagine","prompt":"a paper lantern in a rainy alley --sref https://images.example.com/style.jpg --sw 200 --sv 6 --v 8.2"}}
4. 多张风格参考
{"mode":"relaxed","action":{"t":"imagine","prompt":"a paper lantern in a rainy alley --sref https://images.example.com/style-a.jpg https://images.example.com/style-b.jpg --sw 200 --v 7"}}
5. v7 Omni 参考
{"mode":"relaxed","action":{"t":"imagine","prompt":"a teapot displayed in a cozy cafe --oref https://images.example.com/character.jpg --ow 400 --v 7"}}
6. v6.1 角色参考
{"mode":"relaxed","action":{"t":"imagine","prompt":"a ceramic teapot on a kitchen counter --cref https://images.example.com/character.jpg --cw 100 --v 6.1"}}
niji 6 写法是把 --v 6.1 换成 --niji 6,不能同时保留两种版本参数。
7. 垫图 + 风格 + Omni
{"mode":"relaxed","action":{"t":"imagine","prompt":"https://images.example.com/composition.jpg a teapot in a cozy cafe --iw 1.5 --sref https://images.example.com/style.jpg --sw 200 --oref https://images.example.com/character.jpg --ow 400 --ar 3:2 --v 7"}}
8. v8.2 图片 + 指令式提示词
{"mode":"relaxed","action":{"t":"imagine","prompt":"https://images.example.com/reference.jpg make this into a watercolor painting --sref https://images.example.com/style.jpg --sw 200 --raw --v 8.2"}}
最后一例是 imagine 的图片输入与指令,并没有 --edit 参数或独立编辑模型字段。本轮有产出,但不从这个样本推断所有编辑模型的数量、宽高比继承或 remix 限制。
URL 要求与失败排查
| 检查项 | 规则 |
|---|---|
| 可达性 | 必须让 MJ 能读取。你的浏览器能打开不代表上游能打开;localhost、局域网地址和私有存储不适合直接传。 |
| 内容 | 应直接返回图片文件,不是相册、网盘分享页、登录页或验证页。推荐 HTTPS;后缀为 jpg 不足以证明响应是图片。 |
| 认证 | 本服务不会向图片站附加你的 Cookie、Authorization 或自定义请求头。受限图片需由调用方先下载再上传,或提供不依赖这些请求头的有效链接。 |
| 有有效期的 URL | 保留完整查询参数,并让链接在排队和上游读取期间有效。不保证任意图片托管服务的链接都被接受。 |
| 空格 | URL 自身空格编码为 %20;多个图片 URL 之间使用普通空格。JSON 里的 & 保持普通字符,不转成字符串 &。 |
| 本服务图片 API | 需要 API Key 的 /api/image 和 /api/thumb 地址不能直接当作 MJ 可读的公开图链,也不要把 API Key 拼进 URL。 |
| Base64 | 不要把 Base64 或 data:image/png;base64 前缀直接塞进 prompt。先传 file_b64,取得 short_url 再引用。 |
| 正常归一化 | 第三方 URL 在最终命令里变为 s.mj.run 短链不代表失败。需检查最终参数及真实结果,不能仅看 200。 |
POST /api/upload:图片上传
| 字段 | 规格 |
|---|---|
file_b64 | 必填 string,纯 Base64 或 data:image/png;base64 前缀。示例为可校验的 512×512 PNG;本轮只验证 PNG,其他格式由上游决定。 |
filename | 可选 string,默认 image.png;建议使用简短的普通文件名及与内容一致的后缀,不提供本地路径。 |
{"filename":"reference.png","file_b64":"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"}
上例包含完整测试素材,不是省略片段。将 JSON 作为请求体发送到 /api/upload;真实业务可替换为自己的 Base64,并遵守前述 18 MiB 建议上限。不要手工修改编码中间字符。
{"short_url":"https://s.mj.run/21IY3X09bSU","usage":{"image_prompt":"把 short_url 放在 prompt 最前面","style_ref":"在 prompt 末尾加 --sref https://s.mj.run/21IY3X09bSU","character_ref":"使用兼容版本的 --cref 或 --oref"}}
响应短链用于之后的提交,上传本身不创建生成任务。字段 usage 是帮助文案,不是必须照抄的完整提示词;上传返回的真实 short_url 优先于示例地址。
import base64
import os
import requests
BASE = "{BASE}"
with open("reference.png", "rb") as source:
image_b64 = base64.b64encode(source.read()).decode("ascii")
response = requests.post(
BASE + "/api/upload",
headers={"Authorization": "Bearer " + os.environ["MJ_API_KEY"]},
json={"filename": "reference.png", "file_b64": image_b64},
timeout=60,
allow_redirects=False,
)
if response.status_code != 200:
raise RuntimeError("Upload failed: HTTP " + str(response.status_code) + " " + response.text[:300])
print(response.json()["short_url"])
POST /api/mask:上传区域遮罩
| 字段 | 规格 |
|---|---|
mask_b64 | 必填 string,PNG 的纯 Base64;本轮没有使用 data URL 前缀。不要套用 file_b64 字段名。 |
job_id | 必填 string,对应已有源图任务。 |
image_num | integer,缺省 0;应满足 0 ≤ image_num < 源结果张数,负数或越界不属于本页有效用法。 |
遮罩应与所选源图实际像素尺寸一致。本服务原样转发,不保证帮你缩放、反转或修正遮罩。当前没有已独立确认的完整颜色/透明度语义;推荐使用上游编辑器的有效遮罩或由接入方先验收。下面是本轮产出的同类演示:白色不透明底,中央矩形透明;不据此承诺透明处必然代表重绘或保留。
# 依赖:python -m pip install requests pillow
# 必须替换为你真实源任务的 ID、索引和实际尺寸
import base64
from io import BytesIO
import os
import requests
from PIL import Image, ImageDraw
BASE = "{BASE}"
JOB_ID = "ee4c507f-521a-4ce0-888c-16aa71df6f63"
IMAGE_NUM = 0
WIDTH, HEIGHT = 1344, 896
HEAD = {"Authorization": "Bearer " + os.environ["MJ_API_KEY"]}
mask = Image.new("RGBA", (WIDTH, HEIGHT), (255, 255, 255, 255))
ImageDraw.Draw(mask).rectangle(
(WIDTH // 3, HEIGHT // 3, WIDTH * 2 // 3, HEIGHT * 2 // 3),
fill=(255, 255, 255, 0),
)
stream = BytesIO()
mask.save(stream, "PNG")
upload = requests.post(
BASE + "/api/mask", headers=HEAD, timeout=60, allow_redirects=False,
json={"job_id": JOB_ID, "image_num": IMAGE_NUM,
"mask_b64": base64.b64encode(stream.getvalue()).decode("ascii")},
)
if upload.status_code != 200:
raise RuntimeError("Mask upload failed: HTTP " + str(upload.status_code))
mask_url = upload.json()["mask_url"]
created = requests.post(
BASE + "/api/submit", headers=HEAD, timeout=60, allow_redirects=False,
json={"mode": "relaxed", "action": {
"t": "inpaint", "newPrompt": "replace the teapot with a copper kettle",
"maskUrl": mask_url, "id": JOB_ID, "index": IMAGE_NUM,
}},
)
if created.status_code != 200:
raise RuntimeError("Inpaint submission failed: HTTP " + str(created.status_code))
print(created.json()["job"]["job_id"])
{"mask_url":"https://storage.example.com/uploaded-mask.png"}
响应可能含额外字段,接入只需要 mask_url。上面的返回地址也是形状示例,不是真实可用遮罩。本轮上传成功约 0.60 秒;不同模型、图片尺寸和遮罩语义不能仅凭这一次请求外推。
查询图片结果与下载 URL
生成结果以 URL 返回,不返回 Base64。提交任务后,使用响应中的 job.media_url 查询结果。新图片任务会自动准备结果,调用方不需要额外发起准备请求。
| 字段 / 状态 | 含义 |
|---|---|
| archive_status | 结果准备状态,保留实际响应字段名。pending:等待处理;processing:处理中;retry:等待自动重试;ready:全部图片可下载;failed:本次结果准备失败;unsupported:当前不支持获取该类型结果。这是结果可用性状态,不是生成进度百分比。 |
| images | 结果图片数组。每张有零基 index 和 status;只有 status=ready 的条目才有 download_url、thumb_url、preview_url、尺寸、字节数、content_type 和 sha256。 |
| download_url | 原始 PNG 图片的下载 URL。请求这个 URL 时不要带本服务的 Authorization。使用响应中的完整地址,不修改路径或查询参数。 |
| thumb_url / preview_url | 384px / 640px WebP 预览 URL,按边界保持比例缩放;下载原始图片使用 download_url。 |
| url_expires_at | URL 到期时间,Unix 秒。当前约 15 分钟有效;过期后重新查询本接口取得新 URL,不把一次返回的 URL 当永久地址。 |
| error / attempts | 错误说明和尝试次数。failed 表示结果准备失败,不一定表示生成失败;retry 不会创建新生成任务。 |
{"job_id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","archive_status":"processing","attempts":1,"error":null,"url_expires_at":1794582000,"images":[{"index":0,"status":"ready","content_type":"image/png","width":1344,"height":896,"bytes":1376205,"sha256":"replace-with-response-checksum","download_url":"https://images.example.com/result-0.png?token=replace-with-current-response","thumb_url":"https://images.example.com/result-0-small.webp?token=replace-with-current-response","preview_url":"https://images.example.com/result-0-large.webp?token=replace-with-current-response"},{"index":1,"status":"pending"},{"index":2,"status":"pending"},{"index":3,"status":"pending"}]}
这是响应形状示例,地址、校验值和时间都需以真实响应为准。上例第一张已可下载,其余仍在准备中;如果需要整组图片,等待 archive_status=ready。图片结果不包含 file_b64、image_base64 或其他 Base64 文件内容。
curl --fail-with-body -X POST {BASE}/api/media/ee4c507f-521a-4ce0-888c-16aa71df6f63/archive \
-H "Authorization: Bearer $MJ_API_KEY" \
-H "Content-Type: application/json" -d '{}'
历史任务需能在最近结果窗口找到,否则返回 404。只允许处理自己的任务,不允许通过猜测 ID 读取其他人的图片。已就绪的图片会保留;请求超时后先查询状态,不盲目重新提交生成任务。
当前图片结果准备支持每张不超过 64MiB。视频不适用这组图片结果流程,视频接入范围见单独小节。
GET /api/jobs:原始任务记录列表
| 参数 | 规格 |
|---|---|
page_size | integer,默认 60,当前代码收敛到 1–100。仅表示拉取最近窗口,没有 cursor、offset 或翻页保证。 |
{"data":[{"id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","job_type":"v8-2_diffusion","event_type":"diffusion","full_command":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2","batch_size":4,"width":1344,"height":896,"enqueue_time":"2026-11-13T14:44:20.115853+00:00","parent_id":null,"parent_grid":null}],"scoped_to_key":true}
列表可附加 media_archive,其字段与 /api/media/{jobId} 的独立响应相同,包含图片可用状态及 URL。新任务优先使用 job.media_url 查询,不依赖列表窗口。
此接口每次只查询一个来源的最近记录,不聚合所有生成来源;跨来源查结果优先使用 /api/gallery,并仍注意窗口限制。依赖字段限于示例中的任务身份、命令、类型、结果数量、尺寸和父任务关系。响应当前可能有额外上游字段,不将其全部提升为稳定公开契约,也不要传播额外身份信息。没有可靠的 completed_at、started_at 或终态错误字段,enqueue_time 不能替代 GPU 执行起止时间。
GET /api/gallery:作品卡片列表
| 参数 | 规格 |
|---|---|
page_size | integer,默认 30,当前每个来源拉取窗口收敛到 1–60;聚合多个来源时总数量可能超过该值。没有 cursor 或完整历史翻页。 |
{"items":[{"id":"ee4c507f-521a-4ce0-888c-16aa71df6f63","prompt":"a ceramic teapot on a wooden table","command":"a ceramic teapot on a wooden table --ar 3:2 --v 8.2","job_type":"v8-2_diffusion","event_type":"diffusion","is_video":false,"batch_size":4,"width":1344,"height":896,"enqueued_at":"2026-11-13T14:44:20.115853+00:00","thumbs":["/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/0?size=384","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/1?size=384","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/2?size=384","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/3?size=384"],"fulls":["/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/0?size=640","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/1?size=640","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/2?size=640","/api/thumb/ee4c507f-521a-4ce0-888c-16aa71df6f63/3?size=640"]}],"account_count":1,"accounts":[],"errors":[],"scoped_to_key":true}
卡片可附加 media_archive,包含 archive_status 与 images 中的结果 URL。新任务直接用 job.media_url 查询即可;历史任务未登记结果时可请求 /api/media/{jobId}/archive。原有 thumbs / fulls 路径就绪后返回 302 下载地址,未就绪返回 202 JSON,不能无条件保存为图片。
thumbs / fulls 是相对路径,调用程序需要拼接 API 基地址并带自己的 API Key。索引与数组顺序一致;不要固定循环四次。is_video 为 true 时是视频结果,封面路径的尺寸可用性需单独判断。
图片 URL、尺寸与下载
推荐从 /api/media/{jobId} 的 images 取得 URL:download_url 用于原始 PNG,thumb_url 与 preview_url 用于预览。查询接口返回 JSON 和 URL,不返回图片 Base64;对下载 URL 的请求才返回图片文件。
| size | 图片结果 |
|---|---|
| 128 | 按 128px 边界保持比例生成预览,实际尺寸受原图宽高比影响。 |
| 384 | 按 384px 边界保持比例生成预览,对应 thumb_url 的预览规格。 |
| 640 | 按 640px 边界保持比例生成预览,对应 preview_url 的预览规格。 |
| original | 原始 PNG,与已就绪结果的 download_url 对应,实际尺寸以 width / height 和文件内容为准。 |
不要传任意数值期待动态缩放。size 描述图片规格;视频封面并非每个尺寸都有,本轮观察 640px 封面可读,部分 384px 封面返回 404。
# 查看响应的状态和 Location,不将 JSON 或跳转响应保存为图片
curl --fail-with-body -D - -o /dev/null "{BASE}/api/image/ee4c507f-521a-4ce0-888c-16aa71df6f63/0?size=original" \
-H "Authorization: Bearer $MJ_API_KEY"
如果返回 302,用不带 API Key 的独立请求访问 Location;如果返回 202,按 JSON 状态继续查询。不要把 API Key 自动附加到返回的下载 URL。下载成功应为 HTTP 200 和正确的 Content-Type,保存文件后可用 bytes 与 sha256 验证完整性。
视频结果范围
视频当前不适用 /api/media 的图片结果流程,会显示 unsupported。历史已知的视频 URL 形状如下,需替换真实任务 ID 和有效序号;本轮没有重新验收视频生成或完整下载,不宣称它与图片流程具有相同保障。
https://cdn.midjourney.com/video/ee4c507f-521a-4ce0-888c-16aa71df6f63/0.mp4
https://cdn.midjourney.com/video/ee4c507f-521a-4ce0-888c-16aa71df6f63/0_640_N.webp?frame=last
访问这些地址也不要发送本服务 API Key。若返回 403,检查 URL 有效性与当前可用性并联系服务方,不假设所有 403 都能靠等待解决。
GET /api/credits:共享 GPU 额度快照
{"account_count":1,"relax_ms_total":-8481557,"fast_available_ms_total":44940000,"accounts":[{"plan":"standard","relax_ms":-8481557,"fast_available_ms":44940000}]}
| 字段 | 类型与说明 |
|---|---|
account_count | number,快照中可汇总的资源数量,不是你的 Key 任务数 |
fast_available_ms_total | number,快速余额毫秒;除以 60000 得分钟,除以 3600000 得小时 |
relax_ms_total | number,慢速资源结余,可为负;不能据此精确换算某任务何时开始 |
accounts | 可能包含套餐和余额条目,不依赖数组顺序或把它当作可操作身份列表 |
数据是快照,当前可能缓存约 45 秒;任务完成后立即查询不保证计费已经最终结算。提交、列表查询和下载产生的 Key 请求次数与这些 GPU 毫秒不是同一指标。没有公开的单 Key 剩余次数查询,需联系服务方确认配置。
GET /api/queue:共享队列计数
{"running":2,"waiting":1,"account_count":1,"accounts":[]}
running / waiting 是计数,不是任务 ID 列表;快照可能有缓存。0 / 0 不能证明你的任务完成,也不能证明任务失败。不要用它计算单个任务精确排队时间或 GPU 时间。
GET /health:连通性检查
{"service":"mj-lite-service","version":"0.2","ok":true,"accounts":1,"docs":"/docs"}
错误、恢复与响应结构
先看 HTTP 状态,再检查 Content-Type。应用错误通常有字符串 error;hint、detail、attempts、retry_after 都可能缺省,不能假设每次同形。请求入口或其他上游失败还可能返回 HTML 或纯文本。
| HTTP | 可能来源 | 处理建议 |
|---|---|---|
| 200 | 请求成功;提交动作只是已受理 | 保存任务 ID,继续核对列表和资源 |
| 202 | 结果已登记,但图片尚未全部就绪 | 读取 JSON 状态并有限轮询,不能把正文当图片 |
| 302 | 已鉴权图片接口返回下载地址 | 不要向下载 URL 发送 API Key;优先从 media JSON 取得 download_url 后独立下载 |
| 304 | 图片缓存条件请求命中 | 复用已有正文,不把空响应当新图片 |
| 400 | JSON、字段或动作格式有误 | 检查 error 和请求体;不反复重发原样请求 |
| 401 | API Key 缺失/无效,或上游登录状态失效被转发 | 根据 error 区分,不把上游身份问题都当作要换 API Key |
| 403 | 缺权限、Key 已撤销/过期、作品归属拒绝,或上游图片访问验证 | 若 error 为图片获取失败,联系服务方排查取图;不要盲目更换有效 Key |
| 404 | 路径、任务、索引或尺寸不存在;图片尚未就绪;任务没有产出 | 核对字段及实际资源,不默认所有 404 只需等一会儿 |
| 413 | 请求体或解码后图片超过限制 | 缩小原文件,计算 Base64 和 JSON 总大小;响应可能不是 JSON |
| 429 | Key 每日次数、图片短时限流或上游限制 | 按 error 和可选 retry_after 区分。每日限额等 UTC 日期切换,短时限流按秒等待;GET 轮询也占次数 |
| 500 | 未预期的服务错误 | 保留时间、路径及响应,联系服务方;不要自动重发可能已受理的 POST |
| 502 | 上游拒绝、参数/模型冲突、上游访问失败,或多次尝试均失败 | 检查 error 与 attempts,不把所有 502 都当短暂网络错误 |
| 503 | 没有可用生成容量或服务暂不可用 | 停止继续提交,查询恢复情况;不要用高频重试加重队列 |
{"error":"请求没有 submit 权限","hint":"联系服务提供方确认权限"}
{"error":"图片获取失败 (403)","detail":null}
{"error":"图片请求太频繁","retry_after":60}
retry_after 是 JSON 里的秒数示例,不承诺所有错误都返回 HTTP Retry-After 头。当前没有稳定统一的机器错误 code 枚举,本页不虚构一组与实现不符的代码。
可运行的 Python 与 Node.js 示例
示例需要自己的 API Key,运行入口会真实提交任务,默认使用 relaxed。提交后直接按任务 ID 等待结果 URL,不需要先轮询作品列表;取得 URL 后用不含 API Key 的独立请求下载。结果为 URL,不含 Base64。失败会明确报错,不自动重发 POST。
Python 3.10+:requests
先安装 requests,设置 MJ_API_KEY,保存为 client.py。主流程为 submit → wait_for_result → download_image;wait_for_record 是按列表查看记录的可选辅助函数,不是获取结果 URL 的前置条件。
import os
import time
from pathlib import Path
import requests
BASE = "{BASE}"
KEY = os.environ.get("MJ_API_KEY", "").strip()
if not KEY:
raise RuntimeError("Set MJ_API_KEY before running")
HEAD = {"Authorization": "Bearer " + KEY}
def api_request(method, path, body=None, timeout_seconds=30):
response = requests.request(
method, BASE + path, headers=HEAD, json=body,
timeout=timeout_seconds, allow_redirects=False,
)
if not 200 <= response.status_code < 300:
try:
message = response.json().get("error", response.text[:200])
except ValueError:
message = response.text[:200]
raise RuntimeError("HTTP " + str(response.status_code) + ": " + str(message))
return response
def submit(prompt, mode="relaxed"):
response = api_request("POST", "/api/submit", {
"mode": mode, "action": {"t": "imagine", "prompt": prompt},
})
return response.json()["job"]["job_id"]
def wait_for_record(job_id, timeout_seconds=600):
deadline = time.monotonic() + timeout_seconds
while True:
remaining = deadline - time.monotonic()
if remaining <= 0:
raise TimeoutError("Observation deadline reached; task completion is unknown: " + job_id)
response = api_request("GET", "/api/gallery?page_size=60", timeout_seconds=min(20, remaining))
for record in response.json().get("items", []):
if record.get("id") == job_id:
return record
time.sleep(min(10, max(0, deadline - time.monotonic())))
def wait_for_result(job_id, timeout_seconds=600):
deadline = time.monotonic() + timeout_seconds
while time.monotonic() < deadline:
remaining = deadline - time.monotonic()
payload = api_request("GET", "/api/media/" + job_id, timeout_seconds=max(0.1, min(20, remaining))).json()
if payload["archive_status"] == "ready":
return payload
if payload["archive_status"] in ("failed", "unsupported"):
raise RuntimeError("Result preparation failed: " + str(payload.get("error")))
time.sleep(min(10, max(0, deadline - time.monotonic())))
raise TimeoutError("Result observation deadline reached: " + job_id)
def download_image(job_id, index, path):
manifest = api_request("GET", "/api/media/" + job_id).json()
image = next((item for item in manifest["images"] if item["index"] == index and item["status"] == "ready"), None)
if image is None:
raise RuntimeError("Image result is not ready")
# Do not send the service API Key to the returned download URL.
response = requests.request("GET", image["download_url"], timeout=60, allow_redirects=False)
if response.status_code != 200 or not response.headers.get("Content-Type", "").lower().startswith("image/"):
raise RuntimeError("Image download failed: HTTP " + str(response.status_code))
digest = __import__("hashlib").sha256(response.content).hexdigest()
if len(response.content) != image["bytes"] or digest != image["sha256"]:
raise RuntimeError("Image file integrity check failed")
Path(path).write_bytes(response.content)
return path
if __name__ == "__main__":
job_id = submit("a ceramic teapot on a wooden table --ar 3:2 --v 8.2", mode="relaxed")
print("Accepted:", job_id)
result = wait_for_result(job_id)
print("Result URLs ready:", len(result["images"]))
download_image(job_id, 0, "out.png")
print("Downloaded out.png")
Node.js 18+:内置 fetch,保存为 client.cjs
使用 CommonJS 的 .cjs 后缀运行 node client.cjs;不需要第三方请求库。每次请求使用 AbortSignal.timeout,总轮询也有截止时间。BASE 只在一处配置,不把模板变量混成错误 URL。
const { writeFileSync } = require("node:fs");
const BASE = "{BASE}";
const KEY = (process.env.MJ_API_KEY || "").trim();
if (!KEY) throw new Error("Set MJ_API_KEY before running");
async function apiRequest(method, path, body, timeoutMs = 20000) {
const response = await fetch(BASE + path, {
method,
headers: {
Authorization: "Bearer " + KEY,
"Content-Type": "application/json",
},
body: body === undefined ? undefined : JSON.stringify(body),
redirect: "error",
signal: AbortSignal.timeout(timeoutMs),
});
if (!response.ok) {
const text = await response.text();
let message = text.slice(0, 200);
try { message = JSON.parse(text).error || message; } catch { }
throw new Error("HTTP " + response.status + ": " + message);
}
return response;
}
async function submit(prompt, mode = "relaxed") {
const response = await apiRequest("POST", "/api/submit", {
mode, action: { t: "imagine", prompt },
});
return (await response.json()).job.job_id;
}
async function waitForRecord(jobId, timeoutMs = 600000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const remaining = deadline - Date.now();
if (remaining <= 0) break;
const response = await apiRequest("GET", "/api/gallery?page_size=60", undefined, Math.max(1, Math.min(20000, remaining)));
const data = await response.json();
const found = (data.items || []).find(record => record.id === jobId);
if (found) return found;
await new Promise(resolve => setTimeout(resolve, Math.min(10000, Math.max(0, deadline - Date.now()))));
}
throw new Error("Observation deadline reached; task completion is unknown: " + jobId);
}
async function waitForResult(jobId, timeoutMs = 600000) {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
const remaining = Math.max(1, Math.min(20000, deadline - Date.now()));
const response = await apiRequest("GET", "/api/media/" + jobId, undefined, remaining);
const manifest = await response.json();
if (manifest.archive_status === "ready") return manifest;
if (["failed", "unsupported"].includes(manifest.archive_status)) throw new Error("Result preparation failed: " + manifest.error);
await new Promise(resolve => setTimeout(resolve, Math.min(10000, Math.max(0, deadline - Date.now()))));
}
throw new Error("Result observation deadline reached: " + jobId);
}
async function downloadImage(jobId, index, filename) {
const manifest = await (await apiRequest("GET", "/api/media/" + jobId)).json();
const image = manifest.images.find(item => item.index === index && item.status === "ready");
if (!image) throw new Error("Image result is not ready");
// Do not send the service API Key to the returned download URL.
const response = await fetch(image.download_url, { signal: AbortSignal.timeout(60000), redirect: "error" });
if (!response.ok || !(response.headers.get("content-type") || "").toLowerCase().startsWith("image/")) {
throw new Error("Image download failed: HTTP " + response.status);
}
const bytes = new Uint8Array(await response.arrayBuffer());
const digest = require("node:crypto").createHash("sha256").update(bytes).digest("hex");
if (bytes.byteLength !== image.bytes || digest !== image.sha256) throw new Error("Image file integrity check failed");
writeFileSync(filename, bytes);
return filename;
}
async function run() {
const jobId = await submit("a ceramic teapot on a wooden table --ar 3:2 --v 8.2", "relaxed");
console.log("Accepted:", jobId);
const result = await waitForResult(jobId);
console.log("Result URLs ready:", result.images.length);
await downloadImage(jobId, 0, "out.png");
console.log("Downloaded out.png");
}
if (require.main === module) {
run().catch(error => { console.error(error.message); process.exitCode = 1; });
}
常见问题与接入验收
快速模式是不是只有文生图?
不是,mode 是公共提交字段。但本轮快速模式只验证了普通文生图;其他动作的 fast 分支明确标为未单独实测,不把“可传”写成“已完成”。
为什么提交 200 后一直没有结果?
可能仍在处理、落到列表窗口外、上游未产出或状态无法查询。保存任务 ID、提交时间和响应,使用有限等待窗。队列 0 不构成成功证明;不要自动重新提交导致重复任务。
为什么图片 URL 返回 403,但 API Key 能查询结果?
查询权限和下载 URL 的有效性需分别检查。先重新查询结果,使用最新 download_url 再下载,且不要附加 API Key。如果最新 URL 仍被拒绝,保留任务 ID、时间和响应状态联系服务方,不反复提交生成任务。
结果是否返回 Base64?
不返回。生成结果通过 images 中的 download_url、thumb_url、preview_url 提供。参考图上传支持 file_b64,这是输入方式,不代表生成输出也是 Base64。
如何获取原始分辨率的图片?
使用 images 中已就绪结果的 download_url,按 content_type、width、height、bytes、sha256 核对文件。预览 URL 用于展示,不能代替原图。URL 失效后重新查询即可。
为什么新 Key 还能看到部分旧作品?
历史未归属任务当前放行,不符合严格隔离承诺。接入方应知悉此限制;有明确归属的新任务仍按 Key 判断。不能仅因 scoped_to_key=true 就推断所有历史数据已隔离。
如何知道还有多少调用次数?
/api/credits 给 GPU 毫秒,不给单 Key 剩余次数。每日次数、权限、到期时间联系服务方确认。轮询和取图也计数,UTC 00:00 重置。
批量生成怎么做?
当前没有公开的一次多任务事务或批量幂等接口。由调用方逐条提交并保存每个 job_id;先使用较低并发,按资源与请求预算调节,失败时不要盲重发全部。每个请求都是独立任务和独立结果。
这份文档是否宣称全部参数已实测?
没有。它覆盖当前列出的公开能力,并把已产出、历史记录、条件限制、未确认和当前异常分开。个人化成功路径、stealth 成功路径、视频新一轮生成、所有模型交叉参数、所有数值边界、人物一致性、区域保真都没有被本轮完整验收。
接入验收至少分别核对:认证、权限、受理 ID、实际参数、结果张数、资源可读、尺寸格式、超时恢复和数据范围。功能变更、上游版本或套餐变化后,相关状态需要重新确认,不能只靠文档存在某个参数就宣布可用。