返回首页

Seedance 视频 API

面向已审核账号的服务端视频生成接口。本文档只描述本站协议,其他 API 平台仅作为结构参考。

1. 接入地址和准备

Base URL:https://example.invalid
请求路径直接从 /v1 开始,不要再额外添加 /api。

登录生成页面,打开“个人信息”,可以为不同程序创建多个 API Key(每个账号最多 10 个)。完整密钥只显示一次;各 Key 可以单独停用或删除,全部共用当前账号的余额、限流、任务记录和幂等范围。

模型H3 / 牛来示例上传图片创建图生视频示例查询与轮询预览与下载错误与计费OpenAPI JSON

2. 通用规则

项目规则
鉴权生成、查询、列表、模型、余额和上传接口使用 Authorization: Bearer sd_live_...,密钥只在服务端保存。唯一公开视频例外是 GET / HEAD /v1/videos/{id}/content:无需 API Key、Cookie 或 token。
请求格式创建视频任务使用 Content-Type: application/json,请求体最大 1 MB。图片上传支持 multipart 或 JSON,使用下方独立的大小限制。
限流每个账号需要鉴权的 /v1/* 请求合计每分钟最多 120 次,超限返回 429 和 Retry-After。
幂等创建视频任务时建议传 Idempotency-Key,8-128 位字母、数字或 ._:-;同一账号同一 Key 必须对应完全相同的请求体。网络超时后保留原 Key 和请求体;收到 409 request_in_progress 才按 Retry-After 自动重试创建。收到 request_state_uncertain 或 retryable:false 时停止自动创建重试,保留追踪编号联系管理员。图片上传不提供幂等,每次成功上传都会生成新链接。
跨域公共 API 返回 Access-Control-Allow-Origin: *,但不要因此把 API Key 放进浏览器代码。
请使用本站的 API Key 和接口字段。生成请求中的参考素材必须是公网 HTTP(S) 地址;本地图片先调用 POST /v1/uploads/images 上传,再使用返回的顶层 url。

3. 接口总览

GET/v1/models读取后台已启用的模型、计费方式、API 单价和允许时长
GET/v1/balance读取当前 API Key 账号余额
POST/v1/uploads/images上传单张参考图片并获取公网链接,不扣生成余额
POST/v1/videos创建视频任务并预扣余额
GET/v1/videos读取当前账号近 24 小时任务历史
GET/v1/videos/{task_id}刷新并读取单个任务状态
GET / HEAD/v1/videos/{task_id}/content公开播放或下载成功视频,无需鉴权

4. 读取模型

curl "https://example.invalid/v1/models" \
  -H "Authorization: Bearer sd_live_你的密钥"

模型只能由管理员手动添加和启用,data 为空时不要自行猜模型标识。提交时必须原样使用 resolutions[].value,它可能是 4kp、4kpp、1080pp 等供应商枚举。

{
  "object": "list",
  "data": [{
    "id": "供应商实际模型标识",
    "object": "video.model",
    "name": "后台显示名称",
    "billingMode": "per_task",
    "billing_mode": "per_task",
    "resolutions": [{"value": "1080pp", "label": "1080P", "price": 2.5}],
    "durations": [5, 10, 15],
    "supports_reference_audio": true,
    "supports_reference_video": false
  }]
}

billingMode 是模型级计费方式;/v1/models 同时返回值相同的 billing_mode。旧模型默认 per_task,兼容旧响应时缺少这两个字段也按 per_task 处理。计费方式由后台模型配置决定,无需在创建请求中传入。

计费方式resolutions[].price 含义实际任务余额
per_task(默认)每次生成的 API 单价单价。例如 2.5 余额 / 次,生成 15 秒仍为 2.5 余额。
per_second每秒生成的 API 单价单价 × 验证后的时长。例如 0.18 余额 / 秒 × 15 秒 = 2.70 余额。

总额四舍五入保留六位小数。时长使用验证后的 parameters.duration;省略时使用该模型最大允许秒数,不按最终视频文件测量时长计费。创建和历史响应中的 amount 是整笔任务的实际余额金额。

4.1 模型请求示例:H3 和牛来pro

模型由后台动态控制。以下 H3 和 niulaipro 请求仅作字段示例;新站点需要管理员先配置上游和模型。第三方接入时必须先调用 /v1/models,以返回的 id、resolutions[].value 和 durations 为准。

模型 ID显示名称当前示例规格参考素材
H3H3768p / 2K;示例时长 15 秒参考图片最多 9 张
niulaipro牛来pro768p 或 2k;4–15 秒图片最多 9 张、视频最多 3 段、音频最多 3 段

以上字段只是示例;管理员调整模型、价格、时长或供应商后,客户端仍应以 /v1/models 的实时结果为准。上游选择由本站后端完成。

牛来pro:纯文本示例

curl -X POST "https://example.invalid/v1/videos" \
  -H "Authorization: Bearer sd_live_你的密钥" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: niulai-20260923-0001" \
  -d '{
    "model": "niulaipro",
    "input": {"prompt": "人物沿海边缓慢行走,镜头电影感跟随"},
    "parameters": {"duration": 8, "ratio": "16:9", "resolution": "768p"}
  }'

H3:纯文本示例

curl -X POST "https://example.invalid/v1/videos" \
  -H "Authorization: Bearer sd_live_你的密钥" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: h3-20260923-0001" \
  -d '{
    "model": "H3",
    "input": {"prompt": "人物自然转身,镜头缓慢推进"},
    "parameters": {"duration": 15, "ratio": "16:9", "resolution": "2K"}
  }'
如果 /v1/models 没有返回某个模型,不能仅凭本示例强行提交;模型被停用、归档、未绑定接口或供应商不可用时,本站会拒绝创建。

5. 上传参考图片

POST/v1/uploads/images

必须携带审核通过账号的有效 Authorization: Bearer sd_live_...。仅有网页登录 Session 不能调用此接口。每次上传一张图片,支持 PNG、JPEG、GIF、WebP、AVIF,格式以实际图片字节识别,不能靠修改文件扩展名转换格式。

方式请求字段限制
推荐:multipart/form-data必填单个文件字段 file;可选文本字段 originalName。不要手动填写 Content-Type,让 curl 或 SDK 自动生成 boundary。图片最大 8 MiB(8388608 字节);整个请求体最大 8 MiB + 64 KiB(8454144 字节)。
application/json必填 dataUrl,格式为完整的 data:image/png;base64,...;可选 originalName。Base64 解码后的图片最大 8 MiB;整个 JSON 请求体最大 12 MiB(12582912 字节)。

上传本地文件

以下命令使用 Bash;先把环境变量 API_KEY 设为自己的密钥。文件路径按实际修改。

curl --fail-with-body "https://example.invalid/v1/uploads/images" \
  -H "Authorization: Bearer ${API_KEY}" \
  -F "file=@./reference.png" \
  -F "originalName=参考.png"

JSON 请求示例

dataUrl 中的省略号必须替换为文件的完整 Base64 内容。上传接口接受 Base64;视频生成接口只接受上传后的 URL。

{
  "dataUrl": "data:image/png;base64,...",
  "originalName": "参考.png"
}

成功响应(HTTP 200)

{
  "id": "img_12345678-1234-1234-1234-123456789012",
  "object": "image.upload",
  "url": "https://example.invalid/api/uploaded-image/uploads/12345678-1234-1234-1234-123456789012.png",
  "filename": "参考.png",
  "mime_type": "image/png",
  "size": 123
}
读取响应顶层 url,填入 input.media[].url。上传不扣生成余额、不创建视频任务,也不调用视频上游;只有后续创建视频任务才按模型 API 价格预扣余额。

返回的素材链接可公开取图,供视频上游抓取,不需要附带 API Key。建议上传后立即提交生成。这里不承诺图片永久保存;任务及生成结果的 24 小时保留规则见后文。多图参考可分别上传,再把多个返回链接加入 input.media。

上传与其他需要鉴权的 /v1/* 请求共用同账号每分钟 120 次限流。重复上传会生成新链接;不要给上传接口添加 Idempotency-Key 来期待去重。

HTTPerror.code含义
400invalid_upload缺少文件、dataUrl 无效,或上传字段不正确。
401invalid_api_key缺少或无效 API Key,或账号尚未审核。
405method_not_allowed此接口仅支持 POST。
413image_too_large图片或请求体超过对应方式的大小上限。
415unsupported_image图片格式或上传 Content-Type 不支持。
429rate_limit_exceeded请求过于频繁,等待 Retry-After 后再试。
503storage_unavailable图片存储暂时不可用,稍后重试。

6. 创建视频任务

字段类型必填说明
modelstring是建议使用 /v1/models 返回的 id。兼容 model_id、modelId、Seedance 2.0 常见缩写 sd2.0,以及可唯一识别的大小写、空格或分隔符差异;响应始终返回正式 ID。
input.promptstring是视频提示词,最多 10000 个字符。
input.mediaarray否每项包含类型和公网 HTTP(S) 地址。本地图片先上传;不要传本地路径、文件对象或 Base64。没有素材时省略或传空数组。
input.media[].typestring媒体项必填reference_image、reference_voice、reference_video。
parameters.resolutionstring建议必须使用模型列表中的 value 原值;省略时使用该模型首个后台规格。
parameters.ratiostring否省略时为 16:9;具体可用比例由上游模型决定。
parameters.durationinteger否必须是模型列表中的允许秒数;省略时使用该模型最大秒数。按秒计费模型使用这个验证后的时长计算总额。

先读取模型,再把实时返回值填入请求。下面的占位符必须替换,不能直接照抄成固定的 1080p。

curl -X POST "https://example.invalid/v1/videos" \
  -H "Authorization: Bearer sd_live_你的密钥" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: video-20260909-0001" \
  -d '{
    "model": "模型列表中的 id",
    "input": {"prompt": "海边日落,电影感运镜"},
    "parameters": {
      "resolution": "模型列表中的 resolutions[0].value",
      "ratio": "16:9",
      "duration": 15
    }
  }'

创建成功后读取任务 ID 和状态。HTTP 200 表示请求已被接受;部分模型可能立即返回 succeeded,请始终以响应中的 status 为准。

创建成功响应中的 id 是本站任务 ID。保存后携带 API Key 使用 GET /v1/videos/{id} 查询;成功后直接打开响应的 video_url 或 url 播放、下载,无需鉴权。409 错误中的 local_task_id 只是请求追踪编号,不代表任务已被受理,不能把它当成成功响应的 id。
{
  "id": "任务ID",
  "object": "video.task",
  "status": "processing",
  "model": "模型标识",
  "resolution": "1080pp",
  "ratio": "16:9",
  "duration": 15,
  "created_at": "2026-09-09T06:00:00.000Z",
  "amount": 2.5
}

7. 本地图片生成视频:完整示例

先查询 /v1/models,将你选定的模型 ID 和分辨率原值放入环境变量 MODEL、RESOLUTION;API_KEY 使用自己的密钥。示例验证这些值后使用该模型最大允许秒数;按秒计费时,预扣金额为 API 单价乘以这个时长。示例不自动猜测或切换模型。

Bash + curl + jq

需要安装 curl 和 jq。设置 IMAGE_PATH 为本地图片路径;为本次视频任务生成一个唯一的 IDEMPOTENCY_KEY,例如应用生成的 UUID。保存 create-request.json 和原 Key;重试只执行最后一条创建命令,不重新上传图片。409 仅 request_in_progress 可按 Retry-After 重试;request_state_uncertain 或 retryable:false 必须停止,保留追踪编号联系管理员。

set -euo pipefail
: "${API_KEY:?请设置 API_KEY}"
: "${MODEL:?请从模型列表选择 MODEL}"
: "${RESOLUTION:?请从模型列表选择 RESOLUTION}"
: "${IDEMPOTENCY_KEY:?请为本次视频任务设置唯一的 IDEMPOTENCY_KEY}"
BASE_URL="https://example.invalid"

curl --fail-with-body "$BASE_URL/v1/models" \
  -H "Authorization: Bearer $API_KEY" -o models.json
DURATION=$(jq -er --arg model "$MODEL" --arg resolution "$RESOLUTION" \
  'first(.data[] | select(.id == $model) | select(any(.resolutions[]; .value == $resolution)) | .durations | max)' models.json)

curl --fail-with-body "$BASE_URL/v1/uploads/images" \
  -H "Authorization: Bearer $API_KEY" \
  -F "file=@${IMAGE_PATH:-./reference.png}" -o upload.json
IMAGE_URL=$(jq -er '.url' upload.json)

jq -n --arg model "$MODEL" --arg resolution "$RESOLUTION" \
  --arg url "$IMAGE_URL" --argjson duration "$DURATION" \
  '{model:$model,input:{prompt:"参考图中的人物自然转身,镜头缓慢推进",media:[{type:"reference_image",url:$url}]},parameters:{resolution:$resolution,ratio:"16:9",duration:$duration}}' \
  > create-request.json

curl --fail-with-body "$BASE_URL/v1/videos" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data-binary @create-request.json

Python requests

安装依赖:pip install requests。环境变量使用同样的 API_KEY、MODEL、RESOLUTION 和可选 IMAGE_PATH。示例在创建前输出并保存请求及幂等 Key;网络异常和短期 request_in_progress 保持原内容重试。确认不确定状态后停止自动重试;保留 create-state.json 与追踪编号,不能换 Key 重新提交。

import json
import os
import time
import uuid
from pathlib import Path
import requests

BASE_URL = "https://example.invalid"
api_key = os.environ["API_KEY"]
session = requests.Session()
session.headers["Authorization"] = f"Bearer {api_key}"

def read_json(response):
    response.raise_for_status()
    return response.json()

state_path = Path(os.environ.get("CREATE_STATE", "create-state.json"))
if state_path.exists():
    saved = json.loads(state_path.read_text(encoding="utf-8"))
    idempotency_key, payload = saved["idempotency_key"], saved["request"]
else:
    model_id, resolution = os.environ["MODEL"], os.environ["RESOLUTION"]
    catalog = read_json(session.get(f"{BASE_URL}/v1/models", timeout=30))
    model = next((item for item in catalog["data"] if item["id"] == model_id), None)
    if model is None:
        raise ValueError("MODEL 不在当前可用模型列表中")
    if resolution not in {item["value"] for item in model["resolutions"]}:
        raise ValueError("RESOLUTION 必须使用该模型 resolutions[].value 原值")
    duration = max(model["durations"])
    image_path = Path(os.environ.get("IMAGE_PATH", "reference.png"))
    if image_path.stat().st_size > 8 * 1024 * 1024:
        raise ValueError("参考图片不能超过 8 MiB")
    # requests 自动生成 multipart Content-Type 和 boundary。
    with image_path.open("rb") as image_file:
        uploaded = read_json(session.post(
            f"{BASE_URL}/v1/uploads/images",
            files={"file": (image_path.name, image_file)},
            data={"originalName": image_path.name},
            timeout=90,
        ))
    payload = {
        "model": model_id,
        "input": {
            "prompt": os.environ.get("PROMPT", "参考图中的人物自然转身,镜头缓慢推进"),
            "media": [{"type": "reference_image", "url": uploaded["url"]}],
        },
        "parameters": {"resolution": resolution, "ratio": "16:9", "duration": duration},
    }
    idempotency_key = str(uuid.uuid4())
    saved = {"idempotency_key": idempotency_key, "request": payload}
    state_path.write_text(json.dumps(saved, ensure_ascii=False), encoding="utf-8")
if saved.get("stop_retry"):
    raise RuntimeError(f"请先联系管理员核对,保留追踪编号:{saved.get('local_task_id', '')}")
if saved.get("id"):
    raise SystemExit(f"已有任务,请直接 GET /v1/videos/{saved['id']}")
print(json.dumps(saved, ensure_ascii=False))
deadline = time.monotonic() + 180
while time.monotonic() < deadline:
    try:
        response = session.post(
            f"{BASE_URL}/v1/videos",
            headers={"Idempotency-Key": idempotency_key},
            json=payload,
            timeout=120,
        )
    except (requests.Timeout, requests.ConnectionError):
        time.sleep(3)
        continue
    task = response.json()
    error = task.get("error")
    code = error.get("code") if isinstance(error, dict) else ""
    if code in {"request_state_uncertain", "idempotency_outcome_unknown"} or task.get("retryable") is False:
        saved.update(stop_retry=True, local_task_id=task.get("local_task_id", ""))
        state_path.write_text(json.dumps(saved, ensure_ascii=False), encoding="utf-8")
        raise RuntimeError(f"停止自动创建重试,请保留追踪编号并联系管理员:{saved['local_task_id']}")
    if response.status_code == 409 and code == "request_in_progress":
        saved["local_task_id"] = task.get("local_task_id", "")
        state_path.write_text(json.dumps(saved, ensure_ascii=False), encoding="utf-8")
        time.sleep(max(1, int(response.headers.get("Retry-After", "3"))))
        continue
    response.raise_for_status()
    if not task.get("id"):
        raise RuntimeError("未返回任务 ID;保留原请求和 Key,联系管理员核对")
    saved["id"] = task["id"]
    state_path.write_text(json.dumps(saved, ensure_ascii=False), encoding="utf-8")
    break
else:
    raise RuntimeError("创建结果仍待确认;保留 create-state.json,不要生成新 Key")
print("本站任务 ID:", task["id"], "状态:", task["status"])
# 后续携带 API Key 用 task["id"] 查询;成功后的 video_url 可直接读取,无需鉴权。

同一任务恢复时保持 CREATE_STATE 文件和 API Key 不变,不会重新上传图片。只有明确要创建另一笔新任务时,才为 CREATE_STATE 指定新的文件名;不要并发运行同一个状态文件。

8. 查询任务和轮询

curl "https://example.invalid/v1/videos/任务ID" \
  -H "Authorization: Bearer sd_live_你的密钥"

状态固定使用 processing、succeeded、failed。建议按 2、4、8、15 秒递增轮询,收到 succeeded 后调用 content 接口;不要高频并发查询。如返回 HTTP 202、code: video_result_pending,表示生成已完成但成片文件仍在准备:保留原任务 ID,按 Retry-After 继续查询,不要重新创建。下面等待最多 30 分钟,超时仍保留任务 ID;等待结束不代表生成失败。把创建成功响应的 id 保存为 SEEDANCE_TASK_ID,可重跑示例继续查询已有任务。

// 服务端 JavaScript 示例,仅查询已创建任务
const base = 'https://example.invalid';
const headers = { Authorization: `Bearer ${process.env.SEEDANCE_API_KEY}` };
const taskId = process.env.SEEDANCE_TASK_ID;
if (!taskId) throw new Error('请设置创建成功响应中的 id:SEEDANCE_TASK_ID');
async function readJson(response) {
  const data = await response.json().catch(() => ({}));
  if (!response.ok) {
    const message = data?.error?.message || data?.error || `HTTP ${response.status}`;
    const error = new Error(message); error.status = response.status; error.retryAfter = response.headers.get('Retry-After'); throw error;
  }
  data.retry_after = Number(response.headers.get('Retry-After') || data.retry_after || 0);
  return data;
}
let task = { id: taskId, status: 'processing' };
const deadline = Date.now() + 30 * 60 * 1000;
let wait = 2000;
while (Date.now() < deadline) {
  if (['succeeded', 'failed'].includes(task.status)) break;
  await new Promise(resolve => setTimeout(resolve, wait));
  try {
    task = await readJson(await fetch(`${base}/v1/videos/${encodeURIComponent(taskId)}`, {
      headers, signal: AbortSignal.timeout(90000)
    }));
  } catch (error) {
    if (![429, 500, 502, 503, 504].includes(error.status)
        && !['TimeoutError', 'AbortError', 'TypeError'].includes(error.name)) throw error;
    wait = Math.max(15000, (Number(error.retryAfter) || 0) * 1000);
    continue;
  }
  wait = task.result_pending ? Math.max(1000, Number(task.retry_after || 20) * 1000) : Math.min(wait * 2, 15000);
}
if (task.status === 'failed') throw new Error(task.error || '视频生成失败');
if (task.status === 'succeeded') {
  // video_url / url 是本站公开内容地址;下载无需 API Key、Cookie 或 token。
  const video = await fetch(task.video_url || task.url, { credentials: 'omit' });
  if (!video.ok) throw new Error(`下载暂不可用,保留任务 ${taskId};HTTP ${video.status}`);
} else {
  console.log(`本轮等待结束,任务仍待确认。保留 ${taskId},稍后继续 GET 查询;不要重新创建。`);
}

9. 读取任务历史

curl "https://example.invalid/v1/videos?limit=20" \
  -H "Authorization: Bearer sd_live_你的密钥"
{
  "object": "list",
  "data": [{
    "id": "任务ID", "object": "video.task", "model": "模型标识",
    "status": "succeeded", "prompt": "海边日落,电影感运镜",
    "resolution": "1080pp", "ratio": "16:9", "duration": 15,
    "video_url": "https://example.invalid/v1/videos/任务ID/content", "amount": 2.5,
    "created_at": "2026-09-09T06:00:00.000Z",
    "completed_at": "2026-09-09T06:08:00.000Z",
    "expires_at": "2026-09-10T06:00:00.000Z"
  }],
  "has_more": false, "next_cursor": ""
}

列表是需要 API Key 的本站 24 小时历史快照。处理中任务需要调用单任务接口刷新;分页时把返回的 next_cursor 作为下一次请求的 cursor。成功且有结果时,video_url 与 url 返回相同的本站绝对内容地址 https://example.invalid/v1/videos/{id}/content;未成功或尚无结果时为空字符串。

10. 预览和下载

curl --fail-with-body "https://example.invalid/v1/videos/任务ID/content?download=1" \
  -o seedance-video.mp4

curl -I "https://example.invalid/v1/videos/任务ID/content"

curl --fail-with-body "https://example.invalid/v1/videos/任务ID/content" \
  -H "Range: bytes=0-1048575" -o first-part.bin

直接使用任务响应中的 video_url 或 url。此精确内容路径支持公开 GET、HEAD 和 HTTP Range(部分内容返回 206),无需 API Key、Cookie 或 token;添加 ?download=1 请求附件下载。返回公开 CORS,浏览器可直接打开或用作播放器地址。

<video controls crossorigin="anonymous" src="https://example.invalid/v1/videos/任务ID/content"></video>

只有成功、尚未过期、未删除且已有结果的任务可读取。如 content 接口返回 409 video_result_pending,不要把 JSON 当作视频;回到单任务接口,按 Retry-After 继续轮询。任务与结果仍按原创建时间保留 24 小时,访问或下载不延长有效期;删除或过期后链接返回 404。公开读取仅适用于上述内容地址,其余生成、查询、列表、余额和上传接口仍需鉴权。

响应含义
200 / 206完整 / 部分视频内容可读取;HEAD 只返回响应头。
409video_result_pending:成片正在准备,按 Retry-After 轮询原任务。
404任务不存在、未成功、无结果、已删除或已过期。
416请求的 Range 无效或超出视频范围。
502视频源暂时不可读取,可稍后重试。

11. 余额、计费和保留时间

curl "https://example.invalid/v1/balance" \
  -H "Authorization: Bearer sd_live_你的密钥"

// 返回示例
{"object":"balance","username":"客户账号","unlimited":false,"credits":12.5}

创建任务时按照模型计费方式和所选分辨率的 API 单价 预扣所属账号余额;API 单价可以与网页前端单价不同。以 GET /v1/models 的 billingMode / billing_mode 和 resolutions[].price 为准:per_task 按每次单价扣费,per_second 按单价乘以验证后的 parameters.duration 扣费,省略时长使用模型最大允许秒数。总额四舍五入到六位小数并记录为任务 amount。

参数错误或上游提交失败时退回本次已预扣金额;已记录任务明确失败 / 取消时按原任务 amount 退回一次,不按后续修改的价格或时长重新计算。图片上传、查询和下载不扣生成余额。管理员账号为无限余额,任务 amount 为 0。任务记录和结果保留 24 小时,过期自动清理;公开内容地址仍遵守相同期限。

12. 错误处理

本站错误优先使用以下结构;上游详细信息可能放在 detail 中,客户端应同时读取 error.code 或字符串 error。

{"ok":false,"error":{"code":"invalid_api_key","message":"API Key 无效、已删除或所属账号尚未通过审核"}}
{"ok":false,"error":"模型或参数不正确","detail":{},"upstreamStatus":400}
状态码处理建议
400检查模型、分辨率、比例、时长、提示词和媒体 URL。
401鉴权接口检查 Bearer Key、账号审核状态,以及该 Key 是否已停用或删除;公开内容读取不需要 Key。
402余额不足;先充值后重试。
403检查调用权限;任务详情用 404 隐藏其他账号的任务,公开内容地址不按访问账号鉴权。
404检查路径、本站任务 ID 或 24 小时有效期;内容接口对未成功、无结果、已删除任务同样返回 404,详情接口也会隐藏不属于当前账号的任务。
409video_result_pending:成片仍在准备,按 Retry-After 查询原任务,不要重新创建。request_in_progress:按 Retry-After 用原 Key、原请求体重试。request_state_uncertain 或 retryable:false:保留 local_task_id 请求追踪编号,停止自动创建重试并联系管理员。其他 409 依错误处理;幂等内容冲突不要换请求体复用 Key。
429等待 Retry-After 后降低请求频率。
502 / 503上游或视频源暂时不可用。查询和下载可稍后重试;创建结果不明时保留原请求、原 Key 和追踪编号,遵守 retryable:false 停止指示,不新建请求编号。
410idempotency_task_expired 或 task_deleted:停止自动创建重试,保留原幂等编号和任务 / 请求追踪编号,联系管理员核对;不要因任务已过期或删除而自动换编号重建。

机器可读描述:/openapi.json。API Key 不要提交到前端、日志、截图或公开仓库。