Midjourney(MJ)API 调用

MJ 使用异步任务流程:提交 Imagine,保存任务 ID,再轮询任务状态,成功后读取 imageUrl。

当前为 dev 预览,生产环境尚未开放。 本页示例使用 https://teamorouter-dev.teamolab.com,需要该开发环境的 API Key 和余额。生产环境的 Key、余额与 dev 分开,不能混用。

接口地址与鉴权

Base URL 为 https://teamorouter-dev.teamolab.com,不带 /v1。请求使用通用 MJ 格式,不能通过 OpenAI Images SDK 的 images.generate() 调用。

方法 路径 用途
POST /mj/submit/imagine 提交 Imagine 任务
GET /mj/task/{task_id}/fetch 查询任务状态及结果

两个接口都需要 TeamoRouter API Key:

http
Authorization: Bearer <TEAMO_API_KEY>
Content-Type: application/json

下方示例从环境变量读取 Key,请在自己的服务端保存凭据。

提交 Imagine

bash
export TEAMO_API_BASE="https://teamorouter-dev.teamolab.com"
export TEAMO_API_KEY="<你的 dev API Key>"

curl --max-time 610 -D mj-submit-headers.txt \
  "$TEAMO_API_BASE/mj/submit/imagine" \
  -H "Authorization: Bearer $TEAMO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "botType": "MID_JOURNEY",
    "prompt": "A tiny blue sailboat on a calm lake, watercolor illustration --ar 1:1",
    "state": "my-mj-request-001"
  }'
参数 必填 说明
prompt 是 非空的图片描述,可带 --ar 等普通 MJ 参数。
botType 否 省略或填写 MID_JOURNEY;当前不支持 NIJI_JOURNEY。
model 否 省略即可;若填写,仅接受 mj_imagine 或 mj_imagine-1k。
state 否 调用方自定义的关联标记,不是幂等键,不能防止重复提交。

受理响应示例:

json
{
  "code": 1,
  "description": "提交成功",
  "result": "1320098173412546"
}

必须同时检查 HTTP 成功、code 为数字 1(已提交)或 22(已排队),以及 result 为有效任务 ID。HTTP 200 本身不代表受理成功;其他业务码应查看 description。result 可能是字符串或整数,保存为字符串后用于查询。任务 ID 由字母、数字、_ 或 - 组成,最长 128 个字符。

保存响应头 x-request-id,用于账单查询和问题排查。如果响应头包含 X-Teamo-Task-Lookup: pending,保留已返回的任务 ID,稍后查询;暂时的 404 不代表提交失败,不能因此再次提交。

查询任务与取得图片

将 TASK_ID 替换为提交响应的 result:

bash
curl "$TEAMO_API_BASE/mj/task/TASK_ID/fetch" \
  -H "Authorization: Bearer $TEAMO_API_KEY"

建议每 10 秒查询一次。响应直接是 MJ task 对象,没有额外的 data 包装。成功示例(节选):

json
{
  "id": "1320098173412546",
  "status": "SUCCESS",
  "progress": "100%",
  "imageUrl": "https://example.com/mj-result.png",
  "failReason": ""
}
status 处理方式
空字符串、NOT_START、SUBMITTED、IN_PROGRESS 等非终态 保留任务 ID,继续轮询;0% 不代表失败。
SUCCESS 停止轮询,读取 imageUrl 并及时保存图片。
FAILURE、CANCEL 停止轮询,查看 failReason。

结果中还可能包含 imageUrls、buttons 等上游字段。返回 buttons 不表示当前已支持执行放大、变体等 Action。图片 URL 的域名和有效期取决于上游,不保证永久有效。

任务查询按用户隔离,同一用户可使用其其他有效 Key 查询。任务查询记录从首次登记起保留 7 天,重复查询不延长保留时间;这不等于图片保留 7 天。任务不存在、已过期或不属于当前用户时都返回 404。

Python 完整示例

使用 Python 标准库,无需 OpenAI SDK。示例只提交一次,并在等待超时后保留任务 ID;再次查询应使用这个 ID,不能重跑提交步骤。

python
import json
import os
import re
import time
import urllib.error
import urllib.request

