API v1 参考

使用 VideoLingo API 创建并查询 YouTube 视频翻译任务。


概览

VideoLingo API v1 允许专业计划用户从服务端代码创建 YouTube 视频翻译任务并查询进度。API 任务与网页任务使用同一套处理流程、账户余额、计费规则和任务列表;未填写名称时,任务名以 API · 开头。

项目说明
API 基址https://videolingo.io/api/v1
鉴权方式Authorization: Bearer <API_KEY>
请求与响应格式JSON
当前接口POST /tasks、GET /tasks/{id}
计划要求有效的专业计划;付费期结束后包含 1 天宽限期
单个视频最长时长4 小时(14400 秒)
同时处理上限每个账户 3 个排队中或处理中的任务,网页任务也计入

API v1 目前只接受 YouTube 链接,暂不提供任务列表、取消任务或 webhook 回调接口。所有响应都带 Cache-Control: no-store,且不返回 CORS 头。请从服务端调用,不要从浏览器前端直接调用;这也能避免把 API Key 暴露给用户。

获取 API Key

登录后打开任务台 → 账户 → API,也可以从右上角头像菜单进入 API Key。有效的专业计划账户会得到一把以 vl_live_ 开头的 Key,可以在该页面显示、复制或重新生成。

API Key 等同密码。不要放进浏览器端代码、不要提交到代码仓库、不要拼进 URL、不要写入日志,也不要分享包含 Key 的截图。请保存在服务端密钥管理服务或环境变量中。

下文示例使用环境变量:

export VL_API_KEY="vl_live_替换成你的Key"

鉴权

每个请求都要带:

Authorization: Bearer vl_live_xxxxxxxxxxxxxxxx

接口不读取 Cookie,也不接受 URL 查询参数里的 Key。缺失、格式错误、已被重新生成或不存在的 Key 返回 401 invalid_api_key;Key 正确但专业计划无效时返回 403 subscription_inactive。

创建任务

POST /tasks

请求头

请求头是否必填值与行为
Authorization是Bearer <API_KEY>。必须带 Bearer,不能只发送 Key。
Content-Type是application/json。请求体必须是合法 JSON。
Idempotency-Key强烈建议8–128 个字符;对这一次预期创建的任务保持唯一且稳定,例如订单号或 UUID。

幂等重试

每个新视频任务使用一个新的 Idempotency-Key。如果网络超时或 5xx 导致结果不确定,请使用同一个 Key 和完全相同的 JSON 请求体重试。重复请求会指向同一个任务;任务开始后不会再次创建或重复扣费。

  • Key 对应的任务已经删除时,返回 422 invalid_request,此时需要换新 Key。
  • Key 少于 8 个或超过 128 个字符时,返回 422 invalid_request。
  • 不要用同一个 Key 提交另一个视频或另一组参数。API v1 并不保证在所有“尚未派发”的状态下都检测请求体冲突。
  • 不带 Key 时,每次重试都可能创建一个独立任务并单独计费。

请求体

请求体是一个扁平 JSON 对象。只有 youtube_url 必填。未列出的字段都会被拒绝,包括 user_plan、watermark、prod、模型名称等由服务端决定的字段。

字段是否必填JSON 类型默认值详细说明
youtube_url是string—YouTube 视频的 HTTPS 链接,最长 2048 字符。允许的主机:youtube.com、www.youtube.com、m.youtube.com、youtu.be。支持 /watch?v=…、youtu.be/…、/shorts/…、/embed/…、/live/…、/v/…。带用户名密码、自定义端口、非 HTTPS、只有播放列表没有单个视频 ID、或非 YouTube 主机的链接都会被拒绝。
name否stringAPI · <视频 ID>任务台中显示的任务名称。服务端会去掉首尾空格,剩余内容必须为 1–200 个字符。
target_language否string 枚举简体中文译文字幕和配音的输出语言。必须传下方目标语言表中的精确值;它不是跟随当前页面语言变化的显示文案。
source_language否string 枚举en源视频里实际说的语言,用于语音识别。必须传下方源语言表中的精确代码。这里不会自动检测;源视频不是英语时请主动设置。
dubbing否booleanfalsefalse 只生成翻译字幕;true 还会生成配音音轨。必须传 JSON 布尔值,不能传字符串 "true" 或 "false"。
tts_method否string 枚举当前 target_language 的第一款预设音色配音音色。fish_voice_… 必须属于所选目标语言;fish_clone 使用系统从视频中提取的参考声音。只有 dubbing 为 true 时才影响成品音频。
target_height否string 枚举"1080"下载 YouTube 视频时的最高分辨率:"480"、"720"、"1080"。必须是 JSON 字符串,不能传数字 1080。如果源视频没有对应清晰度,实际文件可能更低。
demucs否booleantrue是否在转写和配音前分离人声与背景音。对音乐或背景声较大的视频通常更有帮助,但也会增加处理工作量。
glossary否string不传用于人名、品牌名和专业术语的自由文本提示,最多 250 个字符。只放与当前视频有关的简短术语说明。

