API 接入文档(v1 · 已实现版)
> 2026-11-04 · 本文与线上实际接口一致,可直接照着写代码。
一、基础
| 项 | 值 |
|---|---|
| Base URL | http://<你的域名>/v1 |
| 鉴权 | Authorization: Bearer sk-live-xxxx |
| 内容类型 | application/json(上传资产支持 multipart) |
| 可选头 | X-Sub-User: 你的客户标识(用量归集用) |
| 可选头 | Idempotency-Key: 任意字符串(24 小时内重放返回同一任务,不重复扣点) |
怎么拿 key:登录网页 → 点「充值」→ 底部「API 接入」→ 新建 key(明文只显示一次)。
二、9 个功能(kind)
| kind | 说明 | 同步 | 参数 |
|---|---|---|---|
script | 写剧本 | ✅ | input.text |
video | 视频提示词 | ✅ | input.text |
storyboard | 分镜提示词 | ✅ | input.text |
drama | 文戏提示词 | ✅ | input.text |
fight | 武戏提示词 | ✅ | input.text |
edit | 改图提示词 | ✅ | input.text、input.asset(必填)、input.model(建议指定) |
wan3_prompt | 全能视频短剧·写提示词 | ✅ | input.text、input.sec、input.resolution |
t2i | 文生图 | ❌ 异步 | input.text |
reverse | 图片反推 | ❌ 异步 | input.asset(必填) |
drama_gen | 短剧生成 | ❌ 异步 | input.text、input.target_sec |
wan3 | 全能视频短剧·出片 | ❌ 异步 | input.prompt、input.prompt_job(必填)、input.sec、input.resolution |
实时单价一律从 GET /v1/caps 读,不要硬编码。
关于 input.model(改图 / 文生图)
两个模型的提示词格式不一样,必须告诉接口你打算用哪个:
| model | 应用 | 图片引用格式 | 说明 |
|---|---|---|---|
模型B | 模型B-Image 2.1 | <image1> <image2> | 尖括号标记(官方规范) |
模型A | 模型A(改图) | 「图1」「图2」 | K2 不认尖括号,写了也无效 |
模型C | 模型C | 「图1」 | 同 模型A 口径 |
模型A(t2i) | 模型A 文生图 | — | 文生图默认就是这个 |
不传 model 就走站内默认;传了但匹配不到应用会返回 400 并列出可用值。
POST /v1/jobs
{ "kind": "edit",
"input": { "text": "把背景换成雪夜街道,人物不动",
"asset": "ast_xxx",
"model": "模型A" } }
返回(模型A 口径,注意是「图1」不是 <image1>):
保持图1中人物的身份、五官、发型、姿势、表情、视线、服装、肢体动作和画面位置完全不变,
只替换人物身后的背景。把原背景整体换成雪夜街道……
三、接口
1. 创建任务
POST /v1/jobs
{
"kind": "script",
"input": { "text": "一个外卖骑手在暴雨里接单,到了地址发现客户是前女友" },
"wait": 45
}
| 字段 | 说明 |
|---|---|
kind | 见上表 |
input | 按 kind 不同 |
wait | 0(默认,立即返回)/ 1~60(最多等这么多秒) |
响应(已完成)
{
"id": "20261104_180521_747680",
"kind": "script",
"status": "done",
"points": 17,
"points_raw": 18,
"created": 1793786721.4,
"elapsed_ms": 40120,
"result": { "text": "【场景1】……" }
}
响应(异步,wait=0)
{
"id": "20261104_180742_0783c6",
"kind": "wan3",
"status": "queued",
"points": 100,
"points_raw": 100,
}
points_raw 是估点数,points 是实际要扣的点数(已经算好,直接按它扣)。
2. 查询任务
GET /v1/jobs/{id}
{
"id": "20261104_180742_0783c6",
"kind": "wan3",
"status": "done",
"points": 100,
"elapsed_ms": 188230,
"result": {
"text": "已出片:1 个文件 · 1 段 · 扣 100 点",
"videos": [
{
"url": "/v1/files/20261104_180742_0783c6/0",
"type": "video",
"name": "20261104_180742_0783c6_seg01.mp4",
"bytes": 1162369
}
]
}
}
status:queued / running / done / failed / canceled
result 结构
- 提示词类:
{"text": "..."} - 出图类:
{"images": [{url,type,name,bytes}]} - 出片类:
{"videos": [{url,type,name,bytes}]}+ 可能带text说明
3. 取消任务
POST /v1/jobs/{id}/cancel
只有 queued 能取消(running 返回 409)。
4. 下载产物
GET /v1/files/{job_id}/{index}?key=sk-live-xxxx
index 就是 result.videos[0] / result.images[0] 里的序号(从 0 开始)。
为什么要 ?key=:<video src> / <img src> 带不了 Authorization 头,所以这个接口额外接受 query 里的 key。
5. 能力清单
GET /v1/caps
{
"kinds": {
"script": { "group": "prompt", "sync": true, "available": true, "points": 18 },
"wan3": {
"group": "video", "sync": false, "available": true,
"sec_range": [2, 30],
"resolutions": {
"480P": { "points_per_sec": 20 },
"720P": { "points_per_sec": 34 },
"1080P": { "points_per_sec": 65 }
},
"require": "prompt_job"
}
},
"is_agent": false,
"balance": 2900,
"user": { "id": 1, "name": "admin" }
}
points / points_per_sec 就是最终要扣的点数,直接按它扣,不用自己再换算。
6. 余额
GET /v1/balance
→ { "points": 2900, "today_used": 0, "day_limit": 0, "is_agent": false }
7. 上传资产
POST /v1/assets
方式 A:JSON base64
{ "data": "data:image/png;base64,iVBORw0...", "name": "参考图", "media": "image" }
方式 B:multipart
curl -X POST http://<域名>/v1/assets \
-H "Authorization: Bearer sk-live-xxxx" \
-F "[email protected]" -F "media=image"
{ "id": "ast_dd0ff6857e", "name": "参考图", "media_type": "image", "bytes": 139982,
"url": "/api/asset-image/ast_dd0ff6857e" }
拿到 id 后,reverse / t2i / wan3 的 input.asset 传它。
8. 用量
GET /v1/usage?from=2026-11-01&to=2026-11-04&group=kind
{
"from": "2026-11-01", "to": "2026-11-04", "group": "kind",
"total_jobs": 8, "total_points": 285,
"groups": [
{ "key": "wan3", "jobs": 2, "points": 200 },
{ "key": "script", "jobs": 1, "points": 18 }
]
}
group 可选 day / kind / sub_user。
9. 流水
GET /v1/ledger?limit=50
{
"items": [
{ "kind": "consume", "points": -100, "job_id": "20261104_180742_0783c6",
"api_kind": "wan3", "status": "done", "created": 1793786862.4 }
],
"limit": 50, "offset": 0
}
kind = consume(消耗)/ refund(失败退回,points 为 0 表示已退回)。
10. 自己管理 key
GET /v1/keys 列 key
POST /v1/keys 新建({"name":"生产"})→ 返回明文一次
DELETE /v1/keys/{kid} 吊销
> 第一个 key 必须在网页上建(「充值」→「API 接入」),之后可以用 API 管理。
四、完整示例:全能视频短剧(两步)
import requests, time
BASE = "http://your-domain/v1"
H = {"Authorization": "Bearer sk-live-xxxx"}
# 第①步:写 视频提示词(这一步扣提示词费)
p = requests.post(f"{BASE}/jobs", headers=H, json={
"kind": "wan3_prompt",
"input": {"text": "一个女孩站在暴雨的街口,抬头看路灯", "sec": 5, "resolution": "480P"},
"wait": 60,
}, timeout=120).json()
print(p["status"], p["points"]) # done 15
prompt = p["result"]["text"]
# 客户可以随便改这段提示词
prompt = prompt.replace("路灯", "钠灯")
# 第②步:出片(必须带 prompt_job,扣出片费)
v = requests.post(f"{BASE}/jobs", headers=H, json={
"kind": "wan3",
"input": {
"prompt": prompt,
"prompt_job": p["id"],
"sec": 5,
"resolution": "480P",
},
"wait": 0,
}).json()
# 轮询
while True:
j = requests.get(f"{BASE}/jobs/{v['id']}", headers=H).json()
if j["status"] in ("done", "failed", "canceled"):
break
time.sleep(5)
print(j["status"], j["points"])
video = j["result"]["videos"][0]
url = f"http://your-domain{video['url']}?key=sk-live-xxxx"
open("out.mp4", "wb").write(requests.get(url).content)
五、限流与错误
| 项 | 默认 |
|---|---|
| QPS | 10 次/秒 |
| 并发任务 | 5 个 |
| 单文件 | ≤ 20MB |
错误结构
{ "detail": { "code": "insufficient_points", "message": "需要 100 点,当前 40 点" } }
| code | HTTP | 含义 |
|---|---|---|
invalid_api_key | 401 | key 无效/吊销 |
account_blocked | 403 | 账号被封 |
insufficient_points | 402 | 点数不足 |
rate_limited | 429 | 超出并发/QPS |
invalid_input | 400 | 参数错误 |
not_ready | 501 | 该 kind 还没开放 |
job_not_found | 404 | 任务/产物不存在 |
job_not_cancelable | 409 | 已开始跑,不能取消 |
六、数据模型
6.1 Job 对象
| 字段 | 类型 | 说明 |
|---|---|---|
id | string | 任务 ID,形如 20261104_180521_747680 |
kind | string | 功能名,见第二节 |
status | string | queued / running / done / failed / canceled |
points | integer | 实扣点数(直接按它扣) |
points_raw | integer | 创建时的估点数,仅创建时返回 |
created | number | 创建时间,Unix 秒(带小数) |
|---|---|---|
elapsed_ms | integer | 从开始执行到结束的毫秒数,未完成时为 null |
result | object | 见 6.2,仅 done 时有 |
error | string | 失败原因,仅 failed 时有 |
6.2 Result 对象
| 字段 | 类型 | 说明 |
|---|---|---|
text | string | 提示词 / 剧本内容。出片类也可能有一句说明 |
videos | array | 视频产物,见 6.3 |
images | array | 图片产物,见 6.3 |
三个字段至少有一个。
6.3 Media 对象
| 字段 | 类型 | 说明 | |
|---|---|---|---|
url | string | 相对路径,如 /v1/files/xxx/0,必须拼域名 + ?key= | |
type | string | video / image | |
name | string | 原始文件名 | |
bytes | integer | 文件大小 | |
sec | number\ | null | 视频时长(秒),图片为 null |
6.4 Kind 枚举
| 值 | 中文 | 分组 | 同步 |
|---|---|---|---|
script | 写剧本 | prompt | ✅ |
video | 视频提示词 | prompt | ✅ |
storyboard | 分镜提示词 | prompt | ✅ |
drama | 文戏提示词 | prompt | ✅ |
fight | 武戏提示词 | prompt | ✅ |
edit | 改图提示词 | prompt | ✅ |
wan3_prompt | 全能视频短剧·写提示词 | prompt | ✅ |
t2i | 文生图 | image | ❌ |
reverse | 图片反推 | image | ❌ |
drama_gen | 短剧生成 | video | ❌ |
wan3 | 全能视频短剧·出片 | video | ❌ |
6.5 错误对象
{ "detail": { "code": "insufficient_points", "message": "需要 100 点,当前 40 点" } }
⚠️ 注意:错误体是 detail 包裹的。你的后端要给前端用,记得先解包
(body.detail.code / body.detail.message)。
七、幂等与重试
7.1 幂等
POST /v1/jobs
Idempotency-Key: <你生成的唯一字符串,建议 UUID>
- 同一 Key 在 24 小时内重复提交 → 返回同一个 job,不重复扣点
- 只对
POST /jobs生效 - 建议在「网络超时 / 连接中断」时用同一个 Key 重试
7.2 什么情况可以重试
| 情况 | 能不能重试 | 怎么做 |
|---|---|---|
| 网络超时、连接被重置 | ✅ | 带同一个 Idempotency-Key 重发 |
| 429 rate_limited | ✅ | 按 Retry-After 退避(没这个头就等 5 秒) |
| 502 upstream_error | ✅ | 等 10 秒重试,最多 3 次 |
| 504 timeout | ✅ | 任务还在跑,转成轮询 GET /jobs/{id} |
| 401 / 402 / 403 / 400 | ❌ | 改配置或充值,重试无用 |
7.3 轮询建议
间隔:5 秒
上限:10 分钟(出片类一般 3~6 分钟能出)
超过上限:判超时,不要再等,去后台看任务状态
不要用 1 秒间隔轮询——会撞 QPS 限流(429)。
八、变更日志
| 日期 | 变更 |
|---|---|
| 2026-11-04 | 首次发布 v1。11 个 kind,6 个接口。新增 wan3 两步流程(prompt_job 校验)、edit 的 model 参数、/v1/files 下载 |
| — | 后续变更按「日期 + 改了什么 + 影不影响调用方」补在这里 |