curl --request GET \
--url https://apis.viggle.ai/v1/videos/{video_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://apis.viggle.ai/v1/videos/{video_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://apis.viggle.ai/v1/videos/{video_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/videos/{video_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/videos/{video_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://apis.viggle.ai/v1/videos/{video_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/videos/{video_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"stage": "queued",
"progress": 50,
"video_url": "<string>",
"alpha_url": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
},
"seed": 123,
"queue_position": 1,
"estimated_wait_seconds": 1
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}获取视频
通过统一接口获取渲染、视频生成或视频超分的完整状态。
curl --request GET \
--url https://apis.viggle.ai/v1/videos/{video_id} \
--header 'Authorization: Bearer <token>'import requests
url = "https://apis.viggle.ai/v1/videos/{video_id}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://apis.viggle.ai/v1/videos/{video_id}', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://apis.viggle.ai/v1/videos/{video_id}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/videos/{video_id}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://apis.viggle.ai/v1/videos/{video_id}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/videos/{video_id}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "<string>",
"status": "queued",
"stage": "queued",
"progress": 50,
"video_url": "<string>",
"alpha_url": "<string>",
"created_at": "2023-11-07T05:31:56Z",
"completed_at": "2023-11-07T05:31:56Z",
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
},
"seed": 123,
"queue_position": 1,
"estimated_wait_seconds": 1
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}{
"error": {
"code": "UNAUTHENTICATED",
"message": "<string>",
"retryable": true,
"request_id": "<string>",
"details": {},
"remediation": {
"action": "<string>",
"retry_after_ms": 1
}
}
}GET /v1/videos/{video_id} 接受四类 ID 并返回当前持久化状态:渲染的 render_、H3 生成的 vid_、Viggle-Animate 生成的 anim_,以及视频 2 倍超分的 vsr_。每 3–5 秒轮询一次,直到进入终态。Render 来源的 ID 也支持监听渲染推送。
本接口替代已停用的 GET /v1/renders/{render_id}。
405 Method Not Allowed,而不是 404,因为该路径仍注册有其他方法。只有路径完全没有注册方法时才返回 404。如旧集成通过 404 判断接口已停用,请同时处理 405,或直接迁移到本接口。请求参数
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
video_id | string | 是 | 完整公开 ID:render_...、vid_...、anim_... 或 vsr_...。使用同一 ID 每 3–5 秒轮询,直到进入终态。 |
响应参数
返回200 OK 和 Video 对象。
| 字段 | 类型 | 始终返回 | 说明 |
|---|---|---|---|
id | string | 是 | 所请求的视频 ID。 |
status | string | 是 | queued、processing、ready、failed 或 cancelled。H3(vid_)视频不会返回 cancelled,后端取消或超时均以 failed 返回。 |
stage | string 或 null | 是 | 仅 Render 来源且 status=processing 时有值,其他情况为 null;H3 始终为 null。不存在 stage: "ready"。 |
progress | integer 或 null | 是 | 0–100 的进度,或 null。 |
video_url | string 或 null | 是 | 就绪后的输出下载地址;此前为 null。 |
alpha_url | string 或 null | 是 | 仅透明背景(background_mode=transparent)的 Render 在就绪后有值。H3 始终为 null。 |
created_at | string 或 null | 是 | Render 来源时间戳精确到纳秒;H3 来源精确到秒。 |
completed_at | string 或 null | 是 | 见下方完成时间说明。 |
error | object 或 null | 是 | status=failed 时的结构化错误详情。 |
seed | integer | 仅 H3 | 实际使用的随机种子:传入时原样返回,未传入时返回生成的值。仅 vid_ 视频包含该字段;Render、角色动画和视频超分来源会省略此字段,而非返回 null。系统生成的种子通常超出 JavaScript 安全整数范围,见下方警告。 |
queue_position | integer 或 null | vid_ 与 anim_ | 处于 queued 状态时前方的任务数;开始处理或进入终态后为 null。render_ 与 vsr_ 完全省略该字段。 |
estimated_wait_seconds | integer 或 null | vid_ 与 anim_ | 根据全局平均渲染时长及当前队列/调度状态估算:queued 时为预计完成所需秒数,processing 时为剩余的平均渲染时长。进入终态、位于非最高优先级队列(可能被新的最高优先级任务持续插队),或无法给出有界估算时为 null。render_ 与 vsr_ 完全省略该字段。 |
seed 是 63 位随机整数(0 到 2^63 − 1),几乎总是大于 Number.MAX_SAFE_INTEGER(2^53 − 1)。JavaScript 的 JSON.parse 会静默丢失精度——下方示例中的 4271960385017522688 会被读成另一个数,用它重新提交也无法复现同一视频。如需精确值,请使用支持 64 位整数的 JSON 解析器(例如 json-bigint),或在创建视频时自行传入不大于 2^53 − 1 的 seed。links,因此不包含创建渲染响应中的 self、events、download 快捷链接。继续查询时使用同一 video_id;Render 来源的 ID 还可使用下载渲染结果。
完成时间
Render 来源的视频在status 变为 ready 后,completed_at 可能延迟约 30 秒回填,并非永久缺失。判断视频是否完成,应检查 status == "ready" 或 video_url 是否有值,不应依赖 completed_at 非空。
Render 来源示例
{
"id": "render_a1b2c3",
"status": "ready",
"stage": null,
"progress": 100,
"video_url": "https://assets.viggle.ai/render_a1b2c3.mp4",
"alpha_url": null,
"created_at": "2026-08-25T09:12:03.123456789Z",
"completed_at": "2026-08-25T09:13:47Z",
"error": null
}
H3 来源示例
{
"id": "vid_3f2a9c",
"status": "ready",
"stage": null,
"progress": 100,
"video_url": "https://storage.googleapis.com/...signed...",
"alpha_url": null,
"created_at": "2026-08-24T09:12:03Z",
"completed_at": "2026-08-24T09:13:47Z",
"error": null,
"seed": 4271960385017522688,
"queue_position": null,
"estimated_wait_seconds": null
}
角色动画来源示例
{
"id": "anim_7c1e4b",
"status": "ready",
"stage": null,
"progress": 100,
"video_url": "https://storage.googleapis.com/...signed...",
"alpha_url": null,
"created_at": "2026-09-09T09:12:03Z",
"completed_at": "2026-09-09T09:13:47Z",
"error": null,
"queue_position": null,
"estimated_wait_seconds": null
}
seed 字段;该字段仅适用于 H3。queue_position 与 estimated_wait_seconds 两种来源都会返回,进入终态后为 null。
失败示例
{
"id": "render_a1b2c3",
"status": "failed",
"stage": null,
"progress": null,
"video_url": null,
"alpha_url": null,
"created_at": "2026-08-25T09:12:03.123456789Z",
"completed_at": "2026-08-25T09:13:50Z",
"error": {
"code": "TASK_FAILED",
"message": "The render could not be completed.",
"retryable": false,
"request_id": "req_123abc",
"details": {},
"remediation": { "action": "contact_support", "retry_after_ms": null }
}
}
示例
curl "https://apis.viggle.ai/v1/videos/render_a1b2c3" -H "Authorization: Bearer $VIGGLE_API_KEY"
import os, requests
response = requests.get("https://apis.viggle.ai/v1/videos/render_a1b2c3", headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"})
response.raise_for_status()
video = response.json()
const response = await fetch("https://apis.viggle.ai/v1/videos/render_a1b2c3", { headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` } });
const video = await response.json();
req, _ := http.NewRequest("GET", "https://apis.viggle.ai/v1/videos/render_a1b2c3", nil)
req.Header.Set("Authorization", "Bearer "+os.Getenv("VIGGLE_API_KEY"))
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
授权
服务端 SDK 使用项目 API 密钥,Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。
请求头
可选的调用者自定义关联 ID,最长 128 字符。服务会在响应头返回实际使用的值,便于追踪和支持排查。
1 - 128可选来源标签,最长 128 字符,用于识别 SDK、集成、产品入口或内部工作流。
1 - 128路径参数
当前调用者拥有的视频公开 ID:渲染为 render_,H3 为 vid_,角色动画为 anim_,视频超分为 vsr_。
1响应
请求成功。
统一、只读的视频完整状态,支持 render_、vid_ 和 anim_。不包含 links 或 self/events/download 快捷链接。stage 仅 Render 来源且 processing 时有值,其余为 null。alpha_url 仅透明背景 Render 就绪时有值。seed 仅 H3 包含,Render 和角色动画完全省略该字段,而不是返回 null。
所请求的视频 ID。
1queued、processing、ready、failed 或 cancelled。
queued, processing, ready, failed, cancelled 仅 Render 来源且 status=processing 时有值,其他情况为 null;H3 始终为 null。不存在 stage: "ready"。
queued, preparing, generating, finalizing, ready, failed, cancelled, analyzing, rendering, finishing 0–100 的进度,或 null。
0 <= x <= 100就绪后的输出下载地址;此前为 null。
仅透明背景(background_mode=transparent)的 Render 在就绪后有值。H3 始终为 null。
Render 来源时间戳精确到纳秒;H3 来源精确到秒。
见下方完成时间说明。
status=failed 时的结构化错误详情。
Show child attributes
Show child attributes
实际使用的随机种子:传入时原样返回,未传入时返回生成的值。仅 vid_ 视频包含该字段;Render、角色动画及视频超分来源会省略此字段,而非返回 null。系统生成的种子是 63 位随机整数(0 到 2^63−1),通常大于 2^53 − 1,请用支持 64 位整数的 JSON 解析器读取;JavaScript 的 JSON.parse 会静默丢失精度。
H3(vid_)与角色动画(anim_)视频返回。处于 queued 状态时表示前方任务数;开始处理或进入终态后为 null。Render 与视频超分来源完全省略该字段。
x >= 0H3(vid_)与角色动画(anim_)视频返回。根据全局平均渲染时长及当前队列或调度状态估算的剩余秒数:排队时为预计完成所需时间,处理中为剩余的平均渲染时长。进入终态、位于非最高优先级队列(可能被新的最高优先级任务持续插队),或无法给出有界估算时为 null。Render 与视频超分来源完全省略该字段。
x >= 0
