curl --request POST \
--url https://apis.viggle.ai/v1/scenes/reconstruct \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "living-room-01",
"referenceBatchIds": [
"<string>"
],
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
'import requests
url = "https://apis.viggle.ai/v1/scenes/reconstruct"
payload = {
"sessionId": "living-room-01",
"referenceBatchIds": ["<string>"],
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionId: 'living-room-01',
referenceBatchIds: ['<string>'],
spzOutputUrl: '<string>',
outputUris: {spz: '<string>', preview: '<string>', panorama: '<string>'}
})
};
fetch('https://apis.viggle.ai/v1/scenes/reconstruct', 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/scenes/reconstruct",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'living-room-01',
'referenceBatchIds' => [
'<string>'
],
'spzOutputUrl' => '<string>',
'outputUris' => [
'spz' => '<string>',
'preview' => '<string>',
'panorama' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/scenes/reconstruct"
payload := strings.NewReader("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/scenes/reconstruct")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/scenes/reconstruct")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"sessionId": "<string>",
"operation": "pano",
"status": "processing",
"createdAt": 123,
"completedAt": 123,
"result": {
"operation": "pano",
"sessionId": "<string>",
"spz": {
"url": "<string>"
},
"preview": {
"url": "<string>"
},
"panorama": {
"url": "<string>"
},
"outputBatch": {
"batchId": "<string>",
"createdAt": 123,
"manifest": {
"url": "<string>"
},
"kind": "initial",
"views": [
{
"index": 1,
"url": "<string>",
"c2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"intrinsic": [
123
]
}
]
},
"referenceViewCount": 123,
"newViewCount": 123,
"seconds": {}
},
"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
}
}
}重建场景
用会话的图像批次重建 3D 场景,生成新的 .spz。
curl --request POST \
--url https://apis.viggle.ai/v1/scenes/reconstruct \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"sessionId": "living-room-01",
"referenceBatchIds": [
"<string>"
],
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
'import requests
url = "https://apis.viggle.ai/v1/scenes/reconstruct"
payload = {
"sessionId": "living-room-01",
"referenceBatchIds": ["<string>"],
"spzOutputUrl": "<string>",
"outputUris": {
"spz": "<string>",
"preview": "<string>",
"panorama": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
sessionId: 'living-room-01',
referenceBatchIds: ['<string>'],
spzOutputUrl: '<string>',
outputUris: {spz: '<string>', preview: '<string>', panorama: '<string>'}
})
};
fetch('https://apis.viggle.ai/v1/scenes/reconstruct', 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/scenes/reconstruct",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'sessionId' => 'living-room-01',
'referenceBatchIds' => [
'<string>'
],
'spzOutputUrl' => '<string>',
'outputUris' => [
'spz' => '<string>',
'preview' => '<string>',
'panorama' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://apis.viggle.ai/v1/scenes/reconstruct"
payload := strings.NewReader("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://apis.viggle.ai/v1/scenes/reconstruct")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/scenes/reconstruct")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"sessionId\": \"living-room-01\",\n \"referenceBatchIds\": [\n \"<string>\"\n ],\n \"spzOutputUrl\": \"<string>\",\n \"outputUris\": {\n \"spz\": \"<string>\",\n \"preview\": \"<string>\",\n \"panorama\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"id": "<string>",
"sessionId": "<string>",
"operation": "pano",
"status": "processing",
"createdAt": 123,
"completedAt": 123,
"result": {
"operation": "pano",
"sessionId": "<string>",
"spz": {
"url": "<string>"
},
"preview": {
"url": "<string>"
},
"panorama": {
"url": "<string>"
},
"outputBatch": {
"batchId": "<string>",
"createdAt": 123,
"manifest": {
"url": "<string>"
},
"kind": "initial",
"views": [
{
"index": 1,
"url": "<string>",
"c2w": [
[
1,
0,
0,
0
],
[
0,
1,
0,
0
],
[
0,
0,
1,
0
],
[
0,
0,
0,
1
]
],
"intrinsic": [
123
]
}
]
},
"referenceViewCount": 123,
"newViewCount": 123,
"seconds": {}
},
"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
}
}
}.spz 高斯泼溅,通常是创建场景产生的 initial 批次,加上生成场景视图产生的 generated 批次。视图覆盖的场景越多,结果越完整。
接口是异步的:返回 processing 状态的场景任务,轮询直到任务结束。
请求参数
使用application/json,最大 1 MiB。不接受未知字段。
targetC2w、projection、fov 和 seed 属于生成场景视图,在本接口中会被拒绝。
响应参数
返回200 OK 和 processing 状态的场景任务:
{
"id": "scn_0199f0c6-9a8b-7c6d-8e5f-4a3b2c1d0e9f.living-room-01",
"sessionId": "living-room-01",
"operation": "reconstruct",
"status": "processing",
"createdAt": 1791857000000,
"completedAt": null,
"result": null,
"error": null
}
ready 后,result.spz.url 即重建后的场景,result.referenceViewCount 为使用的视图数量。result.outputBatch 为 null:重建不会向会话添加图像。
常见错误
| 错误 | 原因 |
|---|---|
400 INVALID_REQUEST | 字段缺失、不合法或未知,例如 referenceBatchIds 为空、超过 35 个 ID 或有重复,或某个 ID 不是小写 UUID。 |
401 UNAUTHENTICATED | 缺少或无效的 API 密钥。 |
409 INVALID_REQUEST | 该会话已有任务处于 processing,见 error.details.running_task_id。 |
503 SERVICE_BUSY | 场景模型暂时不可用,可重试。 |
INVALID_REQUEST 失败。
示例
curl -X POST https://apis.viggle.ai/v1/scenes/reconstruct \
-H "Authorization: Bearer $VIGGLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"sessionId": "living-room-01",
"referenceBatchIds": [
"3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f",
"9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
]
}'
import os, requests
response = requests.post(
"https://apis.viggle.ai/v1/scenes/reconstruct",
headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
json={
"sessionId": "living-room-01",
"referenceBatchIds": [
"3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f",
"9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
],
},
)
response.raise_for_status()
task = response.json()
const response = await fetch("https://apis.viggle.ai/v1/scenes/reconstruct", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.VIGGLE_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
sessionId: "living-room-01",
referenceBatchIds: [
"3f0a6c1e-8d2b-4b7a-9e5c-1a2b3c4d5e6f",
"9b8a7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
],
}),
});
const task = await response.json();
快速入门:场景模型
授权
服务端 SDK 使用项目 API 密钥,Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。
请求头
可选的调用者自定义关联 ID,最长 128 字符。服务会在响应头返回实际使用的值,便于追踪和支持排查。
1 - 128可选来源标签,最长 128 字符,用于识别 SDK、集成、产品入口或内部工作流。
1 - 128请求体
POST /v1/scenes/reconstruct 的请求体。spzOutputUrl 与 outputUris 不能同时使用。
调用方自定的会话 ID,按账户隔离。一个会话对应一个场景及其全部图像批次,同一时间只运行一个任务;已有任务 processing 时再提交会返回 409,error.details.running_task_id 为正在运行的任务。
1 - 128^[A-Za-z0-9_-]+$"living-room-01"
同一会话内的 1–35 个不重复批次 ID,即 result.outputBatch.batchId。格式正确但属于其他会话的 ID 会让任务以 INVALID_REQUEST 失败。
1 - 35 elements^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$等同于 outputUris.spz。
调用方自己的上传地址,Viggle 完成后用 PUT 把对应文件上传过去;值为 null 的项会被忽略。上传到这里的 .spz Viggle 不再保留,结果中的 spz.url 即该地址;预览图和全景图上传后 Viggle 仍保留一份,结果中链接指向 Viggle 的副本。每个地址必须是 http(s)、不含账号密码、且主机只解析到公网地址。
Show child attributes
Show child attributes
响应
场景任务已启动。
场景任务(以 scn_ 开头),所有 /v1/scenes 提交接口和 GET /v1/scenes/{task_id} 都返回它。ready、failed、cancelled 为终态。任务结束后约 72 小时内可查询。
任务 ID,格式为 scn_{runId}.{sessionId}。
custom-pano 任务也返回 pano。
pano, generate, reconstruct processing, ready, failed, cancelled 开始时间,Unix 毫秒。
结束时间,Unix 毫秒;processing 时为 null。
只在 ready 时有值。
Show child attributes
Show child attributes
只在 failed 时有值。code 为 INVALID_REQUEST(不可重试,模型拒绝了输入,例如引用了其他会话的批次)或 PROCESSING_FAILED(可重试)。
Show child attributes
Show child attributes