target_language 可选值

必须使用下列精确值之一:

语言target_language 精确值
英语English
法语Français
德语Deutsch
意大利语Italiano
西班牙语Español
俄语Русский
韩语한국어
日语日本語
简体中文简体中文
繁体中文繁體中文
粤语粤语

source_language 可选值

必须使用下列精确值之一:

语言source_language 精确代码
英语en
简体中文zh
繁体中文zh-TW
法语fr
德语de
意大利语it
西班牙语es
俄语ru
日语ja

配音音色取值

当 dubbing 为 true 时,可以省略 tts_method(自动使用该目标语言的第一款预设音色)、选择下表中与目标语言匹配的 fish_voice_<模型 ID>,或使用 fish_clone 克隆视频中提取到的参考声音。

预设音色和 target_language 必须属于同一语言。比如法语音色配 target_language: "日本語"、不存在的模型 ID、以及已经停用的 openai_tts 都会返回 422 invalid_request。

target_language 精确值音色性别tts_method 精确值
EnglishSarah女声fish_voice_933563129e564b19a115bedd57b7406a
EnglishSelene女声fish_voice_b347db033a6549378b48d00acb0d06cd
EnglishAdrian男声fish_voice_bf322df2096a46f18c579d0baa36f41d
EnglishEthan男声fish_voice_536d3a5e000945adb7038665781a4aca
FrançaisManon女声fish_voice_10a3a20742114a4ea6dd441e7591850f
FrançaisThérèse女声fish_voice_94702e20bb3e44d39c64ba74bb480dfc
FrançaisLucas男声fish_voice_f69bca092b674168a8d02d61ca20943c
FrançaisJulien男声fish_voice_9af982ac4fbc4877af9d33b06e694fb9
DeutschLena女声fish_voice_3937b44b604249f18b94913daef94043
DeutschMelanie女声fish_voice_d979e92f9c8a489fa581f55f6b9e48da
DeutschLeon男声fish_voice_7b7c88bf825a4ab3bca27d55c26ddf16
DeutschJonas男声fish_voice_44f1ec96a51e429f8b87776cbc55a997
ItalianoChiara女声fish_voice_ef02f46e6a7540759f9d767d7e22c2e5
ItalianoGiulia女声fish_voice_0e36e185d0654d5bac3d24331562a0cc
ItalianoLorenzo男声fish_voice_59ac2b0ad66641b5ab4666d3ed89e5d4
ItalianoMarco男声fish_voice_f6cbad8b89254774a495c088aeb7822e
EspañolCarmen女声fish_voice_3f065d660212478a9c697fa965b4d098
EspañolElena女声fish_voice_566359628f6a4d5fabf902f6f64ecec1
EspañolPablo男声fish_voice_1bd666ea8ada44c789e0fec21cf78f33
EspañolAndrés男声fish_voice_d85aae3c4f4d4c70860997c27554f533
РусскийПолина Polina女声fish_voice_bf75c2e80b0e441485eeec20330a75fa
РусскийMaria女声fish_voice_7adab54c80d34cba8c11463ab1502c9a
РусскийАртём Artyom男声fish_voice_b871e425b6c0442baa5cf73f6c336bbe
РусскийDmitri男声fish_voice_2911dfe1c9d54419b24ed8c4a1489355
한국어하윤 Hayoon女声fish_voice_96ed4e3f47334430b990df471d0a0268
한국어Yuna女声fish_voice_3d31499f0e13438bbce8dcce7b7c4298
한국어지훈 Jihoon男声fish_voice_1faa840246094164bf4b0b0b94ae1675
한국어Minjun男声fish_voice_82703151e4b043dbbd98f082d4841b71
日本語きょうこ(カスタマーサポート)女声fish_voice_b2d9d8db057042688a5e318b8f405bc2
日本語しおり(ナレーション)女声fish_voice_5da7f24e9e274f91b2b677669c818ce9
日本語さとる(ナレーション)男声fish_voice_297a6fd278df47c3b9da9bfdf55ac89a
日本語じん(ラジオパーソナリティ)男声fish_voice_d738c70d206149e69f8e3b6fc8af9d96
简体中文语彤 Yutong女声fish_voice_74c6aba5cbf94a15bbdc547ffce5cb38
简体中文冰冰 Bingbing女声fish_voice_e98fa6cdad6946bf8d9bb8f9cb8c2532
简体中文梓轩 Zixuan男声fish_voice_5d29a99739c14d4ca3e4fe42193105b2
简体中文浩然 Haoran男声fish_voice_d675c275d1d44e57b4ef3840c5a23209
繁體中文詩涵 Shihan(台灣)女声fish_voice_91ec588cf8ef443a9c0d5b21d0c1fa36
繁體中文Ya-Ting女声fish_voice_49066cb45f0a427484ade915a4474534
繁體中文承翰 Chenghan(台灣)男声fish_voice_1e85fd1e0d3e4cc2b79fbca800e7e3fe
繁體中文Chia-Hao男声fish_voice_e7af89da8abc4fbdacd9a10ab9881933
粤语詠詩 Wing Sze女声fish_voice_50c586f7c811466cac751c28c3e4a671
粤语VideoLingo 粵語女聲女声fish_voice_da2d934b77df4561ac51f8ed3edfaa2b
粤语俊傑 Chun Kit男声fish_voice_fc917a4b147145258519982fe306b2cf
粤语VideoLingo 粵語男聲男声fish_voice_a197cea20d84442d8462253a7ddf08a3

