curl --request GET \
--url https://apis.viggle.ai/v1/renders/{render_id}/events \
--header 'Authorization: Bearer <token>'import requests
url = "https://apis.viggle.ai/v1/renders/{render_id}/events"
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/renders/{render_id}/events', 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/renders/{render_id}/events",
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/renders/{render_id}/events"
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/renders/{render_id}/events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/renders/{render_id}/events")
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"<string>"{
"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
}
}
}Watch Render
Watch render state through Server-Sent Events instead of polling.
curl --request GET \
--url https://apis.viggle.ai/v1/renders/{render_id}/events \
--header 'Authorization: Bearer <token>'import requests
url = "https://apis.viggle.ai/v1/renders/{render_id}/events"
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/renders/{render_id}/events', 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/renders/{render_id}/events",
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/renders/{render_id}/events"
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/renders/{render_id}/events")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://apis.viggle.ai/v1/renders/{render_id}/events")
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"<string>"{
"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
}
}
}ready, failed, or cancelled. Reconnect with Last-Event-ID to resume after a snapshot. If the event history has expired, call Get Video (GET /v1/videos/{render_id}) and reconnect from the current state.
Request parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
render_id | string | Yes | Full public Render ID returned by Render Video (from Character and/or Motion) or List Videos, normally beginning with render_. The stream reports events only for this Render. |
Last-Event-ID | string | No | Request header containing the last SSE event ID processed completely. Send it when reconnecting so retained history resumes after that event; omit it for a fresh stream. |
Response
Returns200 OK with a text/event-stream body. Business events carry a JSON data payload; heartbeats may omit data.
| Event | data payload | Description |
|---|---|---|
snapshot | Render event data | Sent immediately on connect. |
queued | Render event data | Render accepted, not yet processing. |
processing | Render event data | Processing has started. |
progress | Render event data | progress and/or stage changed. |
ready | Render event data | Terminal — video_url/alpha_url populated. Stream closes. |
failed | Render event data | Terminal — error populated. Stream closes. |
cancelled | Render event data | Terminal. Stream closes. |
heartbeat | none | Keep-alive; no business data. |
data field:
| Field | Type | Always present | Description |
|---|---|---|---|
event_id | string | Yes | Pass as Last-Event-ID to resume after this event. |
sequence | integer | Yes | Monotonically increasing per render. |
id | string | Yes | Render ID. |
status | string | Yes | queued, processing, ready, failed, or cancelled. |
stage | string or null | Yes | Coarse progress hint when available. |
progress | integer or null | Yes | Progress from 0 to 100 when available. |
video_url / alpha_url | string or null | Yes | Populated on ready. |
occurred_at | string | Yes | ISO 8601 timestamp of the event. |
completed_at | string or null | Yes | ISO 8601 completion timestamp. |
error | object or null | Yes | Populated on failed. |
Examples
curl -N "https://apis.viggle.ai/v1/renders/render_789ghi/events" \
-H "Authorization: Bearer $VIGGLE_API_KEY" \
-H "Accept: text/event-stream"
const response = await fetch("https://apis.viggle.ai/v1/renders/render_789ghi/events", {
headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}`, Accept: "text/event-stream" },
});
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// Split on blank lines to get whole SSE frames, then parse `event:`/`data:`.
}
import os, requests
with requests.get(
"https://apis.viggle.ai/v1/renders/render_789ghi/events",
headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}", "Accept": "text/event-stream"},
stream=True,
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if line:
print(line)
Next step
Once aready event arrives, use Download Render or the event’s own video_url/alpha_url to fetch the result.Authorizations
Server-side SDK clients use a project API key. Remote MCP clients use an OAuth access token. Never expose a project API key in browser code.
Headers
ID of the last SSE event the client processed completely. Send it on reconnection so the server can resume after that event when retained history is available.
1Optional caller-supplied correlation ID, up to 128 characters. The service returns the effective value in the response header for tracing and support.
1 - 128Optional source-channel label, up to 128 characters, used to attribute traffic to an SDK, integration, product surface, or internal workflow.
1 - 128Path Parameters
Public Render ID returned by render creation or listing. It normally begins with render_ and must identify a render owned by the caller.
1Response
Server-Sent Events stream. Business event data fields contain a
JSON RenderEventData value. Heartbeats may omit data.
UTF-8 Server-Sent Events stream.