base = os.environ.get("TEAMO_API_BASE", "https://teamorouter-dev.teamolab.com").rstrip("/")
key = os.environ["TEAMO_API_KEY"]

def request(path, body=None):
    req = urllib.request.Request(
        base + path,
        data=json.dumps(body).encode() if body is not None else None,
        headers={
            "Authorization": "Bearer " + key,
            "Content-Type": "application/json",
        },
    )
    try:
        with urllib.request.urlopen(req, timeout=610 if body is not None else 60) as response:
            return json.load(response), response.headers
    except urllib.error.HTTPError as error:
        request_id = error.headers.get("x-request-id", "unknown")
        detail = error.read().decode("utf-8", errors="replace")
        raise RuntimeError(f"HTTP {error.code}; request_id={request_id}; {detail}") from error

# 只提交一次;网络异常或 unknown 结果也不要自动重试此调用。
submitted, headers = request("/mj/submit/imagine", {
    "botType": "MID_JOURNEY",
    "prompt": "A tiny blue sailboat on a calm lake --ar 1:1",
    "state": "my-mj-request-001",
})
task_id = str(submitted.get("result") or "")
if submitted.get("code") not in (1, 22) or not re.fullmatch(r"[A-Za-z0-9_-]{1,128}", task_id):
    raise RuntimeError(submitted)
print("Save task_id:", task_id, "request_id:", headers.get("x-request-id"), flush=True)

deadline = time.monotonic() + 900
while time.monotonic() < deadline:
    time.sleep(10)
    task, _ = request(f"/mj/task/{task_id}/fetch")
    status = task.get("status", "")
    print(status, task.get("progress"))
    if status == "SUCCESS":
        print(task["imageUrl"])
        break
    if status in ("FAILURE", "CANCEL"):
        raise RuntimeError(task.get("failReason") or status)
else:
    raise TimeoutError(f"Continue querying task {task_id}; do not submit again")

计费与支持范围

当前 1K 标准挂牌价为 $0.10 / 已受理的 Imagine 任务。code=1 或 22 且返回有效任务 ID 即按一个任务收费,不按四宫格中的每张图分别收费;实际金额可能受账号倍率、专属费率或促销影响。

查询任务不会再次扣 Imagine 费。未受理的请求释放预扣;已受理任务后续变为 FAILURE 或 CANCEL,当前不会自动退款。可在账单中按提交响应的 x-request-id 核对这次费用。

当前只开放 Imagine 的 1K 任务,不支持 2K / 4K、Niji、Action(放大、变体、重绘)、批量查询和回调。不要设置 notifyHook,也不要通过 accountFilter.channelId、instanceId 或 modes 指定供应商或模式。

以下 prompt 选项会改变费用或任务数量,当前返回 400:--hd、--q / --quality、--repeat / --r、--fast、--turbo、--relax、--niji,包括 --参数=值 写法。--ar、版本和普通风格参数保留 MJ 语义,由上游校验。

错误处理与重试

情况 处理方式
400 参数错误 检查 prompt、model、botType 和不支持的费用参数。
401 使用当前环境有效的 TeamoRouter API Key。
402 余额或预算不足 检查当前环境余额及账号预算。
404 查询不到任务 确认任务 ID、用户和 7 天保留期;提交响应为 pending 时稍后再查询。
429 限流 降低请求频率;提交请求仍需遵守下方的未知结果处理。
5xx 或连接超时 先判断请求是否可能已提交,不要直接重发 POST。

当错误类型为 midjourney_submission_unknown,或响应头包含 X-Teamo-Submission-State: unknown、X-Should-Retry: false 时,上游可能已创建任务。关闭 HTTP 客户端、SDK 和代理对提交 POST 的自动重试,保留 x-request-id 并联系支持核对;有任务 ID 时继续查询该任务。

当前没有端到端的 Idempotency-Key 去重保证,相同 state 或相同提示词再次 POST 都可能创建并收费一个新任务。查询 GET 可以继续轮询;未知提交结果和等待出图超时都不能作为重新提交的依据。

准备好了?三步即可开始登录控制台 · 购买额度 · 创建 API Key
DiscordGet community help instantly