{
"error": {
"code": "model_not_found",
"message": "Model is not available to the current key",
"stage": "validation",
"retryable": false
},
"request_id": "req_example"
}
supported_endpoint_types 表示可服务协议的并集;native_endpoint_types 表示当前可达渠道原生能力的交集。某协议只出现在前者时,平台可能进行协议转换,不能承诺每条可达渠道都原生支持。关键功能无法保留时,请求仍会被拒绝。目录中的图片、视频和 3D 模型,请以上文媒体模型的查询结果确认参数和提交地址,不要从这里的端点类型推测平台媒体路径。
下表是人工维护的规格参考,不是 GET /v1/models 的响应,也不表示表内所有型号对你的密钥开放。获取实际可用列表、鉴权方式、完整 curl、JSON 响应与字段说明,见模型列表:通用模型目录与文本模型;该目录也包含图片、视频和 3D 模型,文本模型的筛选方法见只列出文本模型。查询本身不发起生成。
“上下文窗口”和“最大输出”是厂商官方页面公布的数值,写法(k、K、M 或具体 token 数)保持厂商原样,1M 约等于 1024k。同一系列的模型在不同厂商渠道下规格可能不同(例如 DeepSeek V4 在 DeepSeek 官方和火山方舟的模型 ID 与最大思维链均不同),请按模型 ID 对照。
curl -s -X POST "$GATEWAY_ORIGIN/media/v1/tasks/$TASK_ID/cancel" \
-H "Authorization: Bearer $KEY"
成功时返回 HTTP 200 和任务对象,status 为 cancelled;对已取消的任务重复调用也返回 200。任务已开始生成时返回 400 This task cannot be cancelled in its current state;对可灵、MiniMax H3 调用返回 400 This model does not support task cancellation。取消后继续查询任务的 billing,确认费用已释放。
{
"id": "task_example",
"object": "media.task",
"model": "doubao-seedance-2-0-260128",
"type": "video",
"status": "reconciling",
"progress": 0,
"created_at": 1791763200,
"started_at": null,
"finished_at": null,
"artifacts": [],
"error": {"code": "provider_unavailable", "message": "Submission or result is being reconciled; query this task and do not resubmit", "stage": "submission", "retryable": false},
"billing": {"status": "reserved", "currency": "CNY", "amount": null},
"metadata": {"client_ref": "video-1"},
"request_id": "req_example"
}
reconciling 期间费用保持预留,平台确认后任务会转为成功或失败。重新提交会产生一个新的生成任务和新的费用,所以请继续查询原任务;需要人工确认时,把任务 id 和 request_id 提供给平台管理员。
另一种情况:status 为 succeeded,但 artifacts 为空且 error.code 为 provider_unavailable、stage 为 delivery(Generation succeeded but the output is not yet readable)。这表示生成成功但交付未完成,应继续查询原任务,不能静默忽略空数组。稍后查询并不保证文件一定恢复:上游文件过期或丢失时要保留任务 ID 请求平台核对,不要重新生成。
3D 调用方应按 kind=model3d 和 format 筛选所需文件,例如 format=fbx;不要固定选择第一项。format 表示模型格式,container 表示外层包装,filename 用于保存文件,三者不改变下载字节。旧任务重新查询也会返回可识别的格式信息,无需重新生成。客户端仍应检查下载完整性和文件头,发现与元数据不符时保留原任务核对。
提交示例均使用 Authorization: Bearer YOUR_VIRTUAL_KEY 与 Content-Type: application/json。“原生”指与厂商官方 API 相同的请求和响应格式:把官方 Base URL 换成本页 Base URL、官方密钥换成平台虚拟密钥即可调用。平台只开放本文列出的模型、操作和字段,官方的账号管理、回调等功能不在其中。
POST /api/v3/images/generations 直接返回图片结果;启用 stream 时按 SSE 读取结果。本接口不创建供调用方查询的异步任务。
模型
请求中的 model
Seedream 5 Lite
doubao-seedream-5-0-lite-260128
Seedream 5 Pro
doubao-seedream-5-0-pro-260628
Seedream 4.0
doubao-seedream-4-0-250828
Seedream 4.5
doubao-seedream-4-5-251128
Seedream 5 Lite 保留名称
doubao-seedream-5-0-260128
实际可调用项由 GET {{GATEWAY_ORIGIN}}/v1/models 或 GET /api/v3/models 返回的目录决定。自动发现客户端也可使用相对于本页 Base URL 的 GET /models 或 GET /v1/models,均支持尾斜杠,返回同一授权目录而不限于火山渠道模型。这两个别名是平台兼容扩展,不是火山官方列表 API;使用平台虚拟密钥,空目录返回 HTTP 200、data: [],读取不调用上游生成或扣费。生成路径仍为下文的原生路径。
**受理与恢复:**原生提交在发送前持久保存平台任务并冻结资金。发送后断连、超时、5xx、截断成功响应或缺任务 ID 时保持待核对,不自动重复提交或释放资金,且不依赖重试次数设置。错误诊断中的 task_id 和 request_id 可定位同一平台任务;使用原查询路径继续核查。未取得可靠上游 ID 时由管理员按这些标识核对,不通过重新 POST 猜测恢复。原生 Idempotency-Key 尚无跨请求重放保证,每次提交仍是一次独立生成尝试。明确未发送或被上游拒绝时才释放本次预留;生成状态与账务结算状态分别判断。
模型自动发现使用相对路径 GET /models 或 GET /v1/models(均支持尾斜杠),与 GET /api/v3/models 返回相同的授权目录,不限于火山渠道模型。这是平台兼容扩展,不是火山官方列表 API;使用平台虚拟密钥,空目录返回 HTTP 200、data: [],不提交生成任务、预留预算或扣费。SDK 如自行追加 /v1/models,不要在 Base URL 中重复加入 /v1;生成仍使用下表原生任务路径。
import json
from pathlib import Path
from media_client import DeliveryPending, save_file
def download_seedance(result, folder="output"):
content = result.get("content") or {}
if result.get("status") != "succeeded" or not content.get("video_url"):
raise DeliveryPending("尚无可读主视频;保留 ID,继续查询原任务")
saved = []
for field, kind in [("video_url", "video"), ("cover_url", "cover"), ("last_frame_url", "last_frame")]:
if field in content:
saved.append(save_file(content[field], Path(folder) / f"seedance-{kind}"))
return saved
if __name__ == "__main__":
result = json.loads(Path("seedance-task.json").read_text(encoding="utf-8"))
download_seedance(result)
print("文件已保存;客户端播放与账务须分别核对")
生成请求可提供 callback_url,默认使用平台允许访问的 HTTPS 地址。平台根据已经持久化的任务状态向该地址发送 POST,正文沿用单任务查询格式,使用平台任务 ID 和受控错误摘要。
接收端应根据平台事件 ID 去重。通知可能因查询周期或投递重试延迟,不承诺观察到每个中间状态;投递失败不会重新生成或修改已确认账单。通知附带 X-Heighliner-Event-Id、X-Heighliner-Event-Sequence、X-Heighliner-Signature,按任务回调与验签校验,不携带上游账号凭据。
使用平台虚拟密钥鉴权:Authorization: Bearer YOUR_VIRTUAL_KEY 或 x-goog-api-key: YOUR_VIRTUAL_KEY。不要填写 Google 上游账号密钥。本页参考图使用内联 inlineData;请求中的 Base64 不带 Data URI 前缀。
import base64
import hashlib
import json
from pathlib import Path
def sse_events(lines):
data = []
for raw in lines:
line = raw.rstrip("\r\n")
if not line:
if data:
yield json.loads("\n".join(data))
data = []
elif line.startswith("data:"):
value = line[5:]
data.append(value[1:] if value.startswith(" ") else value)
# 注释/心跳等非 data 字段不作为 JSON;不能用 TCP 分块当事件边界。
if data:
raise RuntimeError("SSE 末尾事件不完整;保留原响应,不自动重新生成")
def consume_sse(lines, folder="output"):
folder = Path(folder)
folder.mkdir(parents=True, exist_ok=True)
seen, finished, texts, images = set(), {}, {}, {}
for event in sse_events(lines):
if event.get("error") or (event.get("promptFeedback") or {}).get("blockReason"):
raise RuntimeError("流内错误或安全拦截;保留响应和请求标识核对")
for candidate in event.get("candidates") or []:
index = candidate.get("index", 0)
if not isinstance(index, int) or index < 0:
raise RuntimeError("无效候选编号")
seen.add(index)
for part in (candidate.get("content") or {}).get("parts") or []:
if part.get("thought"):
continue
if "text" in part:
texts.setdefault(index, []).append(part["text"])
blob = part.get("inlineData")
if blob is None:
continue
mime = blob.get("mimeType", "")
if not mime.startswith("image/") or not blob.get("data"):
raise RuntimeError("缺少图片 MIME 或 Base64 数据")
try:
data = base64.b64decode(blob["data"], validate=True)
except (ValueError, TypeError) as error:
raise RuntimeError("图片 Base64 不完整或非法") from error
if not data:
raise RuntimeError("图片字节为空")
identity = (index, hashlib.sha256(data).hexdigest())
if identity in images: # 相同候选的重复快照只保存一次
continue
extension = {"image/png": ".png", "image/jpeg": ".jpg", "image/webp": ".webp"}.get(mime, ".bin")
target = folder / f"candidate-{index}-image-{len(images)}{extension}"
partial = Path(str(target) + ".part")
partial.write_bytes(data)
images[identity] = (partial, target)
if extension == ".bin":
print("图片格式未知,保留原始字节供识别:", partial)
if candidate.get("finishReason"):
finished[index] = candidate["finishReason"]
if not seen or any(finished.get(index) != "STOP" for index in seen) or not images:
raise RuntimeError(f"图片响应未完整成功,结束原因={finished};保留 .part,不自动重新生成")
for partial, target in images.values():
partial.replace(target)
for index, parts in texts.items():
(folder / f"candidate-{index}-text.txt").write_text("".join(parts), encoding="utf-8")
return [target for _, target in images.values()]
if __name__ == "__main__":
with open("gemini.sse", encoding="utf-8") as stream:
saved = consume_sse(stream)
print("图片已保存:", saved, ";客户端预览和账务需分别核对")
官方接口:POST https://generativelanguage.googleapis.com/v1beta/models/{model}:generateContent,平台接口 POST /v1beta/models/{model}:generateContent。Google Gen AI SDK 使用本页 Base URL,即 base_url="{{GATEWAY_ORIGIN}}/gemini"、api_version="v1beta" 和平台虚拟密钥。Authorization: Bearer、x-goog-api-key 或 ?key= 均可鉴权,优先使用请求头。当前可用图片模型以该前缀目录为准。
官方接口:POST https://api.minimax.cn/v2/video_generation,查询 GET https://api.minimax.cn/v2/query/video_generation/{task_id}。平台 Base URL 已包含厂商前缀 /minimax,使用本页 Base URL 加上述相对路径和虚拟密钥,请求与响应保持原生格式。
import os
import time
from pathlib import Path
import requests
from media_client import GATEWAY, HEADERS, DeliveryPending, save_file
def download_native(result, folder="output", saved=None):
saved = {} if saved is None else saved
if result.get("status") != "completed":
raise DeliveryPending("原任务尚未完成")
outputs = []
for index, item in enumerate(result.get("data") or []):
declared = str(item.get("type", "")).lower()
# 类型只用白名单命名;OBJ 的 ZIP 包由 save_file 识别,不改成 .obj。
label = declared if declared in {"obj", "glb", "fbx", "stl", "usdz", "mp4"} else "unknown"
outputs.append((f"hy-{index}-{label}", item.get("url")))
if "preview_image_url" in item:
outputs.append((f"hy-{index}-cover", item["preview_image_url"]))
if result.get("output"):
item = result["output"]
outputs.append(("tripo-model", item.get("model_url")))
for field, kind in [("generated_image_url", "image"), ("rendered_image_url", "cover")]:
if field in item:
outputs.append((f"tripo-{kind}", item[field]))
if not outputs:
raise DeliveryPending("完成但产物为空;继续查询原任务")
for name, url in outputs:
if not url:
raise DeliveryPending("产物地址为空;继续查询原任务")
if name not in saved:
saved[name] = save_file(url, Path(folder) / name)
return list(saved.values())
if __name__ == "__main__":
task_id, model = os.environ["TASK_ID"], os.environ["MODEL"]
deadline, saved = time.monotonic() + 1800, {}
while time.monotonic() < deadline:
try:
response = requests.post(f"{GATEWAY}/tencent/v1/api/3d/query",
json={"model": model, "id": task_id}, headers=HEADERS, timeout=30)
response.raise_for_status()
result = response.json()
if result.get("status") == "failed":
raise RuntimeError("原任务失败;保留 ID 核对结果与账务,不自动重提")
download_native(result, saved=saved)
print("文件已保存;原生结果不提供统一 billing,账务仍须在平台记录中核对")
break
except (DeliveryPending, requests.RequestException) as error:
print("尚未完整取得产物:", type(error).__name__, ";继续查询原任务", task_id)
time.sleep(5)
else:
raise TimeoutError("交付未完成;保留原任务 ID 后续恢复,不重新生成")
每次最多查询 500 个 ID。HTTP 200 的 data 是可见任务数组;不存在、已删除或无当前权限的任务不出现在结果中,全部不可见时为 []。平台先校验消费主体、企业、当前模型和密钥限制,不向调用方暴露共享上游账号列表。
提交时的 options.external_task_id 不会覆盖平台生成的 data.id;响应的 external_id 返回调用方自己的外部 ID。已有受理或任务占用同一外部 ID 时,重复提交返回 HTTP 409;它不提供“重复 POST 自动取回原任务”的幂等契约。只有确认尚未提交、没有任务接管并完成资金和用量回收后,该 ID 才可用于新的请求,例如修正预算不足后重试。已接管、已发送或结果未知的任务保留唯一声明;结果未知时按原平台 ID 或外部 ID 查询,不能更换 ID 自动重新提交。
curl -sS -X POST "$GATEWAY_ORIGIN/midjourney/v1/generations/edits" \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
--data '{
"prompt": "Keep the cup and change the background to pale blue",
"image_urls": ["https://media.example.com/cup.png"],
"speed": "fast"
}'
TASK_ID="替换为已放大成功且可局部重绘的源任务 data.task_id"
curl -sS -X POST "$GATEWAY_ORIGIN/midjourney/v1/generations/modal" \
-H "Authorization: Bearer $KEY" \
-H 'Content-Type: application/json' \
--data "{\"task_id\":\"$TASK_ID\",\"prompt\":\"Replace the selected area with a small blue boat\",\"mask_url\":\"https://media.example.com/mask.png\",\"speed\":\"fast\"}"
基于源任务的操作均接受可选 custom_id,用于已有客户端明确指定自己保存的真实源按钮。它必须与平台保存的按钮完全相同,且与请求动作及方向/缩放等语义匹配;不能根据任务 ID 自行拼接。本页 GET 响应不返回 buttons 或 custom_id,没有原按钮值时使用上述选择字段,不能填写示意字符串来绕过前置条件。
上述每次操作都返回一个新的 data.task_id,不会覆盖源任务。保存新 ID 并执行同一查询流程:
图片 Data URI 的本地白名单为 image/png、image/jpeg、image/webp、image/gif、image/avif,格式为 data:image/png;base64,...。通过语法校验不代表目标模型支持全部格式;新接入建议优先使用 PNG/JPEG。asset://... 不是本入口支持的媒体引用。