最小字幕任务示例

curl --request POST 'https://videolingo.io/api/v1/tasks' \
  --header "Authorization: Bearer $VL_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: order-8fa1a2b3' \
  --data '{
    "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "source_language": "en",
    "target_language": "简体中文",
    "dubbing": false
  }'

指定音色的配音任务示例

curl --request POST 'https://videolingo.io/api/v1/tasks' \
  --header "Authorization: Bearer $VL_API_KEY" \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: order-4c5d6e7f' \
  --data '{
    "youtube_url": "https://youtu.be/dQw4w9WgXcQ",
    "name": "日语配音发布视频",
    "source_language": "en",
    "target_language": "日本語",
    "dubbing": true,
    "tts_method": "fish_voice_b2d9d8db057042688a5e318b8f405bc2",
    "target_height": "1080",
    "demucs": true,
    "glossary": "VideoLingo:产品名保留拉丁字母,不翻译"
  }'

接受任务前会发生什么

  1. 接口验证 Key 和完整 JSON 请求体;未知字段或不匹配的值会在处理前失败。
  2. 接口读取公开视频时长,这一步最多约 20 秒。私有或不可访问的视频返回 422 duration_unavailable;超过 4 小时返回 422 invalid_request。
  3. 接口检查共享并发名额和可用余额,预留任务费用,然后派发处理。

成功时返回 202 Accepted 和任务对象;初始 status 通常为 queued 或 processing。

查询任务

GET /tasks/{id}

使用 POST /tasks 返回的 UUID:

curl 'https://videolingo.io/api/v1/tasks/TASK_ID' \
  --header "Authorization: Bearer $VL_API_KEY"

同一接口也能查询当前账户在网页上创建的任务。非法 UUID、不存在、已删除或属于其他用户的任务都会返回同一种 404 not_found,避免泄露任务归属。

建议每 15–30 秒查询一次,直到 status 变成 completed、failed 或 cancelled。查询处理中的任务时,接口也会刷新最新处理状态。

任务对象

两个成功接口返回相同结构:

