{
  "openapi": "3.1.0",
  "info": {
    "title": "Ignite REST API",
    "version": "1.0.0",
    "summary": "Upload, manage and deliver videos with Ignite.",
    "description": "OpenAPI specification for the Ignite REST API (video hosting and streaming).\nHuman-readable documentation with examples: https://docs.ignite.video\n\n**Authentication:** Create an API key on the API Integrations page in the Ignite admin UI\n(admin role required) and send it as a Bearer token. A missing or invalid key is rejected\nwith **403** and `{ \"errors\": [{ \"message\": \"You are not allowed to perform this action\" }] }`.\nThe API does not return 401 for API keys.\n\n**Permissions** are granted per resource: `videos.read|create|update|delete|publish`,\n`categories.create|update|delete`, `tags.create|update|delete`. Read access to categories\nand tags is always granted. `videos.publish` is separate from create and update.\n\n**Publishing:** `visibility: public` is stored only when the key has `videos.publish`.\nWithout it, create stores `private`, and a PATCH that sets `visibility` is accepted but\nthe field is left unchanged. Neither case returns 403.\n\n**Category scope:** A key can optionally be limited to one or more categories. The scope\nincludes those categories and their subcategories. It filters video reads and writes, and\ncategory reads, updates, and deletes. A scoped key cannot delete its own scope anchors.\nCreating a video with no categories assigns the scope categories (up to 10). Tags are not\ncategory-scoped.\n\n**Upload flow:** `PUT /videos/upload` creates the video (`status: NO_FILE`) and returns a\nsigned URL that expires after 1 hour. `PUT` the file to that URL with the file MIME type\nas `Content-Type`. For large files, set `useMultipart: true` (recommended above 100 MB;\nthe API does not enforce that threshold). Part URLs expire after 6 hours. Encoding starts\nafter the upload finishes; poll `GET /videos/{videoId}`.\n",
    "contact": {
      "name": "Ignite",
      "url": "https://ignite.video/en/contact"
    }
  },
  "servers": [
    {
      "url": "https://app.ignitevideo.cloud/api",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Videos"
    },
    {
      "name": "Upload",
      "description": "Single and multipart upload, file replacement"
    },
    {
      "name": "Thumbnails"
    },
    {
      "name": "Text tracks",
      "description": "Subtitles and captions (WebVTT). Requires a video that has finished encoding."
    },
    {
      "name": "Categories"
    },
    {
      "name": "Tags"
    }
  ],
  "paths": {
    "/videos": {
      "get": {
        "tags": [
          "Videos"
        ],
        "operationId": "listVideos",
        "summary": "List videos",
        "description": "Paginated list. Requires `videos.read`. API keys can read videos in `NO_FILE`.\nDefault `limit` is 10. When `depth` is omitted, `categories` and `tags` are objects;\n`depth=0` returns ids. `workspace` is always the workspace id.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Where"
          },
          {
            "$ref": "#/components/parameters/Depth"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of videos",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "docs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Video"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/{videoId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/VideoId"
        }
      ],
      "get": {
        "tags": [
          "Videos"
        ],
        "operationId": "getVideo",
        "summary": "Get a video",
        "description": "Requires `videos.read`. A missing id returns 404.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Depth"
          }
        ],
        "responses": {
          "200": {
            "description": "The video object",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Videos"
        ],
        "operationId": "updateVideo",
        "summary": "Update a video",
        "description": "Requires `videos.update`. Send only the fields to change.\n\nAn API key can write: `title` (max 150), `description` (max 2000), `language`,\n`aiContent`, `categories`, `tags`, `customMetadata`, `chapters`,\n`autoTranscription.autoStart`, `player.useCustomDesign`, `player.selectedPreset`,\n`player.playerDesign`, and, when the workspace has password protection,\n`passwordProtection`. `visibility` is written only with `videos.publish`; otherwise\nit is ignored and the response is still 200.\n\nUnknown category or tag ids are dropped. If none remain, the field is `null`.\n`texttracks`, `audiotracks`, `status`, and file fields are ignored.\nA missing id returns 403, not 404.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VideoUpdate"
              },
              "example": {
                "title": "New video title"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated video",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoDocMessage"
                },
                "example": {
                  "doc": {
                    "id": "507f1f77bcf86cd799439011",
                    "title": "New video title"
                  },
                  "message": "Updated successfully."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "tags": [
          "Videos"
        ],
        "operationId": "deleteVideo",
        "summary": "Delete a video",
        "description": "Requires `videos.delete`. Returns `{ doc, message }` with\n`message` = `Deleted successfully.`. A missing id returns 403, not 404.\n",
        "responses": {
          "200": {
            "description": "The deleted video",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VideoDocMessage"
                },
                "example": {
                  "doc": {
                    "id": "507f1f77bcf86cd799439011"
                  },
                  "message": "Deleted successfully."
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/upload": {
      "put": {
        "tags": [
          "Upload"
        ],
        "operationId": "createVideo",
        "summary": "Create a video and request an upload URL",
        "description": "Requires `videos.create`. `title` is required, trimmed, and cut to 100 characters.\nOptional: `description` (max 2000), `visibility`, `categories` (max 10 ids),\n`tags` (max 20 ids), `language`, `autoTranscribe`, `customMetadata`, `duration`,\n`fps`, `orientation`, `useMultipart`.\n\n`visibility: public` without `videos.publish` is stored as `private`.\n`autoTranscribe: true` requires a supported `language` (for example `de-DE`).\nThere is no `mimeType` field; set `Content-Type` on the upload `PUT` to the signed URL.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VideoCreate"
              },
              "examples": {
                "single": {
                  "summary": "Single-file upload",
                  "value": {
                    "title": "Your video title",
                    "visibility": "private"
                  }
                },
                "multipart": {
                  "summary": "Multipart upload",
                  "value": {
                    "title": "Your video title",
                    "useMultipart": true,
                    "categories": [
                      "category-id"
                    ],
                    "tags": [
                      "tag-id"
                    ]
                  }
                },
                "autoTranscribe": {
                  "summary": "Start AI transcription after encoding",
                  "value": {
                    "title": "Your video title",
                    "language": "de-DE",
                    "autoTranscribe": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Video created and upload instructions returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadInitResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/upload/{videoId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/VideoId"
        }
      ],
      "put": {
        "tags": [
          "Upload"
        ],
        "operationId": "replaceVideoFile",
        "summary": "Replace the video file",
        "description": "Requires `videos.update` on that video. Sets `status` to `REPLACING` and returns a\nsigned URL, or multipart identifiers when the body sets `useMultipart: true`.\nThe body is optional. A missing video returns 400 `{ \"error\": \"not_found\" }`,\nnot 404. An id that is not 24 hex characters returns 400 `{ \"error\": \"invalid_video_id\" }`.\n",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "useMultipart": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload instructions for the replacement file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UploadInitResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/upload/s3/multipart/{uploadId}/prepare-parts": {
      "parameters": [
        {
          "$ref": "#/components/parameters/UploadId"
        },
        {
          "$ref": "#/components/parameters/S3Key"
        }
      ],
      "post": {
        "tags": [
          "Upload"
        ],
        "operationId": "prepareMultipartParts",
        "summary": "Get signed URLs for multipart parts",
        "description": "Requires `videos.update` on the video identified by `key` (`videos/{videoId}/video`).\nReturns up to 100 part URLs. Each URL expires after 6 hours (`expires` is seconds).\nUpload each part with `PUT`. Every part except the last must be at least 5 MB.\nKeep the `ETag` response header, including quotes.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "required": [
                      "startPart",
                      "endPart"
                    ],
                    "properties": {
                      "startPart": {
                        "type": "integer",
                        "minimum": 1
                      },
                      "endPart": {
                        "type": "integer",
                        "minimum": 1
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "partNumbers"
                    ],
                    "properties": {
                      "partNumbers": {
                        "type": "array",
                        "maxItems": 100,
                        "items": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 10000
                        }
                      }
                    }
                  }
                ]
              },
              "example": {
                "startPart": 1,
                "endPart": 2
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Signed part URLs",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "parts",
                    "expires"
                  ],
                  "properties": {
                    "parts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "partNumber",
                          "url"
                        ],
                        "properties": {
                          "partNumber": {
                            "type": "integer"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          }
                        }
                      }
                    },
                    "expires": {
                      "type": "integer",
                      "description": "Lifetime of each part URL, in seconds (21600).",
                      "example": 21600
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/upload/s3/multipart/{uploadId}/complete": {
      "parameters": [
        {
          "$ref": "#/components/parameters/UploadId"
        },
        {
          "$ref": "#/components/parameters/S3Key"
        }
      ],
      "post": {
        "tags": [
          "Upload"
        ],
        "operationId": "completeMultipartUpload",
        "summary": "Complete a multipart upload",
        "description": "Requires `videos.update` on the video in `key`. Pass `parts` sorted by part number,\nor `fetchPartsFromStorage: true` to let the server read the parts from storage.\nEncoding starts after a successful complete.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "type": "object",
                    "required": [
                      "parts"
                    ],
                    "properties": {
                      "parts": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "required": [
                            "PartNumber",
                            "ETag"
                          ],
                          "properties": {
                            "PartNumber": {
                              "type": "integer"
                            },
                            "ETag": {
                              "type": "string",
                              "description": "Value of the part `ETag` header, including quotes."
                            }
                          }
                        }
                      }
                    }
                  },
                  {
                    "type": "object",
                    "required": [
                      "fetchPartsFromStorage"
                    ],
                    "properties": {
                      "fetchPartsFromStorage": {
                        "type": "boolean",
                        "const": true
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Upload completed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "key",
                    "etag"
                  ],
                  "properties": {
                    "success": {
                      "type": "boolean",
                      "const": true
                    },
                    "key": {
                      "type": "string"
                    },
                    "etag": {
                      "type": "string",
                      "description": "S3 ETag of the assembled object. Includes `-{partCount}` for multipart."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "description": "S3 could not complete the upload",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EndpointError"
                }
              }
            }
          }
        }
      }
    },
    "/videos/{videoId}/thumbnail": {
      "parameters": [
        {
          "$ref": "#/components/parameters/VideoId"
        }
      ],
      "put": {
        "tags": [
          "Thumbnails"
        ],
        "operationId": "uploadThumbnail",
        "summary": "Upload a custom thumbnail",
        "description": "Requires `videos.update`. The video must already be encoded (`status: COMPLETE`).\nSend a JPEG or PNG as multipart field `file`. The image is resized to variants up to\nthe video's resolution. The response is the video object itself, not `{ doc, message }`.\nA video that is still encoding, or a missing video, returns 400.\n",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              },
              "encoding": {
                "file": {
                  "contentType": "image/jpeg, image/png"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The video, with updated `src.thumbnails`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "tags": [
          "Thumbnails"
        ],
        "operationId": "resetThumbnail",
        "summary": "Reset the thumbnail",
        "description": "Requires `videos.update` and an encoded video. Restores the generated thumbnail.\nReturns the video object. A missing video returns 400.\n",
        "responses": {
          "200": {
            "description": "The video, with restored `src.thumbnails`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/{videoId}/texttracks": {
      "parameters": [
        {
          "$ref": "#/components/parameters/VideoId"
        }
      ],
      "put": {
        "tags": [
          "Text tracks"
        ],
        "operationId": "createTextTrack",
        "summary": "Create a text track",
        "description": "Requires `videos.update` and an encoded video. `language` must be a supported locale\nsuch as `en-US` or `de-DE` (`en` is rejected). `type` is `subtitles` or `captions`.\nSend WebVTT as JSON `content` or as multipart field `file`.\n\nThe 200 body is the track. Its `content` property is a deprecated placeholder, not the\nuploaded VTT. Use `GET /videos/{videoId}/texttracks/{texttrackId}` for the real file.\nA missing or not-yet-encoded video returns 400, not 404.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TextTrackInput"
              },
              "example": {
                "language": "en-US",
                "type": "captions",
                "content": "WEBVTT\n\n00:00:00.000 --> 00:00:02.000\nHello"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/TextTrackFileInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The created text track",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextTrack"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/videos/{videoId}/texttracks/{texttrackId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/VideoId"
        },
        {
          "name": "texttrackId",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "get": {
        "tags": [
          "Text tracks"
        ],
        "operationId": "getTextTrack",
        "summary": "Get a text track, including VTT content",
        "description": "Requires `videos.read`. `content` is the WebVTT text. A missing track returns 400,\nnot 404.\n",
        "responses": {
          "200": {
            "description": "The text track, with VTT `content`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextTrack"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "patch": {
        "tags": [
          "Text tracks"
        ],
        "operationId": "updateTextTrack",
        "summary": "Update a text track",
        "description": "Requires `videos.update`. `language`, `type`, and `content` are all optional.\nA metadata-only body (for example `{ \"type\": \"subtitles\" }`) is valid.\nThe response `content` is the deprecated placeholder. Use GET for the VTT.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TextTrackPatch"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/TextTrackFilePatch"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The updated text track",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TextTrack"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "tags": [
          "Text tracks"
        ],
        "operationId": "deleteTextTrack",
        "summary": "Delete a text track",
        "description": "Requires `videos.update` and an encoded video. Returns the video object\n(not `{ doc, message }`) with the track removed. A missing track returns 400.\n",
        "responses": {
          "200": {
            "description": "The video, without the deleted track",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Video"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/EndpointError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/categories": {
      "get": {
        "tags": [
          "Categories"
        ],
        "operationId": "listCategories",
        "summary": "List categories",
        "description": "Read access is always granted. A category-scoped key only sees its scope and\nsubcategories. Default sort is `title`. Default `limit` is 10.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Where"
          },
          {
            "$ref": "#/components/parameters/Depth"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of categories",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "docs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Category"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Categories"
        ],
        "operationId": "createCategory",
        "summary": "Create a category",
        "description": "Requires `categories.create`. `title` is required (max 100). `slug` is generated from\n`title` when omitted. `description` max 2000. `parent` is a category id.\nReturns 201 `{ doc, message }` with `message` = `Category successfully created.`\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryInput"
              },
              "example": {
                "title": "Your category title",
                "description": "Optional description"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryDocMessage"
                },
                "example": {
                  "doc": {
                    "id": "507f1f77bcf86cd799439012",
                    "title": "Your category title",
                    "slug": "your-category-title"
                  },
                  "message": "Category successfully created."
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/categories/{categoryId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/CategoryId"
        }
      ],
      "get": {
        "tags": [
          "Categories"
        ],
        "operationId": "getCategory",
        "summary": "Get a category",
        "description": "Returns the category. A missing id returns 404.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Depth"
          }
        ],
        "responses": {
          "200": {
            "description": "The category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Category"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Categories"
        ],
        "operationId": "updateCategory",
        "summary": "Update a category",
        "description": "Requires `categories.update`. Writable fields are `title`, `slug`, `description`,\nand `parent`. Returns `{ doc, message }` with `message` = `Updated successfully.`\nA missing id returns 403, not 404.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CategoryInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryDocMessage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "tags": [
          "Categories"
        ],
        "operationId": "deleteCategory",
        "summary": "Delete a category",
        "description": "Requires `categories.delete`. Returns `{ doc, message }` with\n`message` = `Deleted successfully.` A scoped key cannot delete a category that is\none of its scope anchors. A missing id returns 403, not 404.\n",
        "responses": {
          "200": {
            "description": "Deleted category",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CategoryDocMessage"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/tags": {
      "get": {
        "tags": [
          "Tags"
        ],
        "operationId": "listTags",
        "summary": "List tags",
        "description": "Read access is always granted. Tags are not affected by category scope.",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Sort"
          },
          {
            "$ref": "#/components/parameters/Where"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of tags",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/PaginatedResponse"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "docs": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/Tag"
                          }
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "Tags"
        ],
        "operationId": "createTag",
        "summary": "Create a tag",
        "description": "Requires `tags.create`. `title` is required. `slug` is generated from `title` when\nomitted. Returns 201 `{ doc, message }` with `message` = `Tag successfully created.`\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagInput"
              },
              "example": {
                "title": "Your tag title"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The created tag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TagDocMessage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    },
    "/tags/{tagId}": {
      "parameters": [
        {
          "$ref": "#/components/parameters/TagId"
        }
      ],
      "get": {
        "tags": [
          "Tags"
        ],
        "operationId": "getTag",
        "summary": "Get a tag",
        "responses": {
          "200": {
            "description": "The tag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Tag"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "patch": {
        "tags": [
          "Tags"
        ],
        "operationId": "updateTag",
        "summary": "Update a tag",
        "description": "Requires `tags.update`. Writable fields are `title`, `slug`, and `description`.\nReturns `{ doc, message }`. A missing id returns 403, not 404.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TagInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated tag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TagDocMessage"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationError"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "delete": {
        "tags": [
          "Tags"
        ],
        "operationId": "deleteTag",
        "summary": "Delete a tag",
        "description": "Requires `tags.delete`. Returns `{ doc, message }` with\n`message` = `Deleted successfully.` A missing id returns 403, not 404.\n",
        "responses": {
          "200": {
            "description": "Deleted tag",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TagDocMessage"
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      }
    }
  },
  "webhooks": {
    "videoEvent": {
      "post": {
        "summary": "Video lifecycle event",
        "description": "Webhook subscriptions are configured in the Ignite admin UI, not via this API.\nIgnite sends a `POST` whose body is the video object without `player`.\nEvent types: `video.created`, `video.updated` (metadata, encoding progress, and\ncompletion), `video.deleted` (the object as it existed before deletion).\n\nVerify `X-Webhook-Signature` (`t=<unix ms>,v1=<hex>`):\n`HMAC-SHA256(t + \".\" + raw_body, signing_secret)`.\n",
        "parameters": [
          {
            "name": "X-Webhook-Event",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "video.created",
                "video.updated",
                "video.deleted"
              ]
            }
          },
          {
            "name": "X-Webhook-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string",
              "example": "t=1705316400000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Video"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Return any 2xx status to acknowledge receipt."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from the Ignite admin UI (API Integrations)."
      }
    },
    "parameters": {
      "VideoId": {
        "name": "videoId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-fA-F0-9]{24}$"
        },
        "example": "507f1f77bcf86cd799439011"
      },
      "CategoryId": {
        "name": "categoryId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-fA-F0-9]{24}$"
        }
      },
      "TagId": {
        "name": "tagId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "pattern": "^[a-fA-F0-9]{24}$"
        }
      },
      "UploadId": {
        "name": "uploadId",
        "in": "path",
        "required": true,
        "description": "`multipartUpload.uploadId` from `PUT /videos/upload`",
        "schema": {
          "type": "string"
        }
      },
      "S3Key": {
        "name": "key",
        "in": "query",
        "required": true,
        "description": "`multipartUpload.key` from `PUT /videos/upload` (URL-encoded). Must match `videos/{videoId}/video`.",
        "schema": {
          "type": "string"
        }
      },
      "Page": {
        "name": "page",
        "in": "query",
        "description": "Page number. Default 1.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "description": "Page size. Default 10.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Sort": {
        "name": "sort",
        "in": "query",
        "description": "Field to sort by. Prefix with `-` for descending order, e.g. `-createdAt`.",
        "schema": {
          "type": "string"
        }
      },
      "Depth": {
        "name": "depth",
        "in": "query",
        "description": "Relationship population. Omit it to receive `categories` and `tags` as objects.\n`0` returns ids only. `workspace` stays an id either way.\n",
        "schema": {
          "type": "integer",
          "minimum": 0
        }
      },
      "Where": {
        "name": "where",
        "in": "query",
        "description": "Filter in bracket notation, e.g. `where[status][equals]=COMPLETE`.\nSee https://docs.ignite.video/api-reference/querying for operators.\n",
        "style": "deepObject",
        "explode": true,
        "schema": {
          "type": "object",
          "additionalProperties": true
        }
      }
    },
    "responses": {
      "Forbidden": {
        "description": "Missing or invalid API key, missing permission, or outside category scope.\nFor collection update and delete, a missing id also returns this status.\nBody is `{ \"errors\": [{ \"message\": \"You are not allowed to perform this action\" }] }`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PayloadError"
            }
          }
        }
      },
      "NotFound": {
        "description": "GET of a missing document. Body is `{ \"errors\": [{ \"message\": \"Not Found\" }] }`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PayloadError"
            }
          }
        }
      },
      "ValidationError": {
        "description": "A field failed validation. Body is `{ \"errors\": [{ \"message\": \"<detail>\" }] }`.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/PayloadError"
            }
          }
        }
      },
      "EndpointError": {
        "description": "Custom endpoint error. Body is `{ \"error\": \"<code or sentence>\", \"message\"?: \"<detail>\" }`.\nPermission failures use 403.\n",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/EndpointError"
            }
          }
        }
      }
    },
    "schemas": {
      "PayloadError": {
        "type": "object",
        "required": [
          "errors"
        ],
        "properties": {
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "message"
              ],
              "properties": {
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "EndpointError": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "success": {
            "type": "boolean"
          }
        }
      },
      "PaginatedResponse": {
        "type": "object",
        "required": [
          "docs",
          "totalDocs",
          "limit",
          "totalPages",
          "page",
          "pagingCounter",
          "hasPrevPage",
          "hasNextPage"
        ],
        "properties": {
          "docs": {
            "type": "array",
            "items": {}
          },
          "totalDocs": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "page": {
            "type": "integer"
          },
          "pagingCounter": {
            "type": "integer"
          },
          "hasPrevPage": {
            "type": "boolean"
          },
          "hasNextPage": {
            "type": "boolean"
          },
          "prevPage": {
            "type": [
              "integer",
              "null"
            ]
          },
          "nextPage": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "VideoStatus": {
        "type": "string",
        "enum": [
          "NO_FILE",
          "PROGRESSING",
          "REPLACING",
          "COMPLETE",
          "ERROR"
        ],
        "description": "NO_FILE: object exists, no file uploaded yet. PROGRESSING: encoding in progress.\nREPLACING: replacement file is being uploaded. COMPLETE: playback sources are in `src`.\nERROR: encoding failed. See `errorCode` and `errorMessage`.\n"
      },
      "Visibility": {
        "type": "string",
        "enum": [
          "public",
          "private"
        ]
      },
      "CustomMetadata": {
        "type": "object",
        "maxProperties": 50,
        "propertyNames": {
          "pattern": "^[a-zA-Z0-9_-]+$",
          "maxLength": 40
        },
        "description": "Flat object, at most 50 keys. Keys match `^[a-zA-Z0-9_-]+$` and are at most 40\ncharacters. Values are strings (max 500), finite numbers, or booleans. Nested objects\nand arrays are rejected. A later write merges onto the stored object. Sending `\"\"`\nor `null` for a key deletes that key. Omitted keys are kept.\n",
        "additionalProperties": {
          "oneOf": [
            {
              "type": "string",
              "maxLength": 500
            },
            {
              "type": "number"
            },
            {
              "type": "boolean"
            },
            {
              "type": "null",
              "description": "Deletes the key on write."
            }
          ]
        }
      },
      "VideoCreate": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "description": "Trimmed and cut to 100 characters."
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "visibility": {
            "$ref": "#/components/schemas/Visibility"
          },
          "categories": {
            "type": "array",
            "maxItems": 10,
            "description": "Category ids. Unknown ids are dropped.",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "type": "array",
            "maxItems": 20,
            "description": "Tag ids. Unknown ids are dropped.",
            "items": {
              "type": "string"
            }
          },
          "language": {
            "type": "string",
            "description": "Spoken-language tag, for example `de-DE` or `en-US`.",
            "example": "de-DE"
          },
          "autoTranscribe": {
            "type": "boolean",
            "description": "Start AI transcription after encoding. Requires a supported `language`."
          },
          "customMetadata": {
            "$ref": "#/components/schemas/CustomMetadata"
          },
          "duration": {
            "type": "number",
            "description": "Optional hint in seconds. Encoding overwrites it."
          },
          "fps": {
            "type": "number",
            "description": "Optional hint. Encoding overwrites it."
          },
          "orientation": {
            "type": "string",
            "enum": [
              "landscape",
              "portrait"
            ],
            "description": "Optional hint. Encoding overwrites it."
          },
          "useMultipart": {
            "type": "boolean",
            "description": "Return multipart upload identifiers instead of a single signed URL."
          }
        }
      },
      "VideoUpdate": {
        "type": "object",
        "description": "Send only the fields to change. Other properties are ignored.",
        "properties": {
          "title": {
            "type": "string",
            "minLength": 1,
            "maxLength": 150
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "visibility": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Visibility"
              }
            ],
            "description": "Applied only when the key has `videos.publish`."
          },
          "categories": {
            "type": "array",
            "description": "Replaces the category list. Unknown ids are dropped. An empty result is stored as null.",
            "items": {
              "type": "string"
            }
          },
          "tags": {
            "type": "array",
            "description": "Replaces the tag list. Unknown ids are dropped. An empty result is stored as null.",
            "items": {
              "type": "string"
            }
          },
          "language": {
            "type": "string",
            "description": "Spoken-language tag, for example `en-US`. The API currently stores other strings as well."
          },
          "aiContent": {
            "type": "string",
            "enum": [
              "none",
              "generated",
              "modified"
            ]
          },
          "customMetadata": {
            "$ref": "#/components/schemas/CustomMetadata"
          },
          "chapters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChapterInput"
            }
          },
          "autoTranscription": {
            "type": "object",
            "properties": {
              "autoStart": {
                "type": "boolean",
                "description": "Start AI transcription after the next encode when true."
              }
            }
          },
          "player": {
            "type": "object",
            "properties": {
              "useCustomDesign": {
                "type": "boolean"
              },
              "selectedPreset": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Player preset id."
              },
              "playerDesign": {
                "type": "object",
                "additionalProperties": true
              }
            }
          },
          "passwordProtection": {
            "type": "object",
            "description": "Written only when the workspace has video password protection.",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "password": {
                "type": "string",
                "minLength": 8
              }
            }
          }
        }
      },
      "UploadInitResponse": {
        "type": "object",
        "required": [
          "videoId"
        ],
        "properties": {
          "videoId": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "description": "Present on create. The stored title, after trim and the 100-character cut."
          },
          "signedUrl": {
            "type": "string",
            "format": "uri",
            "description": "Present for a single-file upload. Expires after 1 hour. PUT the bytes with the file MIME type as Content-Type."
          },
          "multipartUpload": {
            "type": "object",
            "description": "Present when `useMultipart` is true.",
            "required": [
              "uploadId",
              "key"
            ],
            "properties": {
              "uploadId": {
                "type": "string"
              },
              "key": {
                "type": "string",
                "example": "videos/507f1f77bcf86cd799439011/video"
              }
            }
          }
        }
      },
      "VideoDocMessage": {
        "type": "object",
        "required": [
          "doc",
          "message"
        ],
        "properties": {
          "doc": {
            "$ref": "#/components/schemas/Video"
          },
          "message": {
            "type": "string",
            "examples": [
              "Updated successfully.",
              "Deleted successfully."
            ]
          }
        }
      },
      "ThumbnailVariant": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Resolution label. Generated sizes are 2160p, 1440p, 1080p, 720p, 480p, 360p, and 240p, capped at the source.",
            "enum": [
              "2160p",
              "1440p",
              "1080p",
              "720p",
              "480p",
              "360p",
              "240p"
            ]
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          },
          "formats": {
            "type": "object",
            "properties": {
              "jpeg": {
                "$ref": "#/components/schemas/ImageFile"
              },
              "webp": {
                "$ref": "#/components/schemas/ImageFile"
              }
            }
          }
        }
      },
      "ImageFile": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "fileSize": {
            "type": "integer"
          }
        }
      },
      "VideoSource": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "enum": [
              "2160p",
              "1440p",
              "1080p",
              "720p",
              "540p",
              "360p",
              "240p"
            ]
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "width": {
            "type": "integer"
          },
          "height": {
            "type": "integer"
          }
        }
      },
      "Chapter": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "maxLength": 100
          },
          "timestamp": {
            "type": "string",
            "description": "HH:MM:SS",
            "pattern": "^\\d{2}:\\d{2}:\\d{2}$"
          }
        }
      },
      "ChapterInput": {
        "type": "object",
        "required": [
          "title",
          "timestamp"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 100
          },
          "timestamp": {
            "type": "string",
            "pattern": "^\\d{2}:\\d{2}:\\d{2}$"
          }
        }
      },
      "TaxonomyRef": {
        "type": "object",
        "description": "Category or tag as nested on a video at the default depth. `depth=0` returns the id string instead.",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          }
        }
      },
      "Video": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "status": {
            "$ref": "#/components/schemas/VideoStatus"
          },
          "statusProgress": {
            "type": "number",
            "description": "Encoding progress in percent."
          },
          "errorCode": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set when `status` is `ERROR`. Examples include DURATION_LIMIT_EXCEEDED,\nUNKNOWN_ERROR, and MEDIACONVERT_1040 (unsupported format). New codes can appear.\n"
          },
          "errorMessage": {
            "type": [
              "string",
              "null"
            ]
          },
          "visibility": {
            "$ref": "#/components/schemas/Visibility"
          },
          "v": {
            "type": "number",
            "description": "File version. Starts at 0 and increments when a replacement finishes encoding."
          },
          "contentUpdatedAt": {
            "type": "string",
            "format": "date-time",
            "description": "Bumped on content writes. Not writable."
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "duration": {
            "type": "number",
            "description": "Duration in seconds. Filled when encoding completes."
          },
          "fps": {
            "type": "number"
          },
          "orientation": {
            "type": "string",
            "enum": [
              "landscape",
              "portrait"
            ]
          },
          "language": {
            "type": "string"
          },
          "aiContent": {
            "type": "string",
            "enum": [
              "none",
              "generated",
              "modified"
            ],
            "description": "AI content label (EU AI Act Art. 50)."
          },
          "categories": {
            "description": "Objects at the default depth, id strings at `depth=0`, or null when empty.",
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TaxonomyRef"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "tags": {
            "description": "Objects at the default depth, id strings at `depth=0`, or null when empty.",
            "oneOf": [
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/TaxonomyRef"
                    },
                    {
                      "type": "string"
                    }
                  ]
                }
              },
              {
                "type": "null"
              }
            ]
          },
          "customMetadata": {
            "$ref": "#/components/schemas/CustomMetadata"
          },
          "src": {
            "type": "object",
            "description": "Empty until encoding completes.",
            "properties": {
              "filename": {
                "type": "string"
              },
              "thumbnailUrl": {
                "type": "string",
                "format": "uri",
                "deprecated": true,
                "description": "1080p JPEG of the active thumbnail. Use `src.thumbnails`."
              },
              "thumbnails": {
                "type": "array",
                "description": "Active thumbnail variants, highest resolution first.",
                "items": {
                  "$ref": "#/components/schemas/ThumbnailVariant"
                }
              },
              "abr": {
                "type": "object",
                "description": "Adaptive bitrate HLS master playlist.",
                "properties": {
                  "resolution": {
                    "type": "string",
                    "example": "auto"
                  },
                  "description": {
                    "type": "string"
                  },
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "maxWidth": {
                    "type": "integer"
                  },
                  "maxHeight": {
                    "type": "integer"
                  }
                }
              },
              "hls": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/VideoSource"
                }
              },
              "mp4": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/VideoSource"
                }
              },
              "audio": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "name": {
                      "type": "string",
                      "description": "For example `high-quality` or `low-quality`."
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "texttracks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TextTrackSummary"
            }
          },
          "chapters": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Chapter"
            }
          },
          "audiotracks": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "transcriptions": {
            "type": "array",
            "description": "Derived transcript view. Not writable.",
            "items": {
              "type": "object",
              "properties": {
                "language": {
                  "type": "string"
                },
                "autoGenerated": {
                  "type": "boolean"
                },
                "text": {
                  "type": "string"
                },
                "segments": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "startTime": {
                        "type": "number"
                      },
                      "endTime": {
                        "type": "number"
                      },
                      "text": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "autoTranscription": {
            "type": "object",
            "properties": {
              "autoStart": {
                "type": "boolean"
              },
              "lastUpdatedAt": {
                "type": "string",
                "format": "date-time"
              },
              "data": {
                "description": "Related transcription records, populated according to `depth`."
              }
            }
          },
          "player": {
            "type": "object",
            "description": "Included on API-key reads. Omitted from webhook payloads.",
            "properties": {
              "selectedPreset": {
                "description": "Preset object, or absent when none is selected."
              },
              "useCustomDesign": {
                "type": "boolean"
              },
              "playerDesign": {
                "type": "object",
                "additionalProperties": true
              },
              "shareUrl": {
                "type": "string",
                "format": "uri",
                "description": "Embed player URL. Use as an iframe `src` or share link."
              }
            }
          },
          "passwordProtection": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean"
              },
              "password": {
                "type": "string",
                "description": "Present for callers who can update the video when the feature is enabled."
              }
            }
          },
          "previewVideoUrl": {
            "type": "string",
            "format": "uri",
            "description": "Signed preview URL, added on read when renditions exist."
          },
          "previewThumbnailUrl": {
            "type": "string",
            "format": "uri"
          },
          "previewThumbnailUrlSmall": {
            "type": "string",
            "format": "uri"
          },
          "workspace": {
            "type": "string",
            "description": "Workspace id."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TextTrackType": {
        "type": "string",
        "enum": [
          "subtitles",
          "captions"
        ]
      },
      "TextTrackSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "language": {
            "type": "string",
            "example": "en-US"
          },
          "filename": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/TextTrackType"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "autoGenerated": {
            "type": "boolean"
          },
          "autoTranslated": {
            "type": "boolean"
          },
          "edited": {
            "type": "boolean"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "content": {
            "type": "string",
            "description": "On a video object, and on create or update responses, this is a URL-encoded\ndeprecated placeholder. It is not the uploaded WebVTT. GET the track for the file.\n"
          }
        }
      },
      "TextTrack": {
        "allOf": [
          {
            "$ref": "#/components/schemas/TextTrackSummary"
          },
          {
            "type": "object",
            "properties": {
              "content": {
                "type": "string",
                "description": "On GET, the WebVTT document. On create and update responses, the deprecated placeholder.\n"
              }
            }
          }
        ]
      },
      "TextTrackInput": {
        "type": "object",
        "required": [
          "language",
          "type",
          "content"
        ],
        "properties": {
          "language": {
            "type": "string",
            "description": "Supported locale, for example `en-US` or `de-DE`. `en` is rejected.",
            "example": "en-US"
          },
          "type": {
            "$ref": "#/components/schemas/TextTrackType"
          },
          "content": {
            "type": "string",
            "description": "WebVTT document."
          }
        }
      },
      "TextTrackPatch": {
        "type": "object",
        "description": "All fields are optional. A metadata-only change does not require `content`.",
        "properties": {
          "language": {
            "type": "string",
            "example": "de-DE"
          },
          "type": {
            "$ref": "#/components/schemas/TextTrackType"
          },
          "content": {
            "type": "string",
            "description": "Replacement WebVTT document."
          }
        }
      },
      "TextTrackFileInput": {
        "type": "object",
        "required": [
          "language",
          "type",
          "file"
        ],
        "properties": {
          "language": {
            "type": "string",
            "example": "en-US"
          },
          "type": {
            "$ref": "#/components/schemas/TextTrackType"
          },
          "file": {
            "type": "string",
            "format": "binary",
            "description": "WebVTT file."
          }
        }
      },
      "TextTrackFilePatch": {
        "type": "object",
        "properties": {
          "language": {
            "type": "string"
          },
          "type": {
            "$ref": "#/components/schemas/TextTrackType"
          },
          "file": {
            "type": "string",
            "format": "binary"
          }
        }
      },
      "Breadcrumb": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "doc": {
            "type": "string",
            "description": "Category id this crumb points at. Sometimes absent on the create response."
          },
          "url": {
            "type": "string"
          },
          "label": {
            "type": "string"
          }
        }
      },
      "CategoryInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 100
          },
          "slug": {
            "type": "string",
            "description": "Generated from `title` when omitted."
          },
          "description": {
            "type": "string",
            "maxLength": 2000
          },
          "parent": {
            "type": "string",
            "description": "Parent category id."
          }
        }
      },
      "Category": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "parent": {
            "description": "Parent category object at the default depth, or absent for a root. `depth=0` returns the id."
          },
          "path": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Breadcrumb"
            }
          },
          "pathLabel": {
            "type": "string",
            "description": "Breadcrumb titles joined with ` / `."
          },
          "videoCount": {
            "type": "integer"
          },
          "videoCountWithSubcategories": {
            "type": "integer"
          },
          "workspace": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CategoryDocMessage": {
        "type": "object",
        "required": [
          "doc",
          "message"
        ],
        "properties": {
          "doc": {
            "$ref": "#/components/schemas/Category"
          },
          "message": {
            "type": "string"
          }
        }
      },
      "TagInput": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "description": "Generated from `title` when omitted."
          },
          "description": {
            "type": "string"
          }
        }
      },
      "Tag": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "workspace": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "TagDocMessage": {
        "type": "object",
        "required": [
          "doc",
          "message"
        ],
        "properties": {
          "doc": {
            "$ref": "#/components/schemas/Tag"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
