视频生成 API 实战:一个端点接入 Veo 3.1
作者:CodeGateway 团队 发布:2026-06-06 | 最后更新:2026-09-26 预计阅读时长:12 分钟
TL;DR:视频生成的麻烦从来不在 prompt,而在接入——每接一家厂商就是一套 Key、一种请求体、一份账单。CodeGateway 把它收成一个端点:POST /v1/video/generate,一套 Bearer Key,靠请求体里的 model 字段决定调用哪个视频模型。一个要先知道的关键点:端点是同步阻塞的,HTTP 连接会保持约两分钟直到视频生成完毕才返回结果,所以把读超时设长、别写轮询。
模型可用性(2026-09-26 更新):视频端点当前支持 google/veo-3.1-fast 一个模型。bytedance/seedance-2.0 与 minimax/hailuo-2.3-fast 已于 2026-09-26 下架、不可调用,下架原因见「模型可用性现状」一节;这两个模型的参数契约作为历史存档保留在文末附录。当前可用的视频模型以模型清单为准。
目录
视频生成模型这两年迭代得很快,但凡真正接过的人都知道:模型好不好用是一回事,接入成本是另一回事。三家厂商意味着三套 API Key、三套鉴权约定、三种请求体格式、三份账单。光是把鉴权和密钥管理跑通,就能耗掉一两天,更别说后面还要在代码里维护三条互不兼容的调用路径。
CodeGateway 的视频生成 API 把这件事压缩成了一个端点:POST /v1/video/generate。同一套 Key、同一个接口、同一套计费口径,只靠请求体里的 model 字段切换底层模型。本文用一篇可复制粘贴的教程,带你跑通文生视频和图生视频,并把当前可用视频模型的参数契约讲清楚。
端点与鉴权
整个视频生成接口只有一个入口:
POST https://api.codegateway.dev/v1/video/generate鉴权走标准的 HTTP Bearer:在请求头里带上你的 API Key 即可。这和 CodeGateway 其他端点用的是同一把 Key,鉴权风格沿用 OpenAI 那套 Authorization: Bearer 习惯,能直接套进你现有的工具链——无论你用的是什么 HTTP 客户端,加一行 header 就行。
Authorization: Bearer <CODEGATEWAY_API_KEY>这里有一个必须先讲清楚的关键行为:这个端点是同步阻塞的。它不是「提交任务拿一个 job id 再去轮询」的异步模式,也没有 webhook 回调。你发起请求后,HTTP 连接会一直保持打开,直到视频真正生成完毕,再把结果直接返回给你。2026-09-19 生产实测:veo-3.1-fast 一条 6 秒成片耗时 83.4 秒(1280×720、13.7 MB)。长阻塞请求容易在传输层被掐断——用 curl 默认的 HTTP/2 时,我们在第 109 秒收到 curl: (16) Error in the HTTP2 framing layer,而且拿不到任何响应体;把 HTTP 版本钉到 1.1(--http1.1)才稳定成功。
这意味着两件事:
客户端必须设置足够长的读超时,建议 180 秒起步。默认 30 秒或 60 秒的超时一定会把请求掐断。
不要写轮询逻辑、不要找 job id、不要等 webhook——这些在这个端点上都不存在。一个请求,等两分钟,拿到成品。
成功时返回 200,响应体结构如下:
{
"created": 1789809317,
"model": "google/veo-3.1-fast",
"serving": "direct-passthrough",
"data": [
{ "url": "https://<object-storage-host>/provider-outputs/<id>.mp4?X-Amz-Expires=86400&X-Amz-Signature=<sig>" }
]
}视频地址在 data[0].url。2026-09-19 实测:返回的是预签名 GET 链接,有效期写在 URL 自身(X-Amz-Expires=86400,即 24 小时);响应体里没有 expires_at 字段(早期版本有过,现已不再返回)。
注意:预签名链接会过期(实测 24 小时),请拿到后尽快把文件下载到自己这边,不要长期热链(hotlink)。
输入有问题时会返回 400,错误信息在 error.message 里,error.type 标明错误类别,例如:
{
"error": {
"message": "prompt is required for google/veo-3.1-fast",
"type": "invalid_request_error"
}
}常见的 400 原因包括缺少必填的 prompt、prompt 超过 2000 字、媒体 URL 不是 https 或指向内部地址,以及请求了一个当前不在支持集里的 model。
快速上手:最小文生视频调用
先跑通一个最简单的文生视频请求。请求体里只放 model 和 prompt 两个字段,其余参数全部走默认值。
下面三段代码做的是同一件事:发起请求、等待生成完成、读取 data[0].url 并把视频保存到本地。请注意每一段都把读超时设到了 180 秒。
curl
curl -X POST https://api.codegateway.dev/v1/video/generate \
-H "Authorization: Bearer $CODEGATEWAY_API_KEY" \
-H "Content-Type: application/json" \
--http1.1 \
--max-time 180 \
-d '{
"model": "google/veo-3.1-fast",
"prompt": "A calico cat stretching slowly on a sunlit wooden windowsill, gentle morning light, cinematic"
}'返回的 JSON 里 data[0].url 就是视频地址,再下载即可:
# 把上一步返回的 url 存到变量后下载
curl -o output.mp4 "$VIDEO_URL"Python(requests)
import os
import requests
API_KEY = os.environ["CODEGATEWAY_API_KEY"]
resp = requests.post(
"https://api.codegateway.dev/v1/video/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "google/veo-3.1-fast",
"prompt": "A calico cat stretching slowly on a sunlit wooden windowsill, gentle morning light, cinematic",
},
timeout=180, # 同步阻塞,留足读超时
)
resp.raise_for_status()
result = resp.json()
video_url = result["data"][0]["url"]
print("video url:", video_url)
# 预签名链接会过期,立即下载
video = requests.get(video_url, timeout=180)
with open("output.mp4", "wb") as f:
f.write(video.content)Node / TypeScript(fetch)
import { writeFile } from "node:fs/promises";
const API_KEY = process.env.CODEGATEWAY_API_KEY!;
// 内置 fetch 默认无读超时,这里用 AbortSignal.timeout 显式设 180s
const resp = await fetch("https://api.codegateway.dev/v1/video/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "google/veo-3.1-fast",
prompt:
"A calico cat stretching slowly on a sunlit wooden windowsill, gentle morning light, cinematic",
}),
signal: AbortSignal.timeout(180_000),
});
if (!resp.ok) {
throw new Error(`request failed: ${resp.status} ${await resp.text()}`);
}
const result = await resp.json();
const videoUrl = result.data[0].url as string;
console.log("video url:", videoUrl);
// 预签名链接会过期,立即下载落盘
const video = await fetch(videoUrl, { signal: AbortSignal.timeout(180_000) });
await writeFile("output.mp4", Buffer.from(await video.arrayBuffer()));三段代码的共同点:请求体最小化、读超时拉长到 180 秒、拿到 data[0].url 后立刻下载。这就是接入视频生成 API 的基本骨架。
模型可用性现状
视频端点的支持集会随上游通道状态调整。截至 2026-09-26,状态如下:
| 状态 | 说明 |
|---|---|---|
| 可用 | 文生视频 + 图生视频,可选生成音频 |
| 已下架(2026-09-26) | 不可调用,参数契约见文末附录 |
| 已下架(2026-09-26) | 不可调用,参数契约见文末附录 |
下架时间与原因:这两个模型自 2026-09-26 起从视频端点与模型清单中移除。直接原因是它们所依赖的上游视频通道预付费额度耗尽,通道无法继续结算,继续把它们留在目录里会让用户看到一个点不通的模型。同一批次还包含 2026-09-26 之前就已下架的几个变体(google/veo-3.1、minimax/hailuo-2.3、bytedance/seedance-2.0-fast、bytedance/seedance-2.0-mini),处理口径一致。
下架后的行为:这两个 model 字段值已经不在端点的支持集内,请求会被端点直接拒绝,返回 400:
{
"error": {
"message": "Unsupported video model: bytedance/seedance-2.0. Supported: google/veo-3.1-fast",
"type": "invalid_request_error"
}
}(2026-09-26 实测,请求体为 {"model": "...", "prompt": "..."} 的最小形式;两个已下架 id 的返回结构一致。)
关于替代能力:Seedance 2.0 原先的优势是控制面更宽(多比例、固定镜头、水印开关、参考图 / 参考视频 / 起止帧、随机种子)。这些控制项目前在视频端点上没有等价替代——google/veo-3.1-fast 的参数集见下一节,请不要把本文附录里的 Seedance 参数当成 Veo 的参数照抄。是否有恢复计划,以模型清单与变更历史的实际状态为准。
模型参数与选型
当前可用的 google/veo-3.1-fast 支持文生视频与图生视频,请求体的通用结构是:
{ "model": "google/veo-3.1-fast", "prompt": "...", "<模型专属字段>": "..." }字段 | 类型 / 取值 | 默认值 | 必填 |
|---|---|---|---|
| 字符串,最长 2000 字 | — | 是 |
|
|
| 否 |
| 字符串 |
| 否 |
|
|
| 否 |
| 布尔 |
| 否 |
| base64 字符串(图生视频) | — | 否 |
要点:duration 是带 s 后缀的字符串,写 "6s" 而不是 6。音频默认关闭,需要才显式开。当前按秒计费、与分辨率无关,网关会把 resolution 统一落到默认档(实测 veo 产物就是 1280×720),传 1080p 不会拿到 1080p。
一个带参数的最小请求体:
{
"model": "google/veo-3.1-fast",
"prompt": "Aerial shot flying over autumn forest at golden hour",
"aspect_ratio": "16:9",
"duration": "8s",
"resolution": "1080p"
}实时可用性(2026-09-19 生产实测):google/veo-3.1-fast 返回 200、耗时 83.4 秒(6 秒成片,1280×720)。
图生视频:用一张图驱动一段视频
给 google/veo-3.1-fast 传 image_input(base64 字符串)即可从一张首帧图生成视频。下面是一个可执行的完整示例:
import base64
import os
import requests
API_KEY = os.environ["CODEGATEWAY_API_KEY"]
with open("first-frame.jpg", "rb") as f:
frame_b64 = base64.b64encode(f.read()).decode()
resp = requests.post(
"https://api.codegateway.dev/v1/video/generate",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "google/veo-3.1-fast",
"prompt": "The camera slowly pushes in as the leaves begin to sway in the wind",
"image_input": frame_b64,
"duration": "6s",
},
timeout=180,
)
resp.raise_for_status()
print(resp.json()["data"][0]["url"])注意:以 URL 形式传入的媒体输入必须是 https,且不能指向内部地址,否则会被 400 拒掉。base64 内联数据不受这条限制。
已下架的两个模型承载图片的字段名与 Veo 不同(Seedance 用 image,Hailuo 用 first_frame_image),但这两个模型自 2026-09-26 起不可调用,字段名仅作为历史存档记在文末附录。
实战注意点
把这几条记住,能避开大多数线上才会暴露的问题。
prompt 上限 2000 字:
prompt有 2000 字上限,超了会直接400。把场景描述写精炼,别堆冗长背景。Veo 的音频默认关闭:
generate_audio默认false,是 opt-in 设计。需要带声音的视频时记得显式设为true,否则拿到的是静音片段。同步超时一定要扛住两分钟:这是最常见的踩坑点。读超时设短了,请求会在视频还没生成完时就被客户端掐断,白白浪费一次生成。统一把读超时设到 180 秒,并在上层加好重试与错误处理。
预签名 URL 会过期:
data[0].url是带有效期的预签名链接(实测 24 小时,期限写在 URL 的X-Amz-Expires上,响应体里没有expires_at字段)。拿到后第一时间下载落盘,不要把这个 URL 直接存进数据库长期当作可访问地址用。媒体输入必须 https 且非内部地址:图生视频传 URL 时,http、localhost、内网地址都会被拒。先把素材放到一个公开可访问的 https 地址上,或者直接内联 base64。
模型 id 要照当前支持集写:写了一个不在支持集里的
model会拿到400 invalid_request_error,错误信息里会列出当前支持的模型。
价格
视频生成按用量计费,无需分别和上游厂商对账。当前费率以官方价格页为准:https://www.codegateway.dev/pricing。
附录:已下架模型的历史参数契约
本附录是历史存档,不是可执行文档。bytedance/seedance-2.0与minimax/hailuo-2.3-fast已于 2026-09-26 下架,当前不可调用(请求会返回400 Unsupported video model)。下面保留它们下架前的参数表与请求体,用途只有一个:让已经写过这两个模型的代码在排障时能对上字段语义。请不要把下面的请求体当成现在能跑通的示例,也不要把参数照抄到 Veo 上。 当前可用模型与字段以本文正文和模型清单为准。
bytedance/seedance-2.0(已下架,不可调用)
下架前的参数契约:
字段 | 类型 / 取值 | 默认值 | 必填 |
|---|---|---|---|
| 字符串,最长 2000 字 | — | 是 |
|
|
| 否 |
| 整数 4–12(秒) |
| 否 |
|
|
| 否 |
| 布尔 |
| 否 |
| 布尔 |
| 否 |
| 固定 24 |
| — |
| 字符串(url 或 base64,图生视频) | — | 否 |
| 字符串 | — | 否 |
| 字符串数组 | — | 否 |
| 字符串 | — | 否 |
| 整数 | — | 否 |
要点(历史语义):duration 是整数(如 8),不是字符串——这一点和 Veo 的 "6s" 差异明显,迁移时容易写错。aspect_ratio 支持的比例档位更多,还能固定镜头、关水印、喂参考图 / 参考视频和起止帧。
下架前的请求体(现已不可执行):
{
"model": "bytedance/seedance-2.0",
"prompt": "A paper boat drifting down a rain-soaked city gutter, reflections of neon signs",
"aspect_ratio": "21:9",
"duration": 8,
"resolution": "1080p",
"camera_fixed": true
}minimax/hailuo-2.3-fast(已下架,不可调用)
下架前的参数契约——注意它只支持图生视频,纯文本请求会被拒:
字段 | 类型 / 取值 | 默认值 | 必填 |
|---|---|---|---|
| 字符串,最长 2000 字 | — | 否 |
| 枚举(示例用 | — | 否 |
|
|
| 否 |
| 字符串(图生视频) | — | 否 |
| 布尔 |
| 否 |
| 布尔 |
| 否 |
要点(历史语义):resolution 写的是大写 P,和另外两个模型的小写 p 不一样。它没有 aspect_ratio 字段。prompt_optimizer 默认开启。它必须传 first_frame_image(图片短边 ≥ 300px),纯文本请求会被 400 拒掉。
下架前的请求体(现已不可执行):
{
"model": "minimax/hailuo-2.3-fast",
"first_frame_image": "https://www.codegateway.dev/api/media/file/codegateway-og-default.jpg",
"prompt": "Slow cinematic push-in, gentle light sweep across the card surface",
"duration": 6,
"resolution": "1080P",
"prompt_optimizer": true
}小结
接入时记住三件事:端点是同步阻塞的,读超时设 180 秒并把 HTTP 版本钉在 1.1;google/veo-3.1-fast 同时支持文生视频与图生视频,duration 是 "6s" 这样的字符串;返回的视频链接会过期(实测 24 小时),拿到尽快下载。2026-09-26 起视频端点只支持这一个模型,另外两个模型的历史参数契约见附录,但已不可调用。
把本文的最小调用骨架复制下来,填上你自己的 Key,就能跑出第一段视频。要开始,先到 CodeGateway 创建 API Key,然后用上面的 curl 命令发出第一个 POST /v1/video/generate 请求。
相关资料
模型清单 —— 当前可用的视频模型与全部模型状态。
计费与充值说明 —— 充值方式、账单口径与余额查看位置。
错误排查指南 —— 按状态码定位 400 / 401 / 403 / 429 / 5xx。
变更历史 —— 模型上下架与定价调整的记录位置。
MDN:AbortSignal.timeout() —— Node / 浏览器里给长阻塞请求设读超时的标准做法。
MDN:fetch() —— 内置 fetch 的超时与 AbortSignal 语义。