{
  "id": "3f2c7a1e-5b8d-4c6f-9a0b-1d2e3f4a5b6c",
  "name": "API · dQw4w9WgXcQ",
  "status": "processing",
  "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
  "video_duration_seconds": 212,
  "cost_usd": 0.294444,
  "step": "Translating text",
  "step_index": 6,
  "error": null,
  "result": null,
  "created_at": "2026-09-24T08:00:00.000Z",
  "updated_at": "2026-09-24T08:03:12.000Z"
}
字段类型何时出现、应该怎么用
idstring (UUID)稳定的任务 ID。请保存下来,用于后续查询。
namestring任务台显示的任务名称。
statusstring 枚举生命周期状态。业务逻辑应判断此字段,取值见下表。
youtube_urlstring | null源视频链接。网页上传的本地文件任务为 null。
video_duration_secondsnumber | null已知时返回源视频秒数。
cost_usdnumber | null预留的美元费用:视频时长 × 每小时 5 美元。仅字幕与配音任务使用相同费率;时长未知时为 null。
stepstring | null处理中的可读流程名称。可以展示给用户,但不要依赖这段文案编写业务逻辑。
step_indexnumber | null适合进度 UI 使用的数字阶段,完整映射见下表。
errorstring | null当 status 为 failed 时的可读失败原因;它与 HTTP 错误响应里的 error 对象不是一回事。
resultobject | nullcompleted 时包含下载链接,其他状态为 null。
created_atstringISO 8601 格式的 UTC 创建时间。
updated_atstring任务最后一次持久化更新的 ISO 8601 UTC 时间。

status 取值

值是否终态含义与客户端动作
draft否尚未派发。可能是网页草稿,或创建接口返回过 503 dispatch_failed;后一种情况请用同一幂等键重试创建请求。
queued否已接受,正在等待处理资源。继续轮询。
processing否正在处理。可展示 step / step_index,继续轮询。
completed是成功完成,从 result 读取下载链接。
failed是处理失败,从 error 读取原因。除非原创建请求本身返回 503,再次提交应视为新任务并使用新的幂等键。
cancelled是已停止,不会产生结果。

step 与 step_index

step_index仅字幕任务配音任务
0Preparing input videoPreparing input video
1Extracting audio using DemucsExtracting audio using Demucs
2Transcribing using WhisperTranscribing using Whisper
3Splitting sentences using spaCySplitting sentences using spaCy
4Splitting sentences by meaningSplitting sentences by meaning
5Summarizing contentSummarizing content
6Translating textTranslating text
7Splitting for subtitlesSplitting for subtitles
8Aligning timestampsAligning timestamps
9Merging subtitles保留 / 跳过
10Uploading resultsGenerating audio tasks
11—Extracting reference audio
12—Generating audio using TTS
13—Merging full audio
14—Merging dub audio
15—Uploading results

较早开始的配音任务可能短暂上报旧版第 9 步;用于展示时,如果同时有 step,优先显示它。

result

任务完成后,result 包含 4 个可直接下载的链接:

字段文件
video最终 MP4 视频。
subtitles_zip包含全部字幕文件的 ZIP。
translated_srt译文 SRT 字幕。
source_srt原文 SRT 字幕。
{
  "result": {
    "video": "https://cloud.videolingo.io/tasks/3f2c7a1e-…/output.mp4",
    "subtitles_zip": "https://cloud.videolingo.io/tasks/3f2c7a1e-…/srt.zip",
    "translated_srt": "https://cloud.videolingo.io/tasks/3f2c7a1e-…/trans.srt",
    "source_srt": "https://cloud.videolingo.io/tasks/3f2c7a1e-…/src.srt"
  }
}

下载 URL 本身不能代替完成信号;必须先等到 status: "completed" 再使用。

错误与重试策略

HTTP 错误统一使用下列结构。程序应判断稳定的 error.code;error.message 是给人看的说明,未来可能调整措辞。

