开放 API

Sora2U 视频生成 API 文档

通过 API 密钥鉴权、按积分扣费,用 REST 接口创建视频生成任务。下方为完整接口与细节指引。

Sora2U 视频生成开放 API

通过本 API,任何 Sora2U 用户都可以用自己的 API 密钥,在自己的程序 / 脚本 / 服务端里调用网站的视频生成能力。每次生成都会从该用户的积分(GP)余额中正常扣费, 计费规则与网页端完全一致。

  • Base URLhttps://sora2u.com
  • 协议:HTTPS,请求/响应均为 JSON(创建任务的参考图用 base64 内联)
  • 鉴权:API 密钥(Authorization: Bearer <key>
  • 风格:任务为异步——创建后先返回任务 ID,再轮询查询结果

机器可读的接口定义见同目录下的 openapi.yaml,可直接导入 Postman / Swagger UI / openapi-generator。


目录

  1. 快速开始(5 分钟跑通)
  2. 获取与管理 API 密钥
  3. 鉴权方式
  4. 生成一条视频
  5. 查询任务状态
  6. 其他接口
  7. 计费与积分扣减
  8. 任务状态机
  9. 错误码
  10. 最佳实践
  11. 完整示例(Node.js / Python)
  12. 给维护者:上线步骤

快速开始(5 分钟跑通)

bash
# 0. 先在网页端登录后创建一把密钥(见下一节),拿到形如 sk_sora_xxx 的明文密钥
export SORA_KEY="sk_sora_你的密钥"

# 1. 查询余额,确认有积分
curl -s https://sora2u.com/api/v1/credits \
  -H "Authorization: Bearer $SORA_KEY"

# 2. 创建一条文生视频任务
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"一只柯基在海边奔跑,电影质感,黄昏光线","model":"seedance-2.0","duration":5}'
# => { "success": true, "task": { "id": "ckxxx", "status": "pending", ... } }

# 3. 用上一步返回的 task.id 轮询结果(每 5 秒一次)
curl -s https://sora2u.com/api/v1/videos/ckxxx \
  -H "Authorization: Bearer $SORA_KEY"
# 当 status = "completed" 时,video_url 即为成片地址

获取与管理 API 密钥

API 密钥与你的账号绑定,代表你本人调用接口并消耗你的积分。请像对待密码一样保管它。

密钥的创建 / 列出 / 吊销使用网页端登录态(Cookie 会话)完成,通常由控制台页面调用:

创建密钥 · POST /api/api-keys

请求体(均可选):

字段类型说明
namestring密钥备注名,便于区分用途,最长 60 字符,默认「默认密钥」
expires_in_daysnumber有效天数(1–3650)。不传则永不过期

响应(201)——明文密钥只在这一次返回,请立刻保存

json
{
  "success": true,
  "api_key": "sk_sora_AbC1d2Ef...完整明文...",
  "key": {
    "id": "ckkey123",
    "name": "我的脚本",
    "key_prefix": "sk_sora_AbC1…",
    "expires_at": null,
    "created_at": "2026-06-17T12:00:00.000Z"
  },
  "warning": "请妥善保存该密钥,它只会显示这一次,无法再次查看。"
}

列出密钥 · GET /api/api-keys

只返回前缀与状态,永不返回明文

json
{
  "success": true,
  "keys": [
    {
      "id": "ckkey123",
      "name": "我的脚本",
      "key_prefix": "sk_sora_AbC1…",
      "status": "active",
      "last_used_at": "2026-06-17T12:30:00.000Z",
      "expires_at": null,
      "revoked_at": null,
      "created_at": "2026-06-17T12:00:00.000Z"
    }
  ]
}

status 取值:active(有效)、expired(已过期)、revoked(已吊销)。

吊销密钥 · DELETE /api/api-keys/{id}

立即失效,操作幂等(重复吊销也返回成功)。一旦泄露,请第一时间吊销并重建。

单账号最多保留 20 把有效密钥,超出需先吊销旧密钥。


鉴权方式

