视频生成接口
全部文档视频生成
用接口生成视频。视频生成是异步任务:提交后马上拿到任务 ID,生成通常需要几分钟,之后查询任务取得视频。请求与任务对象沿用火山方舟(Seedance)视频生成接口的字段。
不写代码时,可以在控制台的 视频生成 页提交任务、查看进度、播放与下载视频;用你的 API 密钥提交的任务也列在那里。
准备工作
- API 密钥:在控制台的 API 密钥 页新建,把下文的
sk-...换成你的密钥。 - 接入地址:
https://api.gxcy.com/v1,与 OpenAI 接口相同。 - 模型:控制台的 模型 页中类型为“视频生成”的模型,下文以
MiniMax-H3为例。
接口一览
| 方法与路径 | 用途 |
|---|---|
POST /v1/videos |
提交任务 |
GET /v1/videos/{id} |
查询一个任务 |
GET /v1/videos |
列出任务,或按 ID 批量查询 |
DELETE /v1/videos/{id} |
取消排队中的任务,或删除已结束的任务 |
GET /v1/videos/{id}/content |
下载视频 |
POST /v1/assets |
上传参考图片 |
GET /v1/models/〔模型名称〕 |
查询模型支持的参数 |
请求头带上 Authorization: Bearer <密钥>。任务只有提交它的 API 密钥查得到。
提交任务
curl https://api.gxcy.com/v1/videos \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{
"model": "MiniMax-H3",
"content": [
{"type": "text", "text": "一只橘猫在窗台上伸懒腰,阳光从窗外照进来"}
],
"duration": 5,
"resolution": "720p",
"ratio": "16:9"
}'
返回任务对象,status 为 queued,记下 id 用来查询:
{
"id": "vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F",
"model": "MiniMax-H3",
"status": "queued",
"created_at": 1793091790,
"updated_at": 1793091790,
"usage": null
}
请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
model |
string | 是 | 模型名称 |
content |
array | 是 | 提示词与参考图片,见下文 |
duration |
integer | 否 | 时长(秒);-1 由模型决定 |
resolution |
string | 否 | 分辨率,如 480p、720p、1080p |
ratio |
string | 否 | 画面比例,如 16:9、9:16、1:1;adaptive 跟随首帧图片 |
generate_audio |
boolean | 否 | 是否生成声音 |
seed |
integer | 否 | 随机种子:相同的种子与参数生成相近的画面 |
return_last_frame |
boolean | 否 | 同时返回最后一帧的图片 |
callback_url |
string | 否 | 任务结束时回调的地址,见下文“回调” |
metadata |
object | 否 | 你自己的键值,原样返回;最多 16 个键,值是不超过 512 字的字符串 |
- 除
model与content外,各模型支持的参数与取值不同。模型不支持时返回 400unsupported_parameter,任务不会提交,也不收费。 - 不给的参数用模型的默认值,实际使用的值见任务对象里的同名字段。
- 一个任务只生成一条视频,输出为 MP4。
查询模型支持哪些参数:
curl https://api.gxcy.com/v1/models/MiniMax-H3 \
-H "Authorization: Bearer sk-..."
返回的 video_capabilities 列出可用的分辨率(resolutions)、比例(ratios)、时长范围(duration)与默认值,以及是否支持首帧(first_frame)、尾帧(last_frame)、声音(generate_audio)、随机种子(seed)。没有列出的就是不支持。
提示词与参考图片
content 是一个数组,按顺序放入:
type |
写法 | 说明 |
|---|---|---|
text |
{"type": "text", "text": "…"} |
提示词 |
image_url |
{"type": "image_url", "role": "first_frame", "image_url": {"url": "…"}} |
参考图片;role 为 first_frame(首帧)、last_frame(尾帧)或 reference_image(参考图) |
- 图片地址可以是
https://链接、data URI(data:image/png;base64,…),或上传后的素材 ID(asset_…,见下文“上传参考图片”)。 - 首帧、尾帧各最多一张。能不能同时给首尾帧与参考图、各给几张,由模型决定。
- 整个请求体不超过 64 MB,大图片请上传后用素材 ID 引用。
避免重复提交
提交超时、不知道是否成功时,带同一个 Idempotency-Key 请求头重试即可:24 小时内同一个键、同样的请求只建一个任务,返回已有的任务,不重复计费。同一个键用于不同的请求时返回 409 idempotency_key_reused。
curl https://api.gxcy.com/v1/videos \
-H "Authorization: Bearer sk-..." \
-H "Idempotency-Key: order-1024" \
...
查询结果
curl https://api.gxcy.com/v1/videos/vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F \
-H "Authorization: Bearer sk-..."
status 的取值:
status |
含义 | 已结束 |
|---|---|---|
queued |
排队中 | 否 |
running |
生成中;progress 为 0–100 的进度,没有进度时为 null |
否 |
succeeded |
已完成,可以下载 | 是 |
failed |
失败,原因见 error |
是 |
cancelled |
已取消 | 是 |
expired |
超过 48 小时仍未完成 | 是 |
遇到不认识的 status 时当作还没结束,继续查询。
完成的任务:
{
"id": "vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F",
"model": "MiniMax-H3",
"status": "succeeded",
"content": {
"video_url": "https://api.gxcy.com/v1/videos/vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F/content?expires=1793095390&sig=…"
},
"usage": {"items": {"units.video_seconds.720p": 5}, "source": "reported"},
"duration": 5,
"resolution": "720p",
"ratio": "16:9",
"created_at": 1793091790,
"started_at": 1793091802,
"completed_at": 1793092090,
"expires_at": 1793696590,
"error": null
}
content.video_url是下载链接,自带签名,不需要 API 密钥,可以直接放进<video>标签或交给播放器。链接 1 小时内有效,每次查询任务都会换新,过期后重新查询即可。expires_at之后视频不能再下载,请在此之前保存。- 时间都是 Unix 秒。
- 请求了
return_last_frame时,content.last_frame_url是最后一帧图片的下载链接。
用 Python 提交并等待完成:
import time
import requests
base = "https://api.gxcy.com/v1"
headers = {"Authorization": "Bearer sk-..."}
task = requests.post(f"{base}/videos", headers=headers, json={
"model": "MiniMax-H3",
"content": [{"type": "text", "text": "一只橘猫在窗台上伸懒腰"}],
}).json()
while task["status"] not in ("succeeded", "failed", "cancelled", "expired"):
time.sleep(10)
task = requests.get(f"{base}/videos/{task['id']}", headers=headers).json()
if task["status"] == "succeeded":
video = requests.get(task["content"]["video_url"])
with open("video.mp4", "wb") as f:
f.write(video.content)
else:
print(task["status"], task["error"])
查询间隔建议 10 秒左右;任务多时用回调代替轮询。
列出与批量查询
- 批量查询:
GET /v1/videos?ids=vid_a,vid_b,最多 100 个。返回data按请求的顺序排列,查不到的放在missing。 - 列出:
GET /v1/videos?status=succeeded&limit=20,按提交时间从新到旧。status可以写多个,以逗号分隔;另可以按model、created_after、created_before(Unix 秒)筛选。has_more为true时,带上after=〔这一页最后一个任务的 id〕取下一页。
回调
提交时带上 callback_url,任务结束时平台向这个地址发一次 POST 请求,不必轮询:
{
"id": "evt_01JB8Y…",
"type": "video.succeeded",
"created_at": 1793092091,
"data": {"id": "vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F", "status": "succeeded", "...": "…"}
}
type为video.succeeded、video.failed、video.cancelled或video.expired;data是完整的任务对象。- 地址只能是
https://,不能是内网地址,不跟随重定向。 - 接收方返回 2xx 即为成功;10 秒内没有成功响应时,按 1 分钟、5 分钟、30 分钟、2 小时、6 小时重试。同一个事件可能收到不止一次,请按请求头
webhook-id去重。 - 回调只是通知,任务的状态以查询结果为准。
回调按 Standard Webhooks 签名。签名密钥在控制台的 API 密钥 页查看:在密钥一行的操作菜单中选“回调签名密钥”,每个 API 密钥各有一个,以 whsec_ 开头。校验签名:
import base64
import hashlib
import hmac
def verify(secret: str, headers: dict, body: bytes) -> bool:
key = base64.b64decode(secret.removeprefix("whsec_"))
signed = f"{headers['webhook-id']}.{headers['webhook-timestamp']}.".encode() + body
expected = base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
return any(
hmac.compare_digest(expected, s.split(",", 1)[1])
for s in headers["webhook-signature"].split()
if s.startswith("v1,")
)
body用收到的原始字节,不要先解析再序列化。- 也可以直接用 Standard Webhooks 的官方库(
pip install standardwebhooks等)校验。 - 轮换签名密钥后旧密钥立即失效,之后的回调都用新密钥签名。
上传参考图片
大图片、或者要在多个任务里复用的图片,先上传成素材,再在 content 里用素材 ID 引用:
# 申请上传:给出文件类型与大小(字节)
curl https://api.gxcy.com/v1/assets \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"content_type": "image/png", "size": 482133}'
# 返回 {"id": "asset_…", "status": "pending", "upload_url": "…", "expires_at": …}
# 把文件直接 PUT 到 upload_url,不需要 API 密钥
curl -X PUT "〔upload_url〕" -H "Content-Type: image/png" --data-binary @cat.png
上传后在 content 里写 {"type": "image_url", "role": "first_frame", "image_url": {"url": "asset_…"}}。素材只有上传它的 API 密钥可以引用;GET /v1/assets/{id} 查看状态,DELETE /v1/assets/{id} 删除。平台没有开放上传时这个接口返回 501,请改用图片链接。
取消与删除
DELETE /v1/videos/{id}:
- 排队中的任务:取消,返回任务对象,
status变为cancelled。 - 生成中的任务:大多数模型不能取消,返回 409
cannot_cancel,任务照常生成并计费。 - 已结束的任务:删除,之后查询返回 404,视频一并删除;已经产生的费用不变。
用火山方舟或 MiniMax 的接口接入
已经按火山方舟(Seedance)或 MiniMax 的视频接口写好的程序,只改接入地址与密钥即可,请求与响应仍按原来的格式:
| 接口 | 接入地址 | 路径 |
|---|---|---|
| 火山方舟 | https://api.gxcy.com/byteplus/api/v3 |
提交 POST /contents/generations/tasks;查询、删除 GET、DELETE /contents/generations/tasks/{id};列表 GET /contents/generations/tasks |
| MiniMax | https://api.gxcy.com/minimax |
提交 POST /v2/video_generation;查询 GET /v2/query/video_generation/{task_id} |
model填平台的模型名称。同一个模型可以用上面任意一种接口调用,与/v1/videos的任务互通:任务 ID 都是平台的vid_…,可以用任意一种接口查询。- 视频的下载链接是平台的链接,MiniMax 格式的查询结果中在
task.content.url。 - MiniMax 的分辨率写大写(
768P),水印写aigc_watermark。 - MiniMax 的视频再生成、提示词增强与海螺旧模型的接口暂不支持,返回 501。
- ComfyUI 自带的视频节点也经这两种接口接入。
用火山方舟的 Python SDK:
from volcenginesdkarkruntime import Ark
client = Ark(base_url="https://api.gxcy.com/byteplus/api/v3", api_key="sk-...")
task = client.content_generation.tasks.create(
model="MiniMax-H3",
content=[{"type": "text", "text": "一只橘猫在窗台上伸懒腰"}],
)
print(client.content_generation.tasks.get(task_id=task.id).status)
用 MiniMax 的接口:
curl https://api.gxcy.com/minimax/v2/video_generation \
-H "Authorization: Bearer sk-..." \
-H "Content-Type: application/json" \
-d '{"model": "MiniMax-H3", "content": [{"type": "text", "text": "一只橘猫在窗台上伸懒腰"}], "resolution": "768P", "duration": 5}'
# 返回 {"task_id": "vid_…"}
curl https://api.gxcy.com/minimax/v2/query/video_generation/vid_01JB8Y3N5Q8V7K2M4X6Z9C1D3F \
-H "Authorization: Bearer sk-..."
计费
- 单价见控制台的 模型 页,视频按生成的秒数计价,不同分辨率的单价可能不同。
- 提交本身不计费。任务结束时按任务对象的
usage.items计费,与账单一致;usage.items为空的任务不收费,排队中取消的任务通常不收费。 - 先抵扣订阅与赠送额度,不够的部分从余额扣除。余额或额度不足时提交会被拒绝。
- 用量在控制台的 用量统计 页查看。
错误
出错时返回 {"error": {"code": "…", "message": "…", "param": "…"}},param 是出错的参数名。
| HTTP | code |
说明 |
|---|---|---|
| 400 | invalid_request |
请求体不是合法的 JSON、类型错误或取值超出范围 |
| 400 | unknown_parameter |
出现了未定义的参数 |
| 400 | unsupported_parameter |
这个模型不支持该参数或取值 |
| 400 | content_policy_violation |
提示词或图片未通过审核 |
| 401 | invalid_api_key |
API 密钥无效 |
| 404 | model_not_found、task_not_found、asset_not_found |
模型、任务或素材不存在 |
| 409 | idempotency_key_reused、cannot_cancel、task_not_succeeded |
见上文 |
| 410 | output_expired |
视频已过保留期 |
| 429 | rate_limited |
请求过于频繁,稍后重试 |
| 503 | no_healthy_upstream |
暂时没有可用的模型服务,稍后重试 |
任务失败时 status 为 failed,error.code 说明原因:content_policy_violation(未通过审核)、invalid_input(参考图片无法使用)、generation_failed(生成失败)、upstream_rejected(任务未被受理)。