# Studio previews API

Source: https://frameleaf.app/docs/api/reference/studio-previews/

Use your own server and its scoped API keys.

## 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.

```json
{
  "description": "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.",
  "operationId": "openStudioPreviewStream",
  "parameters": [],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/StudioPreviewStreamOpenDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "201": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewStreamDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Open a Studio preview stream",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## Close a Studio preview stream

DELETE /api/studio/preview-streams/{id}

Ends the session; the worker stops sending on its next signalling poll.

```json
{
  "description": "Ends the session; the worker stops sending on its next signalling poll.",
  "operationId": "closeStudioPreviewStream",
  "parameters": [
    {
      "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/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewStreamDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Close a Studio preview stream",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "getStudioPreviewStream",
  "parameters": [
    {
      "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/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewStreamDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Get a Studio preview stream",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "answerStudioPreviewStream",
  "parameters": [
    {
      "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"
      }
    }
  ],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/StudioPreviewStreamAnswerDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewStreamDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Answer a Studio preview stream",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "reconnectStudioPreviewStream",
  "parameters": [
    {
      "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/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewStreamDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Reconnect a Studio preview stream",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "requestStudioPreview",
  "parameters": [],
  "requestBody": {
    "content": {
      "application/json": {
        "schema": {
          "$ref": "#/components/schemas/StudioPreviewRequestDto"
        }
      }
    },
    "required": true
  },
  "responses": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewResponseDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Request a Studio preview frame",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "cancelStudioPreview",
  "parameters": [
    {
      "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": {
    "200": {
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Cancel a Studio preview",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## Get a Studio preview

GET /api/studio/previews/{id}

The state of one requested frame, including its revision-bound entity tag.

```json
{
  "description": "The state of one requested frame, including its revision-bound entity tag.",
  "operationId": "getStudioPreview",
  "parameters": [
    {
      "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/json": {
          "schema": {
            "$ref": "#/components/schemas/StudioPreviewDto"
          }
        }
      },
      "description": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "Get a Studio preview",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```

## 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.

```json
{
  "description": "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.",
  "operationId": "viewStudioPreviewFrame",
  "parameters": [
    {
      "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": ""
    }
  },
  "security": [
    {
      "api_key": []
    }
  ],
  "summary": "View a Studio preview frame",
  "tags": [
    "Studio previews"
  ],
  "x-frameleaf-permission": "all"
}
```
