The short version
约 10 分钟写完 REST 接入,再把渲染当作需要持久状态的异步任务处理。
这篇教程把一个公开 URL 提交为 30 秒、16:9 的动态图形任务。上传、创建、查询和下载四个接口可以很快接好,但渲染并不保证 10 分钟完成。受控实测明显更久,所以最终代码会保存任务 ID,并处理临时网络错误。
Review TapVid API and MCP access
01
这篇教程里的 Text-to-Video API 是什么
Text to video 可能指 prompt 短片、图片动画、数字人或素材拼接。TapVid 把现有内容变成多场景、结构化的信息视频。公开页面和 brief 提供事实、受众、时长和禁止项。需要修改时,可以只重新生成一个场景并保留其余内容。
“10 分钟”指接好四个 REST 操作,不是承诺 10 分钟渲染完成。Create 返回 `202 Accepted` 后,status 和 export 仍会继续。客户端必须保存 ID,连接中断后也不能重复 create。
下方嵌入的是另一条已验证工作流产出的 TapVid 成片,用于展示 API 可交付的多场景结果。它不是本次 REST 测试的终态结果,因为轮询器在观察到终态前断开。
02
写代码前先看清接口契约
网关是 `https://api.tapvid.ai/api/public/v1`。API Keys 创建 Bearer key,在服务端用 `process.env.TAPVID_API_KEY` 读取。不要放进前端、截图或仓库。
- 使用 HTTPS REST base。
- 在服务端读取 `process.env.TAPVID_API_KEY`。
- 每次只传 URL 或文件一种。
- 保存 `materialId`,HTTP 202 后立即保存 `videoId`。
- 按 `pollAfterSeconds` 轮询并设置可恢复超时。
| 字段 | 限制 | 说明 |
|---|---|---|
| 文件 | 100 MB | multipart |
| URL | HTTPS,4,096 字符 | 不能是内网 host |
| 素材 | 最多 30 个 | 保存所有 ID |
| Prompt | 12,000 字符 | 基于来源 |
| 画幅 | `16:9` 或 `9:16` | 枚举需准确 |
| 时长 | `30s` 到 `5m` | 枚举需准确 |
03
第一步:上传公开 URL 或文件
URL 用 HTTPS JSON,文件用不超过 100 MB 的 multipart。URL 最长 4,096 字符。返回的 `materialId` 是私有应用状态,应立即保存。
export TAPVID_API_KEY="replace-with-your-local-secret"
curl -X POST https://api.tapvid.ai/api/public/v1/materials \
-H "Authorization: Bearer ${TAPVID_API_KEY}" \
-H "Content-Type: application/json" \
-d '{ "url": "https://tapvid.ai/api-mcp" }'cURL 示例用于本地理解,CI 应使用 secret store。`payload_too_large` 要修改素材,URL 被拒要检查 HTTPS、长度、可访问性和重定向。
04
第二步:创建异步视频任务
只有上传成功后才 create。明确受众、来源、30 秒、16:9、英文、步骤和禁止声明。HTTP 202 和 `videoId` 代表已受理,不代表完成。
curl -X POST https://api.tapvid.ai/api/public/v1/video/create \
-H "Authorization: Bearer ${TAPVID_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"materialIds": ["MATERIAL_ID_FROM_UPLOAD"],
"userPrompt": "Create a concise 30-second English explainer for developers. Stay faithful to the supplied source and do not invent claims.",
"title": "TapVid API developer explainer",
"aspectRatio": "16:9",
"duration": "30s",
"language": "en"
}'
下一次网络调用前先持久化 `videoId`。进程崩溃后才能恢复并防止重复创建。响应字段是 `videoId`,查询参数是 `video_id`。
05
第三步:持久化、轮询并请求下载
按 `pollAfterSeconds` 查询 status。progress 不是剩余时间。completed 后再请求 download,并在需要时刷新约一小时有效的签名 URL。
import { writeFile } from 'node:fs/promises'
const apiKey = process.env.TAPVID_API_KEY
if (!apiKey) throw new Error('TAPVID_API_KEY is required')
const base = 'https://api.tapvid.ai/api/public/v1'
const headers = { Authorization: `Bearer ${apiKey}` }
async function request(path, init = {}, { attempts = 1 } = {}) {
let lastError
for (let attempt = 1; attempt <= attempts; attempt += 1) {
try {
const response = await fetch(`${base}${path}`, {
...init,
headers: { ...headers, ...init.headers },
})
const data = await response.json()
if (response.ok) return { response, data }
if (response.status !== 429 && response.status < 500) {
const error = new Error(`HTTP ${response.status}: ${data.code ?? 'unknown'}`)
error.retryable = false
throw error
}
lastError = new Error(`retryable HTTP ${response.status}`)
} catch (error) {
if (error?.retryable === false) throw error
lastError = error
}
if (attempt === attempts) break
await new Promise((resolve) => setTimeout(resolve, attempt * 1000))
}
throw lastError
}
const { data: material } = await request('/materials', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url: 'https://tapvid.ai/api-mcp' }),
})
const { response: createResponse, data: video } = await request('/video/create', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
materialIds: [material.materialId],
userPrompt: 'Create a concise 30-second English explainer for developers. Stay faithful to the source.',
title: 'TapVid API developer explainer',
aspectRatio: '16:9',
duration: '30s',
language: 'en',
}),
})
if (createResponse.status !== 202) throw new Error('Expected 202 Accepted')
// Persist before the next network call. A lost poll must not cause a duplicate create.
await writeFile('.tapvid-job.json', JSON.stringify({ videoId: video.videoId }))
let status
for (let poll = 0; poll < 180; poll += 1) {
const result = await request(
`/video/status?video_id=${encodeURIComponent(video.videoId)}`,
{},
{ attempts: 4 },
)
status = result.data
if (status.status === 'completed' || status.status === 'failed') break
await new Promise((resolve) =>
setTimeout(resolve, Math.max(status.pollAfterSeconds ?? 5, 5) * 1000),
)
}
if (!status) throw new Error('No status received')
if (status.status === 'failed') throw new Error(status.error?.code ?? 'generation_failed')
if (status.status !== 'completed') throw new Error('Polling timeout; resume with the saved videoId')
const query = new URLSearchParams({
video_id: video.videoId,
resolution: '1080P',
watermark: 'true',
subtitle: 'false',
})
const { data: download } = await request(`/video/download?${query}`, {}, { attempts: 4 })
console.log({ status: download.status, expiresAt: download.expiresAt })Node 示例会保存 ID,只对安全读取做有限重试。生产环境把本地 JSON 换成数据库。400 和 401 要修正,429、服务端和网络错误才退避重试。
06
真实 REST 测试暴露了什么
实测上传约 1.4 秒,创建约 0.3 秒并返回 HTTP 202。约 81 秒进入 running 50%,331 秒时仍相同,随后轮询进程在 TLS 建连前收到 `ECONNRESET`。

