Studio previews API
Base URL: https://YOUR-SERVER/api. Send your API key in x-api-key where authentication is required. A key also needs the listed permission; your account's access rules still apply.
API guide · All endpoints · OpenAPI JSON
POST /studio/preview-streams— Open a Studio preview streamDELETE /studio/preview-streams/{id}— Close a Studio preview streamGET /studio/preview-streams/{id}— Get a Studio preview streamPUT /studio/preview-streams/{id}/answer— Answer a Studio preview streamPOST /studio/preview-streams/{id}/reconnect— Reconnect a Studio preview streamPOST /studio/previews— Request a Studio preview frameDELETE /studio/previews/{id}— Cancel a Studio previewGET /studio/previews/{id}— Get a Studio previewGET /studio/previews/{id}/frame— View a Studio preview frame
Open a Studio preview stream
POST /api/studio/preview-streams
Opens a bounded WebRTC playback session of the project's current stored revision from an exact rational time. Refused for a superseded revision, an unavailable source, or when the account already holds the most sessions it may; an open session of the same project is superseded.
Authentication: API key. Permission: all.
Request body
Required.
Field definitions: StudioPreviewStreamOpenDto
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamOpenDto"
}
}
}Responses
Field definitions: StudioPreviewStreamDto
{
"201": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamDto"
}
}
},
"description": ""
}
}Close a Studio preview stream
DELETE /api/studio/preview-streams/{id}
Ends the session; the worker stops sending on its next signalling poll.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
Field definitions: StudioPreviewStreamDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamDto"
}
}
},
"description": ""
}
}Get a Studio preview stream
GET /api/studio/preview-streams/{id}
The session's state and, while it waits for an answer, the worker's offer. Polling it is the keepalive; each poll re-checks project access and the stored head, and closes the session when either has changed.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
Field definitions: StudioPreviewStreamDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamDto"
}
}
},
"description": ""
}
}Answer a Studio preview stream
PUT /api/studio/preview-streams/{id}/answer
The browser's complete answer (non-trickle ICE) to the current negotiation's offer: receive one video, send nothing. The server writes the session's bitrate bound into it before the worker reads it.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Request body
Required.
Field definitions: StudioPreviewStreamAnswerDto
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamAnswerDto"
}
}
}Responses
Field definitions: StudioPreviewStreamDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamDto"
}
}
},
"description": ""
}
}Reconnect a Studio preview stream
POST /api/studio/preview-streams/{id}/reconnect
Starts the next negotiation after the peer connection dropped, only once project access, the stored head, every source's availability and the worker's lease have been validated again. Any failure closes the session with its reason.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
Field definitions: StudioPreviewStreamDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewStreamDto"
}
}
},
"description": ""
}
}Request a Studio preview frame
POST /api/studio/previews
Asks for one frame of a project's current stored revision at an exact rational time, quality and viewport. The server reads the graph from project storage and resolves its sources for the caller; a request naming a superseded revision is refused with the current one. An identical request shares the render rather than starting a second one, and previews of superseded revisions are cancelled.
Authentication: API key. Permission: all.
Request body
Required.
Field definitions: StudioPreviewRequestDto
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewRequestDto"
}
}
}Responses
Field definitions: StudioPreviewResponseDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewResponseDto"
}
}
},
"description": ""
}
}Cancel a Studio preview
DELETE /api/studio/previews/{id}
Retires delivery of a preview. Scoped admissions require their captured consumer and operation identities; cancellation receipt facts distinguish durable request from renderer release. An active renderer directory is retained until genuine release.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
consumerRequestId | query | No | string |
expectedOperationId | query | No | Captured operation ID; literal string null explicitly names a never-enqueued admission. Omission and empty strings are not null. |
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "consumerRequestId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
}
},
{
"name": "expectedOperationId",
"required": false,
"in": "query",
"description": "Captured operation ID; literal string null explicitly names a never-enqueued admission. Omission and empty strings are not null.",
"schema": {
"anyOf": [
{
"type": "string",
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"
},
{
"type": "string",
"enum": [
"null"
]
}
]
}
},
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
Field definitions: StudioPreviewDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewDto"
}
}
},
"description": ""
}
}Get a Studio preview
GET /api/studio/previews/{id}
The state of one requested frame, including its revision-bound entity tag.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
consumerRequestId | query | No | string |
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "consumerRequestId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
}
},
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
Field definitions: StudioPreviewDto
{
"200": {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/StudioPreviewDto"
}
}
},
"description": ""
}
}View a Studio preview frame
GET /api/studio/previews/{id}/frame
Returns the rendered frame. The entity tag contains the project revision, so a frame whose revision has been superseded is refused with 409 rather than served or revalidated.
Authentication: API key. Permission: all.
Parameters
| Name | Where | Required | Description |
|---|---|---|---|
consumerRequestId | query | No | string |
id | path | Yes | string |
Parameter types, defaults and constraints
[
{
"name": "consumerRequestId",
"required": false,
"in": "query",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$",
"type": "string"
}
},
{
"name": "id",
"required": true,
"in": "path",
"schema": {
"format": "uuid",
"pattern": "^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-7[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$",
"type": "string"
}
}
]Responses
{
"200": {
"content": {
"application/octet-stream": {
"schema": {
"format": "binary",
"type": "string"
}
}
},
"description": ""
}
}© 2026 Frameleaf Inc. All rights reserved.
Frameleaf and the Frameleaf logo are Trademarks of Frameleaf Inc.