{
  "error": {
    "code": "concurrency_limit",
    "message": "At most 3 tasks can be queued or processing at once",
    "active": 3,
    "limit": 3
  }
}
HTTPerror.code含义客户端应该怎么做
401invalid_api_keyKey 缺失、格式错误、已重新生成或不存在。不要原样重试;修正请求头或部署当前 Key。
403subscription_inactive不是有效专业计划,或付费期结束已超过 1 天。续费/升级后再试;原 Key 会自动恢复。
404not_foundID 非法、任务不存在、已删除或属于其他账户。检查 ID 和账户,不要无休止重试。
422invalid_requestJSON/字段/值不合法、未知字段、YouTube 链接不合法、视频超过 4 小时、幂等键非法或对应已删除任务。修正请求。只有 Key 对应已删除任务或任务意图改变时才换新 Key。
422duration_unavailable视频为私有、不存在、受限或暂时不可访问,导致无法读取时长。先确认视频可公开访问;URL 不变时可以稍后用同一 Key 重试。
402insufficient_balance可用余额低于任务费用;附加字段为美元 balance、cost。充值后用同一 Key 重试。本次拒绝不会创建任务或扣费。
429concurrency_limit已有 3 个任务排队或处理中;附加字段为 active、limit。等待名额释放,再用同一 Key 重试。本次拒绝不会创建任务或扣费。
503dispatch_failed处理服务暂时拒绝接收;附加字段为 task_id。指数退避,并使用同一 Key 和请求体重试;任务保留为 draft。
500internal_error未预期的服务端错误。因结果可能不确定,请指数退避并使用同一 Key 和请求体重试。

建议瞬时错误退避间隔:2 秒、5 秒、10 秒、30 秒,之后停止并把错误显示给用户。未来如果响应带 Retry-After,应优先遵守。401、403、404 和一般 422 错误在根因未改变前不要自动重试。

限制与计费

  • **并发:**每个账户最多 3 个 queued 或 processing 任务,网页上创建的任务也占用同一名额。
  • **时长:**单个视频最长 4 小时(14400 秒)。
  • **计费:**字幕翻译与配音均按视频时长以每小时 5 美元计费。任务开始时从账户余额预留最终的 cost_usd。
  • **轮询:**目前没有每分钟请求配额,但应保持 15–30 秒一次的合理频率。长视频可以进一步延长间隔,进入终态后立即停止。
  • 异步语义:202 Accepted 只表示任务已接受处理,不表示已经完成;计费和成品都属于这个异步任务。

完整轮询示例

下面的 Bash 脚本需要 curl 和 jq。它会保留幂等键、在 HTTP 错误时失败,并且只在任务进入终态后停止。

#!/usr/bin/env bash
set -euo pipefail
 
: "${VL_API_KEY:?请先设置 VL_API_KEY}"
API='https://videolingo.io/api/v1'
IDEMPOTENCY_KEY="video-$(date +%s)-$$"
 
RESPONSE=$(curl --silent --show-error --fail-with-body \
  --request POST "$API/tasks" \
  --header "Authorization: Bearer $VL_API_KEY" \
  --header 'Content-Type: application/json' \
  --header "Idempotency-Key: $IDEMPOTENCY_KEY" \
  --data '{
    "youtube_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
    "source_language": "en",
    "target_language": "简体中文",
    "dubbing": false
  }')
 
TASK_ID=$(jq --raw-output '.id // empty' <<<"$RESPONSE")
test -n "$TASK_ID" || { printf '响应里没有任务 ID:%s\n' "$RESPONSE" >&2; exit 1; }
printf '任务 ID:%s\n' "$TASK_ID"
 
while true; do
  RESPONSE=$(curl --silent --show-error --fail-with-body \
    "$API/tasks/$TASK_ID" \
    --header "Authorization: Bearer $VL_API_KEY")
  STATUS=$(jq --raw-output '.status' <<<"$RESPONSE")
  STEP=$(jq --raw-output '.step // ""' <<<"$RESPONSE")
  printf '%s %s\n' "$STATUS" "$STEP"
 
  case "$STATUS" in
    completed) jq '.result' <<<"$RESPONSE"; break ;;
    failed|cancelled) jq '{status, error}' <<<"$RESPONSE" >&2; exit 1 ;;
    queued|processing|draft) sleep 30 ;;
    *) printf '未知状态:%s\n' "$STATUS" >&2; exit 1 ;;
  esac
done

轮换 API Key

  • 在任务台 → 账户 → API点击重新生成 Key。
  • 旧 Key 会立即失效并返回 401;正在处理的任务不会中断。
  • 删除自己保存的旧 Key 前,先更新所有服务器、CI 密钥和集成环境。
  • 怀疑泄露时立即重新生成。每个账户同一时间只有一把有效 Key。
  • 专业计划过期时 Key 返回 403;续费后原 Key 会恢复,因此日常续费不需要轮换。