第一版脚本只把 ID 放在进程内存,退出后无法恢复。测试没有重复创建任务。MCP 和 REST 总用量达到 180 credits,每次 create 90。因此本文不会声称 10 分钟成片。
07
处理错误,但不要重复消耗
unauthorized 要修密钥,invalid_request 要修 body,insufficient_credits 要停止,rate_limited 遵守 Retry-After,网络错误只重试安全读取。丢失 create 响应后不要再创建。
| 条件 | 重试? | 操作 |
|---|---|---|
| unauthorized | 否 | 修复密钥 |
| invalid_request | 否 | 修复 body |
| insufficient_credits | 否 | 停止 |
| rate_limited | 是 | 遵守 Retry-After |
| 网络或服务端 | 有限 | 重试读取 |
| create 后丢响应 | 不要重建 | 按 ID 恢复 |
08
可靠生产接入检查清单
生产接入需要服务端 secret、原子保存 ID、分开测量请求和生成时延、可恢复超时、安全日志、可刷新的下载 URL,以及人工审核事实、时长、版权和品牌。
- 密钥只在服务端。
- 原子保存 ID。
- 分开记录时延。
- 遵守间隔和超时。
- 区分读取和写入。
- 刷新签名 URL。
- 不含 secret 地记录 credits。
- 由人审核并发布。
09
用 API 做完整解释视频,而不是随机短片
这套 API 适合把已批准内容做成连贯解释视频,不是随机电影感短片承诺。对话探索看 Claude MCP 教程,持久控制看 REST 和 API/MCP 概览。
10
常见问题
一定能在 10 分钟完成视频吗?
不能保证。接入代码很短,但渲染和导出是异步的。MCP 实测约 28 分钟才 completed。
HTTP 202 是什么意思?
任务已受理。保存 videoId 并查询 status。
多久轮询一次?
使用 pollAfterSeconds、有限重试和可恢复超时。
下载 URL 有效多久?
当前文档说明约一小时。
能去除水印吗?
默认保留水印,去除需要有效订阅。
Turn them into a clear, publishable video
Keep reading
Related stories

如何用 Claude 和 TapVid MCP 生成动态图形视频
基于一个公开 URL、5 个真实 MCP 工具、30 秒 brief 和一次如实记录的生产测试。
Aug 7, 2026

Claude 视频生成:选 Seedance 2.5 还是 TapVid?
Claude 本身不能渲染视频。本文结合真实测试与可复用提示词,说明什么时候该搭配 Seedance 2.5,什么时候该用 TapVid。
Aug 8, 2026

文字动画技巧:不制造视觉噪音的更快动效
一套实用的文字动画框架,帮助需要清晰、有冲击力视频信息的团队。
Apr 16, 2026

