Wan 视频系列
LoopToken Wan 视频模型的完整异步生成 API 接入说明
Wan 视频生成使用统一的异步任务 API。本文列出的模型名、字段和枚举值均区分大小写。实际可用状态和价格以模型列表为准。
适用模型
| 模型 | 稳定用途 |
|---|---|
wan2.7-t2v | 文生视频,可附加自定义音频 URL |
wan2.7-i2v | 首帧图生视频、首尾帧视频、带音频的首帧生成、视频续写 |
wan2.7-r2v | 参考图片生成、参考视频生成、参考图片附加参考声音 |
wan2.6-t2v | 文生视频;稳定示例使用像素级 size |
模型能力矩阵
“不在稳定兼容范围”表示当前没有足够证据将该能力作为长期可依赖的接口契约。
| 能力 | wan2.7-t2v | wan2.7-i2v | wan2.7-r2v | wan2.6-t2v |
|---|---|---|---|---|
| 文生视频 | 支持 | 不在稳定兼容范围 | 不在稳定兼容范围 | 支持 |
| 首帧 | 不在稳定兼容范围 | first_frame | 不在稳定兼容范围 | 不在稳定兼容范围 |
| 尾帧 | 不在稳定兼容范围 | last_frame,依赖首帧或续写视频 | 不在稳定兼容范围 | 不在稳定兼容范围 |
| 参考图片 | 不在稳定兼容范围 | 不在稳定兼容范围 | reference_image | 不在稳定兼容范围 |
| 参考视频 | 不在稳定兼容范围 | 不在稳定兼容范围 | reference_video | 不在稳定兼容范围 |
| 参考音频 | input.audio_url | driving_audio | reference_voice | 不在稳定兼容范围 |
| 视频续写/编辑 | 不在稳定兼容范围 | first_clip,可加尾帧 | 不在稳定兼容范围 | 不在稳定兼容范围 |
| 自动生成音频 | 不在稳定兼容范围 | 不在稳定兼容范围 | 不在稳定兼容范围 | 不在稳定兼容范围 |
| 分辨率 | 720P、1080P | 720P、1080P | 720P、1080P | 已验证 960*960 |
| 宽高比 | 5 种枚举 | 跟随首帧或续写素材 | 5 种枚举 | 由 size 决定 |
| 时长 | 2-15 秒,默认 5 | 2-15 秒,默认 5 | 无参考视频 2-15 秒;含参考视频 2-10 秒;默认 5 | 已验证 2 秒 |
| 智能时长 | 不支持稳定承诺 | 不支持稳定承诺 | 不支持稳定承诺 | 不支持稳定承诺 |
prompt_extend | 支持,默认 true | 支持,默认 true | 支持,默认 true | 不在稳定兼容范围 |
| 多镜头 | 在 prompt 中描述;不支持 shot_type | 不在稳定兼容范围 | 在 prompt 中描述;不支持 shot_type | 不在稳定兼容范围 |
watermark | 支持,默认 false | 支持,默认 false | 支持,默认 false | 不在稳定兼容范围 |
seed | 0-2147483647 | 0-2147483647 | 0-2147483647 | 不在稳定兼容范围 |
callback_url | 可选 | 可选 | 可选 | 可选 |
| 模型专属字段 | audio_url | media | media、reference_voice | size |
调用流程
- 向
POST https://api.vibelab.me/v1/videos/generations提交 JSON 请求。 - 接口受理后返回 HTTP
202和平台task_id。202只表示任务已创建,不表示所有生成参数已经完成最终校验。 - 每 5-10 秒请求
GET https://api.vibelab.me/v1/tasks/{task_id};连续轮询建议逐步退避,最长不超过 30 秒一次。 pending表示排队中,running表示生成中;继续轮询。succeeded和failed是终态。成功后读取video_url,失败时读取error。video_url是临时地址。必须以响应中的expires_at为准并及时转存,不要假定固定有效时长。
请求头
| Header | 必填 | 值 | 说明 |
|---|---|---|---|
Authorization | 是 | Bearer $LOOPTOKEN_API_KEY | LoopToken API Key;不要写入客户端公开代码 |
Content-Type | 是 | application/json | 请求体必须为 JSON |
无需传递其他 Header。响应中的 X-Request-Id 可用于问题排查,但不是请求必填项。
请求参数
顶层与输入字段
| 字段路径 | 类型 | 必填 | 默认值 | 支持模型 | 枚举/范围与说明 |
|---|---|---|---|---|---|
model | string | 是 | 无 | 全部 | 必须使用上方四个精确模型名之一 |
input | object | 是 | 无 | 全部 | 模型输入对象 |
input.prompt | string | t2v、r2v 是;i2v 否 | 无 | 全部 | 2.7 系列最多 5000 字符;2.6 请保持简洁 |
input.negative_prompt | string | 否 | 无 | 2.7 全部 | t2v、r2v 最多 500 字符;i2v 未承诺具体上限 |
input.audio_url | string | 否 | 无 | wan2.7-t2v | 可由服务端直接下载的公网音频 URL;Base64、格式、大小和时长限制不在稳定兼容范围 |
input.media | array | i2v、r2v 是 | 无 | wan2.7-i2v、wan2.7-r2v | 只使用下文列出的对象和组合 |
callback_url | string | 否 | 无 | 全部 | 公网 HTTPS URL,域名必须可解析;私网、回环和本地地址会被拒绝。回调投递不应替代任务轮询 |
生成参数
| 字段路径 | 类型 | 必填 | 默认值 | 支持模型 | 枚举/范围、依赖与冲突 |
|---|---|---|---|---|---|
parameters.duration | integer | 否 | 2.7 为 5 | 全部 | 2.7 t2v/i2v:2-15;r2v:含参考视频 2-10,否则 2-15;2.6 稳定范围只确认 2。必须传连续整数 |
parameters.resolution | string | 否 | 1080P | 2.7 全部 | 720P、1080P;不得与 2.6 的 size 混用 |
parameters.size | string | 2.6 建议显式传 | 无稳定默认值 | wan2.6-t2v | 宽*高;稳定范围已验证 960*960。不得用于 2.7 |
parameters.ratio | string | 否 | 16:9 | wan2.7-t2v、wan2.7-r2v | 16:9、9:16、1:1、4:3、3:4;i2v 比例由素材决定 |
parameters.prompt_extend | boolean | 否 | true | 2.7 全部 | 是否智能扩写 prompt |
parameters.shot_type | string | 否 | 无 | 无稳定支持模型 | t2v/r2v 2.7 明确不支持;多镜头直接写进 prompt |
parameters.watermark | boolean | 否 | false | 2.7 全部 | 是否添加生成内容水印 |
parameters.seed | integer | 否 | 随机 | 2.7 全部 | 0-2147483647;同一 seed 不保证逐像素一致 |
请求体读取上限为 10 MiB,这不是 URL 所指向素材的文件大小限制。参数越界、未知素材组合或不支持字段可能在提交阶段报错,也可能在任务创建后异步失败。
素材对象
所有 URL 都必须允许服务端直接下载,不得依赖登录态、Cookie、临时页面或局域网。下表中的 Wan 稳定素材对象不使用 role 字段,该字段缺省且不要传递。未列出的 Base64 视频和音频输入不在稳定兼容范围。
| 素材 | 对象字段 | URL/Base64 | 格式、大小、时长与分辨率 | 数量和组合规则 |
|---|---|---|---|---|
| 首帧图片 | type: "first_frame"、url | 公网 URL;图片 data URI | MIME 必须与实际图片一致;具体格式、大小和像素上下限不作稳定承诺 | i2v;采用首帧、首帧加尾帧、首帧加参考音频等下列最小组合;其他数量不在稳定兼容范围 |
| 尾帧图片 | type: "last_frame"、url | 公网 URL;图片 data URI | 同首帧 | 不能单独使用;用于 first_frame + last_frame [+ driving_audio] 或 first_clip + last_frame |
| 普通参考图片 | type: "reference_image"、url,可选 reference_voice | 图片支持公网 URL/data URI;声音仅 URL | 具体格式、大小和像素限制不作稳定承诺 | 仅 r2v;与参考视频可混合。图片按出现顺序分别编号为“图1”“图2” |
| 参考视频 | type: "reference_video"、url | 仅承诺公网 URL | Base64、具体 MIME、格式、大小、素材时长和分辨率不作稳定承诺 | 仅 r2v;视频按出现顺序分别编号为“视频1”“视频2”;存在任一视频时输出最长 10 秒 |
| 参考音频 | type: "driving_audio"、url | 仅承诺公网 URL | Base64、格式、大小、时长不作稳定承诺 | 仅 i2v;采用 first_frame + driving_audio 或 first_frame + last_frame + driving_audio 的最小组合,其他数量不在稳定兼容范围 |
| 视频续写素材 | type: "first_clip"、url | 仅承诺公网 URL | Base64、格式、大小、时长和分辨率不作稳定承诺 | 仅 i2v;采用单独续写或 first_clip + last_frame 的最小组合,其他数量不在稳定兼容范围 |
| 参考声音 | reference_image.reference_voice | 仅承诺公网 URL | Base64、格式、大小、时长不作稳定承诺 | 仅作为 r2v 的 reference_image 对象字段使用 |
未给出稳定上限的素材类型,不应通过批量堆叠试探数量。生产请求应使用完成目标所需的最少素材,并仅采用表中组合。
尺寸、比例和时长
wan2.7-t2v 与 wan2.7-r2v
| 分辨率 | 16:9 | 9:16 | 1:1 | 4:3 | 3:4 |
|---|---|---|---|---|---|
| 720P | 1280x720 | 720x1280 | 960x960 | 1088x832 | 832x1088 |
| 1080P(默认) | 1920x1080 | 1080x1920 | 1440x1440 | 1648x1248 | 1248x1648 |
wan2.7-t2v 支持 2-15 秒连续整数。wan2.7-r2v 不含参考视频时支持 2-15 秒,含参考视频时支持 2-10 秒。两者默认都是 5 秒、16:9,不支持将“智能时长”作为稳定参数。
wan2.7-i2v
支持 720P 和 1080P(默认),时长为 2-15 秒连续整数,默认 5 秒。输出比例由首帧或续写素材确定,不传 ratio;具体像素随素材比例确定。
wan2.6-t2v
稳定验证范围为 parameters.size: "960*960" 和 duration: 2,对应 720p、1:1。其他像素枚举、默认尺寸、完整时长范围和智能时长不在稳定兼容范围,生产请求建议显式传入上述值。
参数优先级
| 模型 | 尺寸确定规则 |
|---|---|
wan2.7-t2v、wan2.7-r2v | resolution 选择档位,ratio 选择比例;两者共同确定像素 |
wan2.7-i2v | resolution 选择档位,比例由首帧或续写素材决定 |
wan2.6-t2v | size 同时确定像素、档位和比例 |
完整请求示例
各稳定模式的 JSON 请求体
纯文生视频:
{
"model": "wan2.7-t2v",
"input": { "prompt": "清晨的湖面泛起微波,固定镜头,写实光线" },
"parameters": { "resolution": "720P", "ratio": "1:1", "duration": 2 }
}文生视频并附加自定义音频:
{
"model": "wan2.7-t2v",
"input": {
"prompt": "清晨的湖面泛起微波,画面节奏与音乐自然同步",
"audio_url": "https://www.w3schools.com/html/horse.mp3"
},
"parameters": { "resolution": "720P", "ratio": "16:9", "duration": 5 }
}2.6 文生视频:
{
"model": "wan2.6-t2v",
"input": { "prompt": "极简静态场景,固定镜头" },
"parameters": { "size": "960*960", "duration": 2 }
}首帧与 Base64 图片:
{
"model": "wan2.7-i2v",
"input": {
"prompt": "人物缓慢转身,镜头平稳推进",
"media": [
{ "type": "first_frame", "url": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQ..." }
]
},
"parameters": { "resolution": "720P", "duration": 5 }
}首尾帧生成:
{
"model": "wan2.7-i2v",
"input": {
"prompt": "人物缓慢转身,最终停在目标画面",
"media": [
{ "type": "first_frame", "url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80" },
{ "type": "last_frame", "url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80" }
]
},
"parameters": { "resolution": "720P", "duration": 5 }
}带音频的首帧生成:
{
"model": "wan2.7-i2v",
"input": {
"prompt": "人物按照音频自然说话",
"media": [
{ "type": "first_frame", "url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80" },
{ "type": "driving_audio", "url": "https://www.w3schools.com/html/horse.mp3" }
]
},
"parameters": { "resolution": "720P", "duration": 5 }
}视频续写并指定尾帧:
{
"model": "wan2.7-i2v",
"input": {
"prompt": "延续原有运镜,最终停在目标画面",
"media": [
{ "type": "first_clip", "url": "https://www.w3schools.com/html/mov_bbb.mp4" },
{ "type": "last_frame", "url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80" }
]
},
"parameters": { "resolution": "720P", "duration": 5 }
}参考图片并附加参考声音:
{
"model": "wan2.7-r2v",
"input": {
"prompt": "图1中的人物在舞台中央自然演讲",
"media": [
{
"type": "reference_image",
"url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80",
"reference_voice": "https://www.w3schools.com/html/horse.mp3"
}
]
},
"parameters": { "resolution": "720P", "ratio": "16:9", "duration": 5 }
}仅参考视频:
{
"model": "wan2.7-r2v",
"input": {
"prompt": "延续视频1中的人物动作与镜头节奏",
"media": [
{ "type": "reference_video", "url": "https://www.w3schools.com/html/mov_bbb.mp4" }
]
},
"parameters": { "resolution": "720P", "ratio": "16:9", "duration": 5 }
}参考视频与参考图片混合:
{
"model": "wan2.7-r2v",
"input": {
"prompt": "视频1中的人物拿起图1中的道具,保持原有动作风格",
"media": [
{ "type": "reference_video", "url": "https://www.w3schools.com/html/mov_bbb.mp4" },
{ "type": "reference_image", "url": "https://images.unsplash.com/photo-1518717758536-85ae29035b6d?auto=format&fit=crop&w=1024&q=80" }
]
},
"parameters": { "resolution": "720P", "ratio": "16:9", "duration": 5 }
}cURL:提交并查询
TASK_ID=$(curl -sS https://api.vibelab.me/v1/videos/generations \
-H "Authorization: Bearer $LOOPTOKEN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "wan2.7-t2v",
"input": {"prompt": "清晨的湖面泛起微波,固定镜头"},
"parameters": {"resolution": "720P", "ratio": "1:1", "duration": 2}
}' | jq -r '.task_id')
curl -sS "https://api.vibelab.me/v1/tasks/$TASK_ID" \
-H "Authorization: Bearer $LOOPTOKEN_API_KEY"Python:提交并轮询
import os
import time
import requests
base_url = "https://api.vibelab.me"
headers = {
"Authorization": f"Bearer {os.environ['LOOPTOKEN_API_KEY']}",
"Content-Type": "application/json",
}
body = {
"model": "wan2.7-t2v",
"input": {"prompt": "清晨的湖面泛起微波,固定镜头"},
"parameters": {"resolution": "720P", "ratio": "1:1", "duration": 2},
}
response = requests.post(f"{base_url}/v1/videos/generations", headers=headers, json=body)
response.raise_for_status()
task_id = response.json()["task_id"]
while True:
task = requests.get(f"{base_url}/v1/tasks/{task_id}", headers=headers)
task.raise_for_status()
result = task.json()
if result["status"] in {"succeeded", "failed"}:
print(result)
break
time.sleep(8)Node.js:提交并轮询
const baseUrl = 'https://api.vibelab.me';
const headers = {
Authorization: `Bearer ${process.env.LOOPTOKEN_API_KEY}`,
'Content-Type': 'application/json',
};
const submitted = await fetch(`${baseUrl}/v1/videos/generations`, {
method: 'POST',
headers,
body: JSON.stringify({
model: 'wan2.7-t2v',
input: { prompt: '清晨的湖面泛起微波,固定镜头' },
parameters: { resolution: '720P', ratio: '1:1', duration: 2 },
}),
});
if (!submitted.ok) throw new Error(await submitted.text());
const { task_id: taskId } = await submitted.json();
while (true) {
const response = await fetch(`${baseUrl}/v1/tasks/${taskId}`, { headers });
if (!response.ok) throw new Error(await response.text());
const task = await response.json();
if (task.status === 'succeeded' || task.status === 'failed') {
console.log(task);
break;
}
await new Promise((resolve) => setTimeout(resolve, 8000));
}提交响应
成功提交固定返回 HTTP 202,对象正好包含以下六个字段:
| 字段 | 类型 | 说明 |
|---|---|---|
task_id | string | LoopToken 任务 ID;后续查询使用此值 |
model | string | 请求使用的公开模型名 |
status | string | 提交时为 pending |
created_at | integer | Unix 秒时间戳 |
duration | integer | 提交阶段用于任务估算的时长 |
resolution | string | 提交阶段识别的计费档位,如 720p |
{
"task_id": "vt_example123",
"model": "wan2.7-t2v",
"status": "pending",
"created_at": 1783828800,
"duration": 2,
"resolution": "720p"
}任务查询
字段说明
| 字段 | 类型 | 出现条件 | 说明 |
|---|---|---|---|
task_id | string | 始终 | 平台任务 ID |
model | string | 始终 | 公开模型名 |
status | string | 始终 | pending、running、succeeded、failed |
created_at | integer | 始终 | Unix 秒 |
completed_at | integer | 终态且有完成时间 | Unix 秒 |
duration | integer | 始终 | 终态可能由实际 usage 更新 |
resolution | string | 始终 | 720p 或 1080p;终态可能由实际 usage 更新 |
ratio | string | 终态 usage 提供时 | 实际输出比例 |
usage | object | 终态有统计时 | 仅可能包含 duration、SR、ratio |
credits_charged | number | 完成结算后 | 本任务最终实际扣除的 credits |
video_url | string | 成功且 URL 有效 | 临时视频下载地址 |
expires_at | integer | 有 video_url 时 | URL 失效的 Unix 秒时间戳 |
error.code | string | 失败 | upstream_error 或 timeout |
error.message | string | 失败 | 当前稳定消息为 video generation failed |
排队中:
{
"task_id": "vt_example123",
"model": "wan2.7-t2v",
"status": "pending",
"created_at": 1783828800,
"duration": 2,
"resolution": "720p"
}处理中:
{
"task_id": "vt_example123",
"model": "wan2.7-t2v",
"status": "running",
"created_at": 1783828800,
"duration": 2,
"resolution": "720p"
}成功:
{
"task_id": "vt_example123",
"model": "wan2.7-t2v",
"status": "succeeded",
"created_at": 1783828800,
"completed_at": 1783828920,
"duration": 2,
"resolution": "720p",
"ratio": "1:1",
"usage": { "duration": 2, "SR": 720, "ratio": "1:1" },
"credits_charged": 12,
"video_url": "https://example.com/generated/video.mp4?signature=replace-me",
"expires_at": 1784088120
}失败:
{
"task_id": "vt_example123",
"model": "wan2.7-t2v",
"status": "failed",
"created_at": 1783828800,
"completed_at": 1783828860,
"duration": 2,
"resolution": "720p",
"error": {
"code": "upstream_error",
"message": "video generation failed"
}
}错误处理
即时错误通常使用 { "error": { "code": "...", "message": "..." } }。生成参数和素材问题不保证在提交阶段发现,也可能表现为异步 failed。
| HTTP/结果 | error.code | 触发条件 | 处理建议 |
|---|---|---|---|
| 400 | invalid_request_error | JSON、字段类型或 callback_url 地址非法 | 修正 JSON;回调使用可解析的公网 HTTPS 地址 |
| 402 | insufficient_credits | 余额不足以预扣 | 充值,或降低时长/分辨率后重试 |
| 404 | model_not_found | 模型名不存在或不可用 | 从模型列表复制精确名称 |
| 404 | task_not_found | 任务不存在,或任务不属于当前 API Key 账户 | 检查 task_id 和鉴权账户 |
| 503 | 以响应为准(不作为稳定兼容字段) | 模型暂不可用 | 按可重试服务错误处理,指数退避后重试;不要高频重复提交 |
| 502 | upstream_error | 提交生成任务失败 | 保留请求 ID,退避后有限次数重试 |
202 后 failed | upstream_error | 请求参数不被模型接受、素材 URL 无法访问、素材格式/数量/组合错误、不支持的模型参数或生成失败 | 对照本页矩阵检查模型、字段、URL 可访问性和素材组合;修正后新建任务 |
202 后 failed | timeout | 生成任务超时 | 稍后新建任务;持续发生时联系支持并提供 task_id |
素材 URL、格式、数量和参数名目前没有稳定的一对一细分公开错误码。不要依赖具体失败文案编写业务逻辑,应按 HTTP 状态、error.code 和任务状态分支处理。
计费
- Wan 视频按实际生成时长和 720p/1080p 分辨率档位计费,分辨率越高、时长越长,费用越高。
- 提交时按可解析的请求参数预估并预扣;生成完成后按实际
usage.duration和usage.SR重新结算,多退少补。 credits_charged是完成结算后该任务最终实际扣除的 credits,业务账单应以此字段为准。- 同步提交失败会释放预扣;异步生成失败会退款,失败任务不最终收取生成费用。
- 单价可能调整,不在本文固化,始终以模型列表展示的当前价格为准。
信息安全
- API Key 只保存在服务端环境变量或密钥管理服务中,不要提交到代码仓库、日志或前端页面。
- 不要向终端用户暴露任务调试信息;对外只传递业务所需的状态和结果。
- 素材 URL 应使用最小权限、短期有效的下载地址,并避免在查询参数中放置长期密钥。
- 示例中的公开图片、视频和音频仅用于展示请求形状。生产接入必须替换为你有权处理、允许服务端直接下载的自有素材;
vt_example123、生成结果地址和截断 Base64 均为占位内容。 - 视频生成成功后按
expires_at及时转存,并按照业务的数据保留策略删除不再需要的素材和结果。