所有 /api/v1/* 接口都需要在请求头携带密钥,支持两种写法(推荐第一种):

http
Authorization: Bearer sk_sora_你的密钥
http
x-api-key: sk_sora_你的密钥

鉴权失败统一返回 401

json
{ "error": { "code": "unauthorized", "message": "缺少或无效的 API 密钥..." } }

服务端只保存密钥的 SHA-256 哈希,不存明文;因此一旦丢失只能重新创建,无法找回。

跨域调用(CORS)

/api/v1/* 已开启 CORS,可从任意网页来源直接在浏览器里调用(OpenAI 兼容客户端的「Base URL + API Key」直连模式):

  • 所有响应都带 Access-Control-Allow-Origin: *
  • 浏览器在带 Authorization 头或用 POST / DELETE 前会先发 OPTIONS 预检,本 API 已正确响应(204 + Access-Control-Allow-*);
  • 鉴权用 Authorization: Bearer / x-api-key(非 Cookie),因此放行任意来源且不需要 credentials

注意:密钥即代表你本人扣费。在纯前端(浏览器)使用时,密钥会暴露给终端用户——仅在可信场景(如用户填自己的密钥)这样用;面向公众的页面请改由你自己的后端代理转发,不要把密钥写进前端代码。


生成一条视频

POST /api/v1/videos

请求体(JSON):

字段类型必填说明
promptstring视频描述,至少 10 个字符。可嵌入 `<
modelstring模型名,默认 seedance-2.0(见 GET /api/v1/models
durationnumber时长(秒)。会按模型支持范围自动取整夹取
aspect_ratiostring画幅,如 9:1616:9(取决于模型支持)
resolutionstring分辨率,如 720p
mute / disable_audioboolean静音生成:为 true 时请求引擎不自动配乐 / 不输出音轨,用于规避 Seedance 2.0 自动 BGM 触发 output_audio_copyright(版权 / 敏感)导致的失败。默认 false
referencestring内联参考素材(图片 / 视频 / 音频)的 base64,可带 data:<mime>;base64, 前缀。受请求体 ~4.5MB 上限约束,适合图片与较小文件。详见下文「参考素材上传」一节
reference_urlstring参考素材的公开 https 直链,服务端下载后转交引擎。较大的视频 / 音频用它(绕过请求体大小限制)。与 reference 同传时两者都会作为参考一并提交(合并计数)
referencesstring[]多参考素材的 base64 数组(可混合图片 / 视频 / 音频:图片最多 9 张,视频与音频合用一个 3 槽池、合计 ≤ 3,总数最多 12 个);每个元素规则同 reference。详见「参考素材上传 · 多参考(叠加)」
reference_urlsstring[]多参考素材的公开 https 直链数组(上限同 references,两者合并计数);每个元素规则同 reference_url。可与 references 混用
image / image_base64stringreference 的向后兼容别名(图片场景)

响应(202 Accepted)——任务已创建并已预扣积分,开始后台生成:

json
{
  "success": true,
  "task": {
    "id": "ckxxx",
    "status": "pending",
    "model": "seedance-2.0",
    "model_name": "Seedance 2.0",
    "mode": "image-to-video",
    "duration": 5,
    "estimated_credits": 100,
    "estimated_time": "2-6分钟",
    "created_at": "2026-06-17T12:00:00.000Z"
  },
  "links": { "self": "/api/v1/videos/ckxxx" }
}

注意:estimated_credits预扣金额,最终以任务完成时的实际成本结算(多退少补,见计费)。

示例(图生视频,兼容 image 字段、裸 base64):

bash
B64=$(base64 -i ./ref.png | tr -d '\n')
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"prompt\":\"让画面里的角色缓缓转头微笑\",\"model\":\"seedance-2.0\",\"image\":\"$B64\"}"

智能模型选择(无参考素材时自动「文生视频」)

视频模型有两种工作形态:图生视频 / 视频生视频 / 音频驱动(需要参考素材)与文生视频(纯文本,无需素材)。你无需关心、也无法单独指定内部的文生视频模型——后端按「有没有参考素材」自动判断:

  • 提供了参考素材reference / reference_url / references / reference_urls 任一)→ 按你选的模型做图生视频 / 视频生视频 / 音频驱动;
  • 没有提供任何参考素材 → 自动切换到同系的「文生视频」形态,直接按 prompt 生成视频。

也就是说,想纯文本生成视频时,只要不传任何参考字段即可modelseedance-2.0 或省略走默认)。计费、时长、画幅都按实际生效的形态结算。GET /api/v1/modelssupports_text_only: true 的模型即代表「无素材也能生成」。

响应里看到的是什么? 无论是否自动回退,响应中的 model / model_name 始终是你选择的可见模型(如 seedance-2.0)——你不会看到任何内部 / 隐藏的回退模型名。响应另带一个 mode 字段标明本次实际形态:text-to-video(没传素材,自动文生视频)、image-to-video(传了图片 / 视频 / 音频参考)或 image-generation(图片模型)。所以「没传素材时返回 text-to-video」是预期行为,并不代表接口不支持上传素材——上传素材时它就是 image-to-videomode 字段在创建响应和任务查询响应里都有。

bash
# 纯文本生成视频:不带任何 reference 字段即可,后端自动走文生视频
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"赛博朋克城市夜景,霓虹灯下的雨夜街道,镜头缓缓推进","model":"seedance-2.0","duration":5}'

模型能力一览

GET /api/v1/models 返回为准;下表为常用模型的参考素材能力速查:

模型(model输出文生图参考视频参考音频参考
seedance-2.0视频
seedance-2.0-character视频
seedance-1.5视频
gemini-image / kontext-image图片
  • 全模态seedance-2.0 / seedance-2.0-character):文 / 图 / 视频 / 音频参考都支持。
  • 仅图seedance-1.5):只支持图片参考;传视频 / 音频参考会在创建时 400 unsupported_reference
  • 图片生成gemini-image / kontext-image):只支持图片参考(最多 4 张),不支持视频 / 音频。

参考素材上传(图片 / 视频 / 音频)

POST /api/v1/videos 支持三类参考素材:图片(图生视频)、视频(视频生视频)、音频(音频驱动)。 有两种把素材交给接口的方式,按文件大小二选一:

方式字段适合上限说明
内联 base64reference图片、较小的短视频 / 音频单次请求体 ~4.5MB(平台硬限制)直接把 base64 放进 JSON。简单,但大文件会触发 413 FUNCTION_PAYLOAD_TOO_LARGE
远程直链reference_url较大的视频 / 音频图片 10MB、视频 100MB、音频 50MB把文件放在公开 https 地址,服务端下载后转交引擎,绕过请求体上限

通用规则:

  • 类型能力由模型决定GET /api/v1/modelssupports_image / supports_video / supports_audio 标明每个模型支持哪些参考类型。seedance-2.0(Seedance 2.0)支持图片 / 视频 / 音频;seedance-1.5(Seedance 1.5)仅支持图片。给不支持该类型的模型传对应参考会在创建时直接返回 400 unsupported_reference(如给 seedance-1.5 传视频 / 音频参考),不会等到渲染阶段才失败。
  • ⚠️ 参考图必须是真实、有内容的图片:请勿用纯色块、占位图或明显合成 / AI 生成的图去「试上限」。这类低信息量图片会触发引擎的低质内容审核而失败(错误码 10001305,文案常写作「社区准则」),这并非真正的内容违规——换成真实照片后同样张数即可通过。用占位图测试会 100% 失败并让你误判上限。
  • 视频参考须宽度 ≥ 300px、时长 < 15 秒(音频同样须 < 15 秒):
    • 宽度 < 300px:对 MP4 / MOV 视频,创建时即预判并返回 400 invalid_referencemessage 形如「参考视频宽度须 ≥ 300px(当前约 200px)」);无法预判的容器(如 WebM)仍由引擎在渲染阶段兜底。
    • 时长超 15 秒:走 reference_url 时在创建请求时同步返回 400 invalid_reference_urlmessage 形如 Video is 18.0s — reference must be under 15s.;走 reference(base64) 时在后台处理阶段判失败,error 给出原因,预扣积分自动退还
  • base64 传视频 / 音频务必用 data URL:裸 base64 没有类型信息会被当成图片。即 reference 要写成 data:video/mp4;base64,...data:audio/mpeg;base64,...
  • referencereference_url 同时提供时,两者都会作为参考一并提交(与 references / reference_urls 合并为一组,按同一套数量上限计数)。
  • 多参考(叠加):用 references(base64 数组)/ reference_urls(直链数组)一次传多份素材,引擎会把它们一并作为参考输入。视频生成(如 seedance-2.0)支持混合参考:图片最多 9 张(可叠加)+ 视频与音频合用一个「3 槽池」(合计 ≤ 3,可任意搭配)+ 总数最多 12 个(例如 9 图 + 3 视频 = 12,或 7 图 + 2 视频 + 1 音频 = 10);图片生成模型仅支持图片参考,最多 4 张。超出返回 400 too_many_references。单复数字段可混用,会合并为一组参考,提交顺序即 reference_urls → references

支持的常见格式:图片 png/jpg/jpeg/webp,视频 mp4/mov/webm,音频 mp3/wav/m4a(以 Content-Type 为准)。

⚠️ 参考素材必踩坑速查

  • 参考图要用真实照片,不要用纯色 / 占位 / 合成图(否则触发低质审核 10001305,误报「社区准则」)。
  • base64 视频 / 音频必须带前缀 data:video/mp4;base64, / data:audio/mpeg;base64,,否则被当图片。
  • 视频参考宽度 ≥ 300px时长 < 15 秒;音频时长 < 15 秒
  • 数量:图片 ≤ 9、视频 + 音频合用一个 3 槽池(合计 ≤ 3),总数 ≤ 12。
  • 202 只代表已受理,不等于成功——必须轮询到 status = completed 且拿到 video_url 才算成;失败读 error / error_code / retryable(见「错误码」)。

A. 图片(base64,最常用)

bash
B64=$(base64 -i ./ref.png | tr -d '\n')
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"prompt\":\"让画面里的角色缓缓转头微笑\",\"model\":\"seedance-2.0\",\"reference\":\"data:image/png;base64,$B64\"}"

B. 视频 / 音频(大文件,用 reference_url,推荐)

bash
# 先把 < 15 秒的参考视频放到任意公开 https 地址(你的 OSS / S3 / CDN 等)
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "prompt": "延续参考视频的运镜,让镜头继续推进",
        "model": "seedance-2.0",
        "reference_url": "https://your-cdn.com/clips/ref-12s.mp4"
      }'
bash
# 音频驱动同理
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"人物跟随这段语音的节奏说话","model":"seedance-2.0","reference_url":"https://your-cdn.com/clips/voice-10s.mp3"}'

C. 视频 / 音频(小文件,内联 base64)

bash
B64=$(base64 -i ./ref.mp4 | tr -d '\n')   # 解码后须 < ~3MB,否则请改用 reference_url
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"prompt\":\"延续参考视频的运镜\",\"model\":\"seedance-2.0\",\"reference\":\"data:video/mp4;base64,$B64\"}"

D. 多张参考图(叠加,最多 9 张)

references(base64 数组)一次传多张图;也可用 reference_urls 传多个直链,或两者混用(图片最多 9 张;还可混入视频 / 音频,视频与音频合用一个 3 槽池、合计 ≤ 3)。

bash
A=$(base64 -i ./char.png | tr -d '\n')      # 角色参考
B=$(base64 -i ./scene.png | tr -d '\n')     # 场景参考
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"prompt\":\"让这个角色出现在这个场景里,自然走动\",\"model\":\"seedance-2.0\",\"references\":[\"data:image/png;base64,$A\",\"data:image/png;base64,$B\"]}"
bash
# 用多个公开直链(适合较大图片),可与 references 混用
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "prompt": "把这两张参考图融合成一个连贯运镜",
        "model": "seedance-2.0",
        "reference_urls": ["https://your-cdn.com/a.jpg", "https://your-cdn.com/b.jpg"]
      }'

reference_url 的下载行为与限制:仅接受 https,会拒绝解析到内网 / 回环地址的域名,且不跟随 301/302/307 等任何跳转——请提供可直接访问、无重定向的直链。单个素材下载超时 120 秒(需容纳最大 100MB 的视频参考)。服务端以 User-Agent: Sora2U-Reference-Fetcher/1.0 发起下载,请勿在源站按 UA 拦截。源站返回 application/octet-stream 或缺失 Content-Type 时会按文件头自动识别类型(识别不出才拒绝)。带 query 参数的临时签名 URL 可用,但请确保有效期覆盖整个生成过程(建议 ≥ 1 小时)——生成引擎可能在渲染阶段再次拉取素材,届时签名过期会导致任务以 reference_download_failed 失败。

逐素材错误归因:下载 / 校验 / 上传失败时返回 400 invalid_reference_url(base64 超限为 413 reference_too_large),错误体附 failed_reference 字段:{ "index": <0 基下标:本接口按同源(url / base64)数组计;火山兼容接口 /v1/contents/generations/tasks 按 content 数组内位置计>, "source": "url" | "base64", "url_host": "<仅源站 host,不回显完整签名 URL>", "http_status": <源站返回的 HTTP 状态码,仅下载失败时>, "reason": <机器可读失败类别,仅下载类失败时:network / timeout / http / invalid_url / unsafe_url / unsupported_type / too_large> },用于定位具体是哪一个素材出了什么问题。

E. 在提示词中精确定位参考素材(<|media:N|> 定位标记)

默认(提示词里不写任何标记)时,引擎会自动安排各参考素材的作用位置——例如音频参考会被自动拼接到句尾生效,多数场景到此即可。

需要把某个素材精确放到句子的某个位置(如"她说完这段音频后转身,背景保持这张图")时,在 prompt 里嵌入定位标记 <|media:N|>

  • N 是该素材在本次提交的参考列表中的 0 基下标——「参考提交顺序 = N」是唯一硬约束。
  • 服务端与引擎对 <|media:N|> 原样透传、不改写;未写标记的素材仍由引擎自动安排位置。
  • 为免混用字段时心算顺序,建议把所有参考放进同一个数组字段(全部用 reference_urls,或全部用 references)——此时 N 就是数组下标。混用时合并顺序为:URL 直链类在前(reference_urlreference_urls)、base64 类在后(referencereferences)。
  • 只有 1 个参考素材时,它就是 <|media:0|>
bash
# 图片(下标0) + 音频(下标1):人物先说出音频内容,画面锚定参考图
curl -s -X POST https://sora2u.com/api/v1/videos \
  -H "Authorization: Bearer $SORA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
        "prompt": "她说 <|media:1|> 然后转身走开,人物与背景保持 <|media:0|> 的样子",
        "model": "seedance-2.0",
        "reference_urls": ["https://your-cdn.com/char.png", "https://your-cdn.com/voice-10s.mp3"]
      }'

查询任务状态

GET /api/v1/videos/{id}

只能查询本人的任务。任务处于 pending/processing 时,本接口会顺带触发一次对账, 拉取最新进度。

json
{
  "success": true,
  "task": {
    "id": "ckxxx",
    "status": "completed",
    "progress": 100,
    "progress_text": "生成完成",
    "prompt": "一只柯基在海边奔跑...",
    "model": "seedance-2.0",
    "mode": "text-to-video",
    "image_url": null,
    "video_url": "https://.../result.mp4",
    "error": null,
    "error_code": null,
    "retryable": null,
    "estimated_credits": 100,
    "reserved_credits": 0,
    "credits_charged": 96,
    "created_at": "2026-06-17T12:00:00.000Z",
    "updated_at": "2026-06-17T12:04:10.000Z",
    "completed_at": "2026-06-17T12:04:10.000Z"
  }
}

失败任务示例(error 为脱敏后的安全文案,配合 error_code / retryable 分支处理,详见「错误码 · 任务失败的错误码」):

json
{
  "success": true,
  "task": {
    "id": "ckxxx",
    "status": "failed",
    "video_url": null,
    "error": "内容审核未通过。此类失败多见于使用纯色 / 合成 / 占位参考图触发的低质检测,请改用真实、有内容的参考图后重试。",
    "error_code": "video_audit_rejected",
    "retryable": true
  }
}
  • 202 ≠ 成功:创建接口返回 202 只代表任务已受理,必须轮询到 status = completedvideo_url 非空才算成功。
  • status = completed → 用 video_url 取成片。
  • status = failed → 读 error(安全文案)/ error_code(稳定错误码)/ retryable(是否值得原样重试);预扣积分已自动退还
  • 所有字段都在 task 下(不是顶层);video_url 已脱敏,不含任何内部会话参数。

video_url 的有效期

  • 正常情况(绝大多数):任务完成时平台会把成片转存到自有对象存储,此时 video_url 形如 https://.../api/files/videos/<id>.mp4?token=...长期有效(token 为对该文件的永久签名,不会过期)。
  • 兜底情况(极少数):转存瞬时失败时,video_url 会暂时回退为 https://.../api/video/<id> 形式的引擎中转地址。该地址依赖上游的临时缓存,通常仅数小时内有效;平台会在完成后 48 小时内自动重试转存,成功后同一任务的 video_url 会更新为持久化地址(旧中转地址也会自动 302 到新地址)。
  • 若中转地址在转存成功前就已过期,访问会返回 410 与错误码 video_expired(对应上游的 Video expired (could not be cached in time)),此时成片已无法取回,只能重新发起生成。
  • 建议:任务完成后尽快(24 小时内)下载成片或转存到你自己的存储,不要把 video_url 当作永久 CDN 直链长期外链使用。

取消任务 · DELETE /api/v1/videos/{id}

pending / processing 可取消,取消后退还预扣积分:

json
{ "success": true, "refunded": true, "message": "任务已取消,积分已退还。" }

其他接口

列出最近任务 · GET /api/v1/videos?limit=20

返回本人最近的任务列表,limit 范围 1–50,默认 20。

json
{ "success": true, "count": 2, "data": [ { "id": "...", "status": "completed", ... } ] }

模型与计费规则 · GET /api/v1/models

响应遵循 OpenAI 兼容的列表外壳:顶层 object: "list" + data 数组,每个模型 object: "model", 其 id公开模型名(用作创建任务时的 model 入参),不含内部引擎 id。另附 default_modelcredit_rule 便于一次取齐上下文。

json
{
  "object": "list",
  "data": [
    {
      "id": "seedance-1.5",
      "object": "model",
      "created": 1735689600,
      "owned_by": "sora2u",
      "name": "Seedance 1.5",
      "pricing_unit": "second",
      "credit_cost_per_second": 10,
      "credit_cost": 10,
      "durations": [5, 8, 10, 12],
      "default_duration": 5,
      "aspect_ratios": ["9:16"],
      "default_aspect_ratio": "9:16",
      "resolutions": ["720p"],
      "default_resolution": "720p",
      "max_prompt_length": 2000,
      "supports_image": true,
      "supports_video": false,
      "supports_audio": false,
      "reference_max_seconds": 15,
      "estimated_time": "2-6分钟"
    },
    {
      "id": "seedance-2.0",
      "object": "model",
      "created": 1735689600,
      "owned_by": "sora2u",
      "name": "Seedance 2.0",
      "credit_cost_per_second": 20,
      "supports_image": true,
      "supports_video": true,
      "supports_audio": true,
      "reference_max_seconds": 15,
      "...": "..."
    }
  ],
  "default_model": "seedance-2.0",
  "credit_rule": {
    "currency": "GP",
    "gp_per_video_second": 10,
    "min_charge_gp": 1,
    "note": "预扣 = credit_cost_per_second × duration;任务完成后按实际成本结算,多退少补。"
  }
}

查询余额 · GET /api/v1/credits

json
{
  "success": true,
  "balance": 1280,
  "currency": "GP",
  "daily_free_video": { "eligible": false, "remaining_today": 0, "note": "..." }
}

计费与积分扣减

视频生成消耗 GP 积分,全流程与网页端一致:

  1. 预扣(创建任务时):按 预扣积分 = 模型每秒积分 × 时长(秒) 原子扣减余额。 余额不足直接返回 402 insufficient_credits,不会创建任务。 并发创建多条任务时扣减是原子的,不会把余额扣成负数。
  2. 结算(任务完成时):按上游引擎的实际成本换算成积分,与预扣做差额—— 实际更贵则补扣,更便宜则退还差额。最终扣费体现在任务的 credits_charged
  3. 退款(任务失败 / 取消时):预扣的积分全额退还

关于每日免费额度:网页端历史付费用户每天有 1 条免费视频额度。 为避免脚本批量调用悄悄吃掉这个名额,开放 API 默认不使用免费额度,始终按积分扣费

充值积分请前往网页端的购买页面(开放 API 不涉及支付)。


任务状态机

text
pending ──▶ processing ──▶ completed
   │             │
   └─────────────┴────────▶ failed        (预扣积分自动退还)
   └──(DELETE)──────────────▶ 取消         (预扣积分自动退还)
状态含义下一步
pending已创建、排队中轮询
processing生成中轮询,可读 progress
completed完成video_url
failed失败error,积分已退

progress 是阶段里程碑,不是线性百分比:5 = 已创建、20 = 上传参考素材、35 = 正在提交生成引擎、55 = 引擎已受理、70 = 渲染中、100 = 完成。70 会一直保持到任务落终态,渲染期间数分钟不变属正常。失败任务的 progress 停在失败发生的阶段:35 ≈ 提交阶段失败、70 ≈ 渲染阶段失败,可据此对失败做分层统计。

⚠️ pending / processing 状态下返回的 video_url 是提交时预写入的代理地址,不是成品、不可下载;判断成功的唯一依据是 status === "completed"failed 状态下 video_url 恒为 null)。


错误码

错误统一为 { "error": { "code", "message", ... } }

HTTPcode说明
400invalid_json请求体不是合法 JSON
400invalid_prompt缺少 prompt 或不足 10 字符
400invalid_model模型名不存在
400invalid_param参数非法(如 duration 非数字)
400invalid_referencereference 不是合法 base64
400invalid_reference_urlreference_url 非法 / 非 https / 指向内网 / 不可下载(含超时、超限)/ 类型不符 / 视频音频超 15 秒。错误体附 failed_reference 归因(index / url_host / http_status / reason)
400unsupported_media参考文件类型不支持(仅 image / video / audio)
400unsupported_reference所选模型不支持该类参考素材(如给 seedance-1.5 传视频 / 音频参考)
400too_many_references参考素材超过数量上限(视频生成:图片最多 9 张、视频 + 音频合用一个 3 槽池合计 ≤ 3、总数最多 12 个;图片生成:最多 4 张图)
401unauthorized密钥缺失 / 无效 / 已吊销 / 已过期
402insufficient_credits余额不足,附 current_balancerequired_credits
404not_found任务不存在或非本人
409invalid_status任务状态变化,无法取消
413reference_too_largebase64 参考超过大小上限(图片 10MB / 视频 100MB / 音频 50MB,平台侧限制);URL 参考超限返回 400 invalid_reference_url,两者均附 failed_reference 归因
500internal_error服务端错误,可重试

上表为创建 / 查询请求同步返回的错误({ "error": { "code", "message" } })。

远程参考素材下载失败时,invalid_reference_url / invalid_reference 可能带上定位字段:

json
{
  "error": {
    "code": "invalid_reference_url",
    "message": "下载 reference_url 失败(HTTP 404)",
    "failed_reference": {
      "index": 1,
      "source": "reference_urls",
      "url_host": "cdn.example.com",
      "http_status": 404,
      "reason": "http"
    }
  }
}

index 为对应字段内的 0 基下标;单个 reference_urlsourcereference_url,多 URL 数组为 reference_urls。火山兼容接口会返回 image_url / video_url / audio_url 作为 source

任务失败的错误码(task.error_code

任务被受理(202)后若在生成阶段失败,GET /api/v1/videos/{id} 会返回 status = "failed",并把失败原因归一化为稳定字段:error(安全文案)、error_code(下表)、retryable(是否值得原样重试)。原始上游错误串已脱敏,不会外泄内部细节。

error_code含义retryable
video_audit_rejected内容审核未通过。多为纯色 / 合成 / 占位参考图触发的低质检测(错误码 10001305「社区准则」),并非真正违规——换真实有内容的参考图后重试✅ 是
input_image_real_person参考图疑似包含真实人物,被模型隐私保护拦截。同图重试仍会被拒——请换非真人 / 卡通 / AI 合成参考图,或改用 seedance-2.0-character(人脸素描匿名)❌ 否
output_audio_copyright生成结果的背景音频疑似触发版权 / 敏感检测(自动配乐常见)。可重试,或在提示词中避免特定音乐✅ 是
reference_download_failed生成引擎拉取参考图 / 视频 / 音频地址失败;请确认链接公网可访问、未过期后重试✅ 是
content_policy提示词或参考素材命中内容策略,需调整后重试❌ 否
too_many_references参考素材数量超过上限,需减少❌ 否
invalid_reference参考素材不合规(视频须宽 ≥ 300px、时长 < 15 秒,须为真实有效文件),需更换❌ 否
reference_download_failed生成引擎渲染阶段无法拉取你提供的参考素材地址。确认链接可公网访问、未过期(签名 URL 建议有效期 ≥ 1 小时)后重试✅ 是
reference_upload_failed参考素材上传到生成引擎失败(平台 ↔ 引擎链路问题),重新提交任务即可✅ 是
engine_retry_exhausted生成引擎内部多次尝试(通常 3 次)仍失败,多为上游临时波动。稍后重试;持续失败请联系平台✅ 是
platform_timeout平台侧任务超时(排队 / 处理长时间无进展),已自动取消并退还预扣积分。可直接重试;频繁出现请联系平台✅ 是
settlement_failed生成已完成,但实际费用高于预估且余额不足以补扣积分。请充值后重新发起❌ 否
task_cancelled任务已被调用方取消,预扣积分已退还;如需继续请重新创建
engine_error其余未归类的引擎处理失败(兜底码)✅ 是

重试建议retryable = true 表示同一请求原样重试有望成功(审核抽检、引擎抖动、自动配乐版权等偶发原因),建议指数退避重试 2–3 次;retryable = false 表示需先修正请求(换真实参考图、减少数量、调整提示词)再试。任务失败的预扣积分已自动全额退还


最佳实践

  • 轮询节奏:建议每 5–10 秒查询一次状态,轮询直至终态(completed / failed / cancelled),时间预算至少 30 分钟——复杂任务可能超过 20 分钟才完成,请勿按固定 10 分钟窗口提前判失败(提前放弃后任务若最终完成仍会正常扣费)。如需放弃,可先尝试 DELETE /api/v1/videos/{id} 取消(当前仅支持排队中 / 尚未提交渲染的任务,成功即退还预扣积分)。GET /api/v1/videos/{id} 会顺带触发对账。
  • 及时取回成片status = completed 后尽快下载 video_url(建议 24 小时内)并转存到你自己的存储;有效期细节见「查询任务状态 · video_url 的有效期」。
  • 先查余额:批量生成前先 GET /api/v1/credits,避免中途 402
  • 密钥安全:只放在服务端环境变量里,绝不写进前端代码 / 仓库 / 日志;按用途分多把密钥,泄露即吊销。
  • 设过期时间:临时脚本用 expires_in_days 创建短期密钥,降低泄露风险。
  • 错误重试:仅对 5xx 做指数退避重试;4xx 属调用方问题,先修参数再试。
  • 限流:积分机制本身限制了滥用(无积分即无法生成)。如需对接高频系统,请联系运营协商配额。

完整示例

Node.js(18+,原生 fetch)

js
const BASE = "https://sora2u.com";
const KEY = process.env.SORA_KEY;
const headers = {
  Authorization: `Bearer ${KEY}`,
  "Content-Type": "application/json",
};

async function generate(prompt) {
  const res = await fetch(`${BASE}/api/v1/videos`, {
    method: "POST",
    headers,
    body: JSON.stringify({ prompt, model: "seedance-2.0", duration: 5 }),
  });
  if (!res.ok) throw new Error(`创建失败: ${JSON.stringify(await res.json())}`);
  const { task } = await res.json();

  // 轮询直到完成
  for (let i = 0; i < 120; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const s = await (
      await fetch(`${BASE}/api/v1/videos/${task.id}`, { headers })
    ).json();
    if (s.task.status === "completed") return s.task.video_url;
    if (s.task.status === "failed") throw new Error(s.task.error);
  }
  throw new Error("超时");
}

generate("一只柯基在海边奔跑,电影质感").then(console.log);

Python(requests)

python
import os, time, requests

BASE = "https://sora2u.com"
H = {"Authorization": f"Bearer {os.environ['SORA_KEY']}"}

def generate(prompt: str) -> str:
    r = requests.post(f"{BASE}/api/v1/videos", headers=H,
                      json={"prompt": prompt, "model": "seedance-2.0", "duration": 5})
    r.raise_for_status()
    task_id = r.json()["task"]["id"]
    for _ in range(120):
        time.sleep(5)
        t = requests.get(f"{BASE}/api/v1/videos/{task_id}", headers=H).json()["task"]
        if t["status"] == "completed":
            return t["video_url"]
        if t["status"] == "failed":
            raise RuntimeError(t["error"])
    raise TimeoutError()

print(generate("一只柯基在海边奔跑,电影质感"))

给 AI 用:MCP 与技能

为方便各类 AI(Claude、Cursor、ChatGPT 等)直接调用本 API,仓库内置了两份现成集成:

  • MCP Servermcp/sora2u-video-mcp/。一个 stdio MCP 服务器,把本 API 暴露成工具:create_video(支持本地图片/视频/音频做参考)、get_videolist_videoscancel_videolist_modelsget_credits。适用于 Claude Desktop、Cursor、Cline 等 MCP 客户端,配置见该目录 README。
  • 技能(Skill)skills/sora2u-video/SKILL.md。给 Claude「技能」/自定义 Agent 用的说明书,内含完整调用流程与参考素材上传指引。
  • OpenAPI:本目录的 openapi.yaml 即机器可读规范,可直接导入 ChatGPT「Actions」/ 自定义 GPT、Apifox、Postman 作为函数/工具定义。

三者都覆盖图片 / 视频 / 音频参考素材的上传细节(base64 与 reference_url 两种方式)。


给维护者:上线步骤

本次新增了 ApiKey 数据表与一组 /api/v1/*/api/api-keys 接口。部署前需:

bash
# 1. 安装依赖并生成 Prisma Client(已包含新的 ApiKey 模型)
npm install
npx prisma generate

# 2. 应用数据库迁移(新增 ApiKey 表)
npx prisma migrate deploy        # 生产
# 或本地:npx prisma migrate dev

# 3. 正常构建启动
npm run build && npm start

涉及代码:

  • 数据模型:prisma/schema.prismaApiKey)+ 迁移 prisma/migrations/20260617120000_add_api_keys
  • 密钥工具:lib/auth/api-key.ts(生成 / 哈希 / 鉴权)
  • 生成服务:lib/ai/video-generation-service.ts(站内与开放 API 共用的扣费链路)
  • 开放接口:app/api/v1/{videos,videos/[id],models,credits}/route.ts
  • 密钥管理:app/api/api-keys/route.tsapp/api/api-keys/[id]/route.ts
  • 响应工具:lib/api/public-api.ts

鉴权所需环境变量与现有视频生成一致(DATABASE_URL、视频引擎相关配置等),开放 API 未引入新的必填环境变量

视频生成 API 文档 | Sora2U | Sora2U — 免费 AI 视频生成平台