{
    "openapi": "3.0.2",
    "info": {
        "title": "JSON2Video API",
        "version": "2.0.0",
        "description": "Create and edit awesome videos programmatically"
    },
    "servers": [
        {
            "url": "https://api.json2video.com/v2",
            "description": "Version 2 endpoint"
        }
    ],
    "paths": {
        "/movies": {
            "get": {
                "operationId": "getMovies",
                "summary": "Get the status of your movies",
                "description": "Get the status of one of your movies by passing its project ID in the <code>project</code> (or <code>id</code>) query parameter, or list your movies within a date range. The project ID is returned in the response of POST /movies.",
                "parameters": [
                    {
                        "name": "project",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "minLength": 16, "maxLength": 16 },
                        "description": "16-character project ID returned by POST /movies. When set, returns the status of a single movie."
                    },
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "minLength": 16, "maxLength": 16 },
                        "description": "Alias for <code>project</code>."
                    },
                    {
                        "name": "from",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "format": "date-time" },
                        "description": "Start of the date range (ISO 8601). Defaults to the first day of the current month. Max range is 3 months. Alias: <code>date_start</code>."
                    },
                    {
                        "name": "to",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "format": "date-time" },
                        "description": "End of the date range (ISO 8601). Defaults to the end of the current day. Alias: <code>date_end</code>."
                    },
                    {
                        "name": "limit",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 100 },
                        "description": "Maximum number of movies returned per page."
                    },
                    {
                        "name": "next_token",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Pagination cursor returned by a previous call."
                    },
                    {
                        "name": "format",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "simple" ] },
                        "description": "When set to <code>simple</code>, the per-movie JSON payload is omitted from the response."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Movie status (single project) or paginated list of movies for the given date range.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "from": { "type": "string", "format": "date-time" },
                                        "to": { "type": "string", "format": "date-time" },
                                        "count": { "type": "integer" },
                                        "limit": { "type": "integer" },
                                        "has_next": { "type": "boolean" },
                                        "has_prev": { "type": "boolean" },
                                        "next_token": { "type": "string", "nullable": true },
                                        "movie": {
                                            "type": "object",
                                            "description": "Present when querying a single project."
                                        },
                                        "movies": {
                                            "type": "array",
                                            "description": "Present when listing movies in a date range.",
                                            "items": { "type": "object" }
                                        },
                                        "remaining_quota": {
                                            "type": "object",
                                            "properties": {
                                                "movies": { "type": "integer" },
                                                "drafts": { "type": "integer" },
                                                "time": { "type": "integer" }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": { "description": "Invalid or missing API key" }
                }
            },
            "post": {
                "operationId": "newMovie",
                "summary": "Create a new movie",
                "description": "Submit a new movie rendering job.",
                "responses": {
                    "200": {
                        "description": "Added"
                    }
                },
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/movie"
                            }
                        }
                    }
                }
            }
        },
        "/preloads": {
            "post": {
                "operationId": "newPreload",
                "summary": "Pre-generate or download a batch of assets",
                "description": "Asynchronously prepares assets that can be referenced in future movies via their public URL. The pipeline runs prepare-movie + downloads (parallel and AI lanes) and stores the final assets in the global per-client cache (shared with movies). Maximum 10 items per batch.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "preload" ],
                                "properties": {
                                    "preload": {
                                        "type": "array",
                                        "minItems": 1,
                                        "maxItems": 10,
                                        "description": "Array of assets to pre-generate or download. Each item must have a unique 'id' that the client uses to match results in GET responses.",
                                        "items": {
                                            "$ref": "#/components/schemas/preloadItem"
                                        }
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Batch accepted; the pipeline runs asynchronously. Use GET /preloads/{preload_id} to poll status.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "preload_id": {
                                            "type": "string",
                                            "description": "16-char identifier; pass to GET /preloads/{preload_id}"
                                        },
                                        "timestamp": {
                                            "type": "string",
                                            "format": "date-time"
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid request (schema error, duplicate id, type not allowed, etc.)"
                    },
                    "401": {
                        "description": "Invalid or missing API key"
                    },
                    "402": {
                        "description": "Insufficient credits to generate the AI assets in the batch"
                    }
                }
            }
        },
        "/preloads/{preload_id}": {
            "get": {
                "operationId": "getPreload",
                "summary": "Get the status and results of a preload batch",
                "description": "Returns the consolidated state of a batch submitted via POST /preloads. Items can be pending, running, ready or error; the batch is 'done' when all items reach a terminal state.",
                "parameters": [
                    {
                        "name": "preload_id",
                        "in": "path",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Identifier returned by POST /preloads."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Current state of the batch.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": {
                                            "type": "boolean"
                                        },
                                        "preload_id": {
                                            "type": "string"
                                        },
                                        "status": {
                                            "type": "string",
                                            "enum": [ "pending", "running", "done" ]
                                        },
                                        "created_at": {
                                            "type": "string",
                                            "format": "date-time",
                                            "nullable": true
                                        },
                                        "ended_at": {
                                            "type": "string",
                                            "format": "date-time",
                                            "nullable": true
                                        },
                                        "items": {
                                            "type": "array",
                                            "items": {
                                                "type": "object",
                                                "properties": {
                                                    "id": {
                                                        "type": "string"
                                                    },
                                                    "type": {
                                                        "type": "string"
                                                    },
                                                    "status": {
                                                        "type": "string",
                                                        "enum": [ "pending", "running", "ready", "error" ]
                                                    },
                                                    "url": {
                                                        "type": "string",
                                                        "format": "uri"
                                                    },
                                                    "duration": {
                                                        "type": "number"
                                                    },
                                                    "width": {
                                                        "type": "integer"
                                                    },
                                                    "height": {
                                                        "type": "integer"
                                                    },
                                                    "size": {
                                                        "type": "integer"
                                                    },
                                                    "task": {
                                                        "type": "string"
                                                    },
                                                    "error": {
                                                        "type": "string"
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "400": {
                        "description": "Invalid preload_id format"
                    },
                    "401": {
                        "description": "Invalid or missing API key"
                    },
                    "404": {
                        "description": "preload not found (or not owned by this client)"
                    }
                }
            }
        },
        "/templates": {
            "get": {
                "operationId": "getTemplates",
                "summary": "List templates or get a single template",
                "description": "Without query parameters, returns the list of templates owned by the authenticated client. When <code>id</code> is provided, returns a single template. The <code>format</code> parameter can transform the returned movie variables into Make.com field definitions or a JSON Schema.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Template ID. When set, returns the matching template instead of the list."
                    },
                    {
                        "name": "tag",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Filter the list to templates tagged with this value."
                    },
                    {
                        "name": "scopes",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "default": "movie" },
                        "description": "Comma-separated list of scopes to load for a single template (e.g. <code>movie,prompt</code>). Only applies when <code>id</code> is provided."
                    },
                    {
                        "name": "format",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "make", "jsonschema", "summary" ] },
                        "description": "Output format for the template's variables: <code>make</code> returns Make.com field definitions, <code>jsonschema</code> returns a JSON Schema, <code>summary</code> omits the movie payload."
                    },
                    {
                        "name": "shared",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "tools" ] },
                        "description": "Return a curated, publicly-shared list of templates instead of the user's own."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Template or list of templates.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "count": { "type": "integer" },
                                        "template": { "$ref": "#/components/schemas/template" },
                                        "templates": {
                                            "type": "array",
                                            "items": { "$ref": "#/components/schemas/template" }
                                        },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" },
                    "404": { "description": "Template not found" }
                }
            },
            "post": {
                "operationId": "saveTemplate",
                "summary": "Create, update or duplicate a template",
                "description": "Creates a new template, updates an existing one (when <code>id</code> is provided) or duplicates a template into the current client's account (when <code>action=duplicate</code>). The <code>movie</code> payload accepts either a movie object or a stringified JSON object, and supports referencing another template via <code>{ \"template\": \"<templateId>\" }</code> with optional <code>variables</code> overrides.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Template ID. Required when updating or duplicating; omit to create a new template."
                    },
                    {
                        "name": "action",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "duplicate" ] },
                        "description": "When set to <code>duplicate</code>, copies the template identified by <code>id</code> into the current client's account."
                    }
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "maxLength": 100,
                                        "description": "Human-readable template name."
                                    },
                                    "tags": {
                                        "oneOf": [
                                            { "type": "string", "description": "Comma-separated list of tags." },
                                            { "type": "array", "items": { "type": "string" } }
                                        ]
                                    },
                                    "movie": {
                                        "description": "Movie object, a stringified movie JSON, or a reference to another template via <code>{ \"template\": \"<templateId>\", \"variables\": {...} }</code>.",
                                        "oneOf": [
                                            { "$ref": "#/components/schemas/movie" },
                                            { "type": "string" }
                                        ]
                                    },
                                    "prompt": {
                                        "type": "string",
                                        "description": "Optional AI prompt associated with the template."
                                    },
                                    "variables": {
                                        "type": "object",
                                        "description": "Only used with <code>action=duplicate</code>: variables deep-merged into the source template's <code>movie.variables</code>."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Template saved or duplicated.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "templateId": { "type": "string" },
                                        "name": { "type": "string" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid payload (missing fields, bad JSON, etc.)" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions or template not owned by client" },
                    "404": { "description": "Template not found" }
                }
            },
            "delete": {
                "operationId": "deleteTemplate",
                "summary": "Delete a template",
                "description": "Deletes the template owned by the authenticated client. The associated S3 movie file is removed on a best-effort basis.",
                "parameters": [
                    {
                        "name": "id",
                        "in": "query",
                        "required": true,
                        "schema": { "type": "string" },
                        "description": "Template ID to delete."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Template deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Missing template ID" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" },
                    "500": { "description": "Error deleting the template" }
                }
            }
        },
        "/media": {
            "get": {
                "operationId": "getMediaStorage",
                "summary": "Get media storage usage",
                "description": "Returns the current storage usage for the authenticated client's media library, including free allowance, weekly credit cost for the overage and whether storage is currently blocked.",
                "responses": {
                    "200": {
                        "description": "Media storage info.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "storage": {
                                            "type": "object",
                                            "properties": {
                                                "used_bytes": { "type": "integer" },
                                                "free_allowance": { "type": "integer", "description": "Free storage allowance in bytes (50 MB)." },
                                                "credits_per_week": { "type": "integer", "description": "Weekly credits charged for storage above the free allowance." },
                                                "blocked": { "type": "boolean" },
                                                "blocked_at": { "type": "string", "format": "date-time", "nullable": true }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" }
                }
            }
        },
        "/media/file": {
            "get": {
                "operationId": "getMediaFile",
                "summary": "Get a single media file",
                "description": "Returns metadata (URL, size, content type, status, thumbnail, etc.) for a single file in the client's media library.",
                "parameters": [
                    {
                        "name": "path",
                        "in": "query",
                        "required": true,
                        "schema": { "type": "string" },
                        "description": "Path to the file relative to the media root (e.g. <code>folder/subfolder/file.jpg</code> or <code>file.jpg</code>)."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "File metadata.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "file": { "$ref": "#/components/schemas/mediaFile" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid or missing path" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" },
                    "404": { "description": "File not found" }
                }
            },
            "post": {
                "operationId": "requestMediaUpload",
                "summary": "Request a presigned upload URL",
                "description": "Reserves a slot in the client's media library and returns a short-lived presigned PUT URL the client can use to upload the file directly to S3. Files placed in the <code>temp</code> folder are eligible for automatic lifecycle deletion and do not count towards storage quota.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "name", "contentType", "size" ],
                                "properties": {
                                    "name": {
                                        "type": "string",
                                        "description": "File name. Non-alphanumeric characters except <code>._-</code> are replaced with <code>_</code>."
                                    },
                                    "contentType": {
                                        "type": "string",
                                        "description": "MIME type of the file (e.g. <code>image/png</code>, <code>video/mp4</code>)."
                                    },
                                    "size": {
                                        "type": "integer",
                                        "description": "File size in bytes. Maximum 500 MB.",
                                        "minimum": 1,
                                        "maximum": 524288000
                                    },
                                    "folder": {
                                        "type": "string",
                                        "description": "Destination folder. Use <code>temp</code> for non-billable temporary uploads. Defaults to the root folder."
                                    }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Presigned upload URL.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "uploadUrl": { "type": "string", "format": "uri", "description": "S3 presigned PUT URL." },
                                        "fileUrl": { "type": "string", "format": "uri", "description": "Public URL where the file will be served once uploaded." },
                                        "expiresIn": { "type": "integer", "description": "Validity of the presigned URL in seconds." }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid payload" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions or storage blocked" },
                    "409": { "description": "A file with the same name already exists in the destination folder" },
                    "413": { "description": "File exceeds the maximum allowed size (500 MB)" }
                }
            },
            "put": {
                "operationId": "moveMediaFile",
                "summary": "Move a media file to a different folder",
                "description": "Moves the file from <code>folder</code> to <code>destination</code> within the client's media library, preserving its name. Moving to/from the <code>temp</code> folder updates the billable storage counter accordingly.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "name", "destination" ],
                                "properties": {
                                    "name": { "type": "string" },
                                    "folder": { "type": "string", "description": "Source folder. Defaults to the root folder." },
                                    "destination": { "type": "string", "description": "Destination folder. Use an empty string for the root folder." }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "File moved.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid payload" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" },
                    "404": { "description": "Source file not found" },
                    "409": { "description": "A file with the same name already exists in the destination folder" }
                }
            },
            "delete": {
                "operationId": "deleteMediaFile",
                "summary": "Delete a media file",
                "description": "Deletes the file from both S3 and the metadata store. If the file was non-temporary and uploaded, the storage counter is decreased accordingly.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "name" ],
                                "properties": {
                                    "name": { "type": "string" },
                                    "folder": { "type": "string", "description": "Folder containing the file. Defaults to the root folder." }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "File deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid payload" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" },
                    "404": { "description": "File not found" }
                }
            }
        },
        "/media/folder": {
            "get": {
                "operationId": "getMediaFolder",
                "summary": "List a folder's contents or the folder tree",
                "description": "Returns the contents of a folder (files, sub-folders, paginated, with filters) or, when <code>tree=true</code>, a flat list of folders with aggregated stats.",
                "parameters": [
                    {
                        "name": "path",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "default": "/" },
                        "description": "Folder path. Use <code>/</code> for the root folder. Alias: <code>folder</code>."
                    },
                    {
                        "name": "tree",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "true", "false" ] },
                        "description": "When <code>true</code>, returns a flat list of folders with file count and total size instead of the folder contents."
                    },
                    {
                        "name": "type",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string", "enum": [ "image", "video", "audio", "other" ] },
                        "description": "Filter files by media type (derived from the content-type)."
                    },
                    {
                        "name": "q",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "string" },
                        "description": "Case-insensitive substring filter on the file name."
                    },
                    {
                        "name": "page",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "integer", "minimum": 0, "default": 0 },
                        "description": "Zero-based page index for pagination."
                    },
                    {
                        "name": "page_size",
                        "in": "query",
                        "required": false,
                        "schema": { "type": "integer", "minimum": 1, "default": 20 },
                        "description": "Page size for pagination."
                    }
                ],
                "responses": {
                    "200": {
                        "description": "Folder contents or folder tree.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "oneOf": [
                                        {
                                            "type": "object",
                                            "description": "Folder contents (default mode).",
                                            "properties": {
                                                "success": { "type": "boolean" },
                                                "path": { "type": "string" },
                                                "total_size": { "type": "integer", "description": "Sum of bytes of all direct files in the folder, before filters." },
                                                "total_files": { "type": "integer", "description": "Count of all direct files in the folder, before filters." },
                                                "total": { "type": "integer", "description": "Count of files matching the filters." },
                                                "page": { "type": "integer" },
                                                "page_size": { "type": "integer" },
                                                "folders": { "type": "array", "items": { "type": "string" } },
                                                "files": {
                                                    "type": "array",
                                                    "items": { "$ref": "#/components/schemas/mediaFile" }
                                                }
                                            }
                                        },
                                        {
                                            "type": "object",
                                            "description": "Folder tree (when <code>tree=true</code>).",
                                            "properties": {
                                                "success": { "type": "boolean" },
                                                "tree": {
                                                    "type": "array",
                                                    "items": {
                                                        "type": "object",
                                                        "properties": {
                                                            "path": { "type": "string" },
                                                            "files": { "type": "integer" },
                                                            "size": { "type": "integer" }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    ]
                                }
                            }
                        }
                    },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" }
                }
            },
            "post": {
                "operationId": "createMediaFolder",
                "summary": "Create a folder",
                "description": "Creates an empty folder in the client's media library. Folder names are sanitized to alphanumeric characters plus <code>/_-</code>.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "folder" ],
                                "properties": {
                                    "folder": { "type": "string", "description": "Folder path (e.g. <code>marketing/2025</code>)." }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Folder created (or already existed).",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "message": { "type": "string" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid or missing folder name" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" }
                }
            },
            "delete": {
                "operationId": "deleteMediaFolder",
                "summary": "Delete an empty folder",
                "description": "Deletes a folder. The folder must be empty; the special <code>temp</code> folder and the root folder cannot be deleted.",
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "type": "object",
                                "additionalProperties": false,
                                "required": [ "folder" ],
                                "properties": {
                                    "folder": { "type": "string" }
                                }
                            }
                        }
                    }
                },
                "responses": {
                    "200": {
                        "description": "Folder deleted.",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "type": "object",
                                    "properties": {
                                        "success": { "type": "boolean" },
                                        "timestamp": { "type": "string", "format": "date-time" }
                                    }
                                }
                            }
                        }
                    },
                    "400": { "description": "Invalid folder, folder not empty, or protected folder (root, temp)" },
                    "401": { "description": "Invalid or missing API key" },
                    "403": { "description": "Insufficient permissions" }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "template": {
                "title": "Template",
                "type": "object",
                "description": "A saved movie template owned by the authenticated client.",
                "properties": {
                    "id": { "type": "string", "description": "Template ID." },
                    "name": { "type": "string", "description": "Human-readable template name." },
                    "tags": { "type": "array", "items": { "type": "string" } },
                    "movie": {
                        "description": "Movie JSON associated with the template. Returned as a string or object depending on storage.",
                        "oneOf": [
                            { "$ref": "#/components/schemas/movie" },
                            { "type": "string" }
                        ]
                    },
                    "variables": {
                        "description": "Variables of the template, formatted according to the <code>format</code> query parameter when one is provided.",
                        "oneOf": [
                            { "type": "object" },
                            { "type": "array" }
                        ]
                    },
                    "prompt": { "type": "string", "description": "Optional AI prompt associated with the template." },
                    "ai_prompt": { "type": "string", "description": "Legacy AI prompt field." },
                    "owner": { "type": "boolean", "description": "Whether the authenticated client owns the template." },
                    "created_at": { "type": "string", "format": "date-time" },
                    "updated_at": { "type": "string", "format": "date-time" }
                }
            },
            "mediaFile": {
                "title": "Media File",
                "type": "object",
                "description": "A file in the client's media library.",
                "properties": {
                    "name": { "type": "string" },
                    "folder": { "type": "string", "description": "Folder containing the file, or <code>/</code> for the root folder." },
                    "type": {
                        "type": "string",
                        "enum": [ "image", "video", "audio", "other" ],
                        "description": "Media type derived from the content type."
                    },
                    "contentType": { "type": "string" },
                    "size": { "type": "integer", "description": "File size in bytes." },
                    "url": { "type": "string", "format": "uri" },
                    "thumbnailUrl": { "type": "string", "format": "uri", "nullable": true },
                    "status": {
                        "type": "string",
                        "enum": [ "pending", "uploaded", "error" ],
                        "description": "<code>pending</code> while a presigned upload is awaiting the actual S3 PUT; <code>uploaded</code> once the file is in S3."
                    },
                    "temporary": { "type": "boolean", "description": "True for files in the <code>temp</code> folder; these don't count towards storage quota and may be auto-deleted." },
                    "created_at": { "type": "string", "format": "date-time" }
                }
            },
            "movie": {
                "title": "Movie",
                "type": "object",
                "description": "Object defining the movie to be rendered",
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "Movie ID string. It must be unique per project",
                        "default": "@randomString"
                    },
                    "comment": {
                        "type": "string",
                        "description": "Used for adding your comments"
                    },
                    "draft": {
                        "type": "boolean",
                        "deprecated": true,
                        "description": "Deprecated. This property is ignored and has no effect. Watermarking is now controlled automatically based on the account plan.",
                        "default": true,
                        "enum": [ true, false ]
                    },
                    "template": {
                        "type": "string",
                        "description": "ID of the template to be used for the movie"
                    },
                    "variables": {
                        "type": "object",
                        "description": "Variables of the template. Variable names can only contain letters, numbers and underscores",
                        "default": {},
                        "example": {
                            "myVariable": "myValue",
                            "myOtherVariable": true,
                            "myThirdVariable": 123
                        }
                    },
                    "resolution": {
                        "type": "string",
                        "description": "Set the movie size based on common use cases. Use <code>custom</code> to set a custom size with the <code>width</code> and <code>height</code> properties",
                        "default": "custom",
                        "enum": [
                            "sd",
                            "hd",
                            "full-hd",
                            "squared",
                            "instagram-story",
                            "instagram-feed",
                            "twitter-landscape",
                            "twitter-portrait",
                            "custom"
                        ]
                    },
                    "width": {
                        "type": "integer",
                        "description": "Width of the movie. Only applicable if resolution is set to <code>custom</code>",
                        "dependsOn": {
                            "resolution": "custom"
                        },
                        "default": 640,
                        "minimum": 50,
                        "maximum": 3840,
                        "example": 640
                    },
                    "height": {
                        "type": "integer",
                        "description": "Height of the movie. Only applicable if resolution is set to <code>custom</code>",
                        "dependsOn": {
                            "resolution": "custom"
                        },
                        "default": 360,
                        "minimum": 50,
                        "maximum": 3840,
                        "example": 360
                    },
                    "quality": {
                        "type": "string",
                        "description": "Quality of the final rendered movie. Use it for speeding up the rendering process. <code>low</code> is the lowest quality, <code>high</code> is the highest quality",
                        "enum": [
                            "low",
                            "medium",
                            "high"
                        ],
                        "default": "high"
                    },
                    "fps": {
                        "hidden": true,
                        "type": "integer",
                        "description": "Frames per second",
                        "default": 25
                    },
                    "client-data": {
                        "hidden": false,
                        "type": "object",
                        "description": "Key-value pairs that will be included in the response of the GET requests and in the webhook payloads. Client data is intended to pass on information to the following steps of the workflow.",
                        "default": {}
                    },
                    "settings": {
                        "hidden": true,
                        "type": "object",
                        "description": "Deprecated"
                    },
                    "preload": {
                        "type": "array",
                        "description": "Assets to be downloaded or generated before the main elements. Each preload item must have a unique 'id' that can be referenced in elements using template variables like {{id_url}}, {{id_duration}}, {{id_width}} or {{id_height}}",
                        "items": {
                            "$ref": "#/components/schemas/preloadItem"
                        }
                    },
                    "scenes": {
                        "type": "array",
                        "items": {
                            "$ref": "#/components/schemas/scene"
                        }
                    },
                    "elements": {
                        "type": "array",
                        "items": {
                            "oneOf": [
                                {
                                    "$ref": "#/components/schemas/video"
                                },
                                {
                                    "$ref": "#/components/schemas/image"
                                },
                                {
                                    "$ref": "#/components/schemas/text"
                                },
                                {
                                    "$ref": "#/components/schemas/html"
                                },
                                {
                                    "$ref": "#/components/schemas/component"
                                },
                                {
                                    "$ref": "#/components/schemas/audio"
                                },
                                {
                                    "$ref": "#/components/schemas/voice"
                                },
                                {
                                    "$ref": "#/components/schemas/audiogram"
                                },
                                {
                                    "$ref": "#/components/schemas/subtitles"
                                }
                            ],
                            "discriminator": {
                                "propertyName": "type"
                            }
                        }
                    },
                    "cache": {
                        "type": "boolean",
                        "description": "Use the cached version of the movie if its available",
                        "default": true
                    },
                    "exports": {
                        "type": "array",
                        "description": "You can define different types of exports for your movie. Check the <a href=\"https://json2video.com/docs/tutorial/exports\">documentation</a> for more information",
                        "items": {
                            "export": {
                                "title": "export",
                                "description": "Export type",
                                "type": "object"
                            }
                        }
                    }
                },
                "example": {
                    "comment": "MyProject",
                    "resolution": "full-hd",
                    "scenes": [{
                        "elements": [{
                            "type": "video",
                            "src": "https://example.com/path/to/my/video.mp4"
                        }]
                    }]
                }
            },
            "scene": {
                "title": "Scene",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "ID of the scene",
                        "default": "@randomString"
                    },
                    "condition": {
                        "type": "string",
                        "description": "OPTIONAL. Condition to be met for the scene to be rendered. If the value is false or empty string, the scene is removed from the movie"
                    },
                    "import": {
                        "type": "string",
                        "description": "ID of the scene to import. The scene will be imported as a new scene and the elements will be added to the current scene",
                        "example": "mySceneTemplate"
                    },
                    "variables": {
                        "type": "object",
                        "description": "Local variables of the scene. Variable names can only contain letters, numbers and underscores",
                        "default": {},
                        "example": {
                            "myVariable": "myValue",
                            "myOtherVariable": true,
                            "myThirdVariable": 123
                        }
                    },
                    "comment": {
                        "type": "string",
                        "description": "Used for adding your comments"
                    },
                    "background-color": {
                        "type": "string",
                        "control": "color",
                        "description": "A hexadecimal representation of a color or 'transparent'",
                        "example": "#FF0000",
                        "default": "#000000"
                    },
                    "duration": {
                        "type": "number",
                        "format": "float",
                        "description": "Sets the scene duration in seconds. A value of -1 means that the scene lasts enough to contain all its elements",
                        "default": -1
                    },
                    "preload": {
                        "type": "array",
                        "description": "Assets to be downloaded or generated before the main elements. Each preload item must have a unique 'id' that can be referenced in elements using template variables like {{id_url}}, {{id_duration}}, {{id_width}} or {{id_height}}",
                        "items": {
                            "$ref": "#/components/schemas/preloadItem"
                        }
                    },
                    "elements": {
                        "type": "array",
                        "items": {
                            "oneOf": [
                                {
                                    "$ref": "#/components/schemas/video"
                                },
                                {
                                    "$ref": "#/components/schemas/image"
                                },
                                {
                                    "$ref": "#/components/schemas/text"
                                },
                                {
                                    "$ref": "#/components/schemas/html"
                                },
                                {
                                    "$ref": "#/components/schemas/component"
                                },
                                {
                                    "$ref": "#/components/schemas/audio"
                                },
                                {
                                    "$ref": "#/components/schemas/voice"
                                },
                                {
                                    "$ref": "#/components/schemas/audiogram"
                                },
                                {
                                    "$ref": "#/components/schemas/subtitles"
                                }
                            ],
                            "discriminator": {
                                "propertyName": "type"
                            }
                        }
                    },
                    "transition": {
                        "type": "object",
                        "hidden": true,
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "default": "xfade",
                                "enum": [
                                    "xfade"
                                ]
                            },
                            "style": {
                                "type": "string",
                                "default": "fade",
                                "example": "circleopen",
                                "enum": [
                                    "fade",
                                    "wipeleft",
                                    "wiperight",
                                    "wipeup",
                                    "wipedown",
                                    "slideleft",
                                    "slideright",
                                    "slideup",
                                    "slidedown",
                                    "circlecrop",
                                    "rectcrop",
                                    "distance",
                                    "fadeblack",
                                    "fadewhite",
                                    "radial",
                                    "smoothleft",
                                    "smoothright",
                                    "smoothup",
                                    "smoothdown",
                                    "circleopen",
                                    "circleclose",
                                    "vertopen",
                                    "vertclose",
                                    "horzopen",
                                    "horzclose",
                                    "dissolve",
                                    "pixelize",
                                    "diagtl",
                                    "diagtr",
                                    "diagbl",
                                    "diagbr",
                                    "hlslice",
                                    "hrslice",
                                    "vuslice",
                                    "vdslice",
                                    "hblur",
                                    "fadegrays",
                                    "wipetl",
                                    "wipetr",
                                    "wipebl",
                                    "wipebr",
                                    "squeezeh",
                                    "squeezev"
                                ]
                            },
                            "duration": {
                                "type": "number",
                                "description": "Duration of the transition in seconds",
                                "format": "float",
                                "example": 1.5
                            }
                        }
                    },
                    "cache": {
                        "type": "boolean",
                        "default": true,
                        "description": "Use the cached version of the scene if its available"
                    }
                }
            },
            "BaseElement": {
                "title": "BaseElement",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "id": {
                        "type": "string",
                        "description": "ID of the element",
                        "default": "@randomString"
                    },
                    "condition": {
                        "type": "string",
                        "description": "OPTIONAL. Condition to be met for the element to be rendered. If the value is false or empty string, the element is removed from the scene"
                    },
                    "variables": {
                        "type": "object",
                        "description": "Local variables of the element. Variable names can only contain letters, numbers and underscores",
                        "default": {},
                        "example": {
                            "myVariable": "myValue",
                            "myOtherVariable": true,
                            "myThirdVariable": 123
                        }
                    },
                    "comment": {
                        "type": "string",
                        "description": "Used for adding your comments"
                    },
                    "duration": {
                        "type": "number",
                        "default": -1,
                        "example": 7.3,
                        "format": "float",
                        "description": "Element's duration in seconds. A value of -1 auto calculates the duration based on the asset/file intrinsic length. A value of -2 sets the element duration to the parent scene or element duration"
                    },
                    "start": {
                        "type": "number",
                        "format": "float",
                        "default": 0,
                        "description": "Element's starting time in seconds relative to the container scene or the movie if the element is in the Movie's elements array."
                    },
                    "extra-time": {
                        "type": "number",
                        "default": 0,
                        "example": 0.5,
                        "format": "float",
                        "description": "Element's time span added after the playback."
                    },
                    "z-index": {
                        "type": "number",
                        "default": 0,
                        "minimum": -99,
                        "maximum": 99,
                        "example": 3,
                        "format": "integer",
                        "description": "Element's z-index. Use this property to reorganize the layering of the elements like in HTML"
                    },
                    "cache": {
                        "type": "boolean",
                        "default": true,
                        "example": false,
                        "format": "boolean",
                        "description": "Use the cached version of the element if its available"
                    },
                    "fade-in": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0,
                        "description": "Adds a fade in effect to the element. Value in seconds."
                    },
                    "fade-out": {
                        "type": "number",
                        "format": "float",
                        "minimum": 0,
                        "description": "Adds a fade out effect to the element. Value in seconds."
                    }
                }
            },
            "AudioElement": {
                "title": "AudioElement",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "muted": {
                        "type": "boolean",
                        "default": false,
                        "description": "Mutes the audio"
                    },
                    "volume": {
                        "type": "number",
                        "description": "Volume gain of the audio. A value of 1 means no gain. Higher values increase the volume. Values lower than 1 decrease the volume",
                        "default": 1.0,
                        "minimum": 0,
                        "maximum": 10
                    }
                }
            },
            "VisualElement": {
                "title": "VisualElement",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "position": {
                        "type": "string",
                        "description": "Sets the element position in the scene. A value of 'custom' sets a custom position based on the provided 'x' and 'y' properties. Edge and corner positions are offset by a 5% margin from the canvas edges; 'center-center' (alias 'center') is the exact canvas center with no margin.",
                        "enum": [
                            "top-left", "top-center", "top-right",
                            "center-left", "center-center", "center", "center-right",
                            "bottom-left", "bottom-center", "bottom-right",
                            "custom"
                        ],
                        "default": "custom"
                    },
                    "x": {
                        "type": "number",
                        "format": "integer",
                        "dependsOn": {
                            "position": "custom"
                        },
                        "description": "Sets the horizontal position of the element in the scene. The value <code>0</code> is on the left side",
                        "default": 0
                    },
                    "y": {
                        "type": "number",
                        "format": "integer",
                        "dependsOn": {
                            "position": "custom"
                        },
                        "description": "Sets the vertical position of the element in the scene. The value <code>0</code> is on the top side",
                        "default": 0
                    },
                    "resize": {
                        "type": "string",
                        "description": "Sets the resize mode of the element. A value of 'cover' or 'fill' stretches the element to cover the entire movie canvas. A value of 'fit' or 'contain' stretches the element to fit the movie canvas. If set, the 'width' and 'height' properties are ignored",
                        "enum": [ "cover", "fill", "fit", "contain" ]
                    },
                    "width": {
                        "type": "integer",
                        "description": "Sets the width of the element, scaling up or down if required. A value of '-1' means to keep the aspect ratio",
                        "minimum": -1,
                        "default": -1
                    },
                    "height": {
                        "type": "integer",
                        "description": "Sets the height of the element, scaling up or down if required. A value of '-1' means to keep the aspect ratio",
                        "minimum": -1,
                        "default": -1
                    },
                    "scale": {
                        "type": "object",
                        "description": "This property is deprecated. Use 'width' and 'height' instead",
                        "additionalProperties": false,
                        "properties": {
                            "width": {
                                "type": "integer",
                                "description": "Sets the width for scaling the element",
                                "minimum": -1,
                                "default": -1
                            },
                            "height": {
                                "type": "integer",
                                "description": "Sets the height for scaling the element",
                                "minimum": -1,
                                "default": -1
                            }
                        }
                    },
                    "rotate": {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "angle": {
                                "type": "number",
                                "description": "Sets the angle of rotation",
                                "minimum": -360,
                                "maximum": 360,
                                "default": 0
                            },
                            "speed": {
                                "type": "number",
                                "description": "Sets the time it takes to rotate the provided angle. A zero value means no movement",
                                "minimum": 0,
                                "default": 0
                            }
                        },
                        "required": [ "angle" ]
                    },
                    "crop": {
                        "type": "object",
                        "additionalProperties": false,
                        "description": "Crops the element",
                        "properties": {
                            "x": {
                                "type": "integer",
                                "description": "Sets the left point of croping",
                                "default": 0
                            },
                            "y": {
                                "type": "integer",
                                "description": "Sets the top point of croping",
                                "default": 0
                            },
                            "width": {
                                "type": "integer",
                                "description": "Sets the width of the croping"
                            },
                            "height": {
                                "type": "integer",
                                "description": "Sets the height of the croping"
                            }
                        },
                        "required": [
                            "width",
                            "height"
                        ]
                    },
                    "motion-blur": {
                        "type": "number",
                        "description": "Intensity of directional motion blur applied during x/y keyframe motion. 0 disables (default). 1 is the standard (≈ half-frame shutter analog), higher values increase the blur. Auto-detects motion segments from x/y keyframes and applies an avgblur with size derived from per-frame velocity. Only takes effect during motion windows; stationary frames are not blurred. Does not affect renders without keyframes or without 'motion-blur' set.",
                        "minimum": 0,
                        "maximum": 10,
                        "default": 0
                    },
                    "focus": {
                        "type": "string",
                        "description": "When combined with 'width' and 'height', scales the asset preserving its aspect ratio so that it covers the target dimensions, and crops the excess on the side opposite to the focus point. Equivalent to CSS 'object-fit: cover' + 'object-position'. Only applies when both 'width' and 'height' are set to positive values, and only to 'video' and 'image' elements. Ignored if 'resize' is also set. Supports keyframes on 'width' and 'height' (focus is preserved per frame).",
                        "enum": [
                            "center",
                            "top-left", "top-center", "top-right",
                            "center-left", "center-center", "center-right",
                            "bottom-left", "bottom-center", "bottom-right"
                        ]
                    },
                    "zoom": {
                        "type": "integer",
                        "description": "Animates the element from its native size (1×) to a final scale factor of <code>1 + |zoom| × 0.09</code> over the element's duration. So <code>zoom: 10</code> reaches 1.9× (the maximum), <code>zoom: 5</code> reaches 1.45×, <code>zoom: 1</code> reaches 1.09×. The sign controls the direction of the animation: positive values animate from 1× → final (zoom-in), negative values animate from final → 1× (zoom-out); the scale factor never drops below 1×. <code>zoom: 0</code> disables the effect. Combine with the <code>pan</code> property to choose the anchor point of the zoom. For true per-frame zoom (including factors below 1×) use <code>zoom</code> inside <code>keyframes</code> instead.",
                        "minimum": -10,
                        "maximum": 10
                    },
                    "pan": {
                        "type": "string",
                        "description": "Pans the element to the specified direction. If <code>zoom</code> property is not specified, the effect is a non-zooming pan",
                        "enum": [ 
                            "left", "top", "right", "bottom", "top-left", "top-right", "bottom-left", "bottom-right"
                        ]
                    },
                    "pan-distance": {
                        "type": "number",
                        "format": "float",
                        "description": "Is the distance of the panning effect. A higher value means a larger panning movement (higher speed)",
                        "minimum": 0.01,
                        "default": 0.1,
                        "maximum": 0.5
                    },
                    "pan-crop": {
                        "type": "boolean",
                        "description": "Enable or disable the crop effect when panning",
                        "default": true
                    },
                    "chroma-key": {
                        "type": "object",
                        "description": "Allows to define a color (or a range of colors) that will be converted to transparent",
                        "properties": {
                            "color": {
                                "type": "string",
                                "description": "Set the color for which alpha will be set to 0 (full transparency)",
                                "example": "#00b140"
                            },
                            "tolerance": {
                                "type": "integer",
                                "description": "Makes the selection more or less sensitive to changes in color. A value of 1 will select only the provided color. A value of 100 will select all colors, so the full canvas",
                                "minimum": 1,
                                "maximum": 100,
                                "default": 25
                            }
                        },
                        "required": [ "color" ]
                    },
                    "correction": {
                        "type": "object",
                        "description": "Allows to adjust the contrast, brightness, saturation and gamma of the element",
                        "additionalProperties": false,
                        "properties": {
                            "contrast": {
                                "type": "number",
                                "description": "Adjust the contrast",
                                "minimum": -1000,
                                "maximum": 1000,
                                "default": 1
                            },
                            "brightness": {
                                "type": "number",
                                "description": "Adjust the brightness",
                                "minimum": -1,
                                "maximum": 1,
                                "default": 0
                            },
                            "saturation": {
                                "type": "number",
                                "description": "Adjust the saturation",
                                "minimum": 0,
                                "maximum": 3,
                                "default": 1
                            },
                            "gamma": {
                                "type": "number",
                                "description": "Adjust the gamma",
                                "minimum": 0.1,
                                "maximum": 10,
                                "default": 1
                            },
                            "blur": {
                                "type": "number",
                                "description": "Apply gaussian blur. A value of 0 means no blur. A value of 10 means maximum blur.",
                                "minimum": 0,
                                "maximum": 50,
                                "default": 0
                            }
                        }
                    },
                    "flip-horizontal": {
                        "type": "boolean",
                        "description": "Flips the element horizontally",
                        "default": false
                    },
                    "flip-vertical": {
                        "type": "boolean",
                        "description": "Flips the element vertically",
                        "default": false
                    },
                    "mask": {
                        "type": "object",
                        "description": "A predefined mask name or a URL to a PNG or video file defining a mask for the element. For external mask files, black color is transparent, white is solid, and gray tones in between are partially transparent. Predefined masks names are: 'circle'.",
                        "properties": {
                            "src": {
                                "type": "string",
                                "description": "URL to the mask file"
                            },
                            "seek": {
                                "type": "number",
                                "description": "Seek to the specified time in seconds relative to the begining of the asset. Use negative values to seek backwards",
                                "format": "float",
                                "default": 0
                            }
                        }
                    },
                    "keyframes": {
                        "type": "array",
                        "description": "Animates element properties over time. Each keyframe defines a target value at a given time; the engine interpolates between consecutive keyframes using the specified easing function. Animatable properties are: 'x', 'y', 'width', 'height' and 'zoom'. If the first keyframe time is not 0, an implicit keyframe at time 0 is prepended using the element's current values; an implicit keyframe at the element's end time is appended if missing. 'zoom' keyframes are only valid for 'video' and 'image' elements and cannot be combined with 'width'/'height' keyframes or with the 'pan' property.",
                        "items": {
                            "$ref": "#/components/schemas/Keyframe"
                        },
                        "example": [
                            { "time": 0, "x": 0, "easing": "linear" },
                            { "time": 2, "x": 500, "easing": "ease-out-elastic" }
                        ]
                    }
                }
            },
            "Keyframe": {
                "title": "Keyframe",
                "type": "object",
                "additionalProperties": false,
                "description": "A single keyframe defining target values for animatable properties at a given time. Only the properties you want to animate need to be set; unspecified properties inherit from the previous keyframe (or the element's static value for the first keyframe).",
                "properties": {
                    "time": {
                        "oneOf": [
                            { "type": "number", "format": "float" },
                            { "type": "string" }
                        ],
                        "description": "Time of the keyframe in seconds, relative to the element's start. Accepts a number, a negative number (interpreted as seconds before the element ends, e.g. -1 = 1 second before the element ends), or a percentage string (e.g. '50%' = 50% of the element's duration). Times beyond the element's duration are clamped; keyframes with a time earlier than the previous one are skipped.",
                        "example": 1.5
                    },
                    "x": {
                        "type": "number",
                        "description": "Target horizontal position in pixels (only meaningful when 'position' is 'custom' or resolved to custom by an x/y keyframe)."
                    },
                    "y": {
                        "type": "number",
                        "description": "Target vertical position in pixels (only meaningful when 'position' is 'custom' or resolved to custom by an x/y keyframe)."
                    },
                    "width": {
                        "type": "number",
                        "description": "Target width in pixels. A value of -1 preserves the aspect ratio relative to the 'height' keyframe value."
                    },
                    "height": {
                        "type": "number",
                        "description": "Target height in pixels. A value of -1 preserves the aspect ratio relative to the 'width' keyframe value."
                    },
                    "zoom": {
                        "type": "number",
                        "description": "Target per-frame zoom level. Maps to a scale factor of <code>1 + zoom × 0.09</code> applied centered on the element: <code>zoom: 0</code> = 1× (no zoom), <code>zoom: 10</code> = 1.9× (max zoom-in), <code>zoom: -10</code> = 0.10× (max zoom-out). Unlike the static <code>zoom</code> property, negative values here produce a true scale factor below 1×. The crop is always centered — there is no per-keyframe anchor/focus. Only valid for 'video' and 'image' elements and incompatible with 'width'/'height' keyframes and with the 'pan' property.",
                        "minimum": -10,
                        "maximum": 10
                    },
                    "easing": {
                        "type": "string",
                        "description": "Easing function applied to the transition from the previous keyframe to this one. Acts as a default for every animated property in this keyframe; can be overridden per property via 'easing-x', 'easing-y', 'easing-width', 'easing-height' or 'easing-zoom'.",
                        "default": "linear",
                        "enum": [
                            "linear",
                            "ease",
                            "ease-in-sine", "ease-out-sine", "ease-in-out-sine",
                            "ease-in-quad", "ease-out-quad", "ease-in-out-quad",
                            "ease-in-cubic", "ease-out-cubic", "ease-in-out-cubic",
                            "ease-in-quart", "ease-out-quart", "ease-in-out-quart",
                            "ease-in-quint", "ease-out-quint", "ease-in-out-quint",
                            "ease-in-expo", "ease-out-expo", "ease-in-out-expo",
                            "ease-in-circ", "ease-out-circ", "ease-in-out-circ",
                            "ease-in-back", "ease-out-back", "ease-in-out-back",
                            "ease-in-elastic", "ease-out-elastic", "ease-in-out-elastic",
                            "ease-in-bounce", "ease-out-bounce", "ease-in-out-bounce"
                        ]
                    },
                    "easing-x": {
                        "type": "string",
                        "description": "Overrides 'easing' for the 'x' property only. See 'easing' for the list of accepted values."
                    },
                    "easing-y": {
                        "type": "string",
                        "description": "Overrides 'easing' for the 'y' property only. See 'easing' for the list of accepted values."
                    },
                    "easing-width": {
                        "type": "string",
                        "description": "Overrides 'easing' for the 'width' property only. See 'easing' for the list of accepted values."
                    },
                    "easing-height": {
                        "type": "string",
                        "description": "Overrides 'easing' for the 'height' property only. See 'easing' for the list of accepted values."
                    },
                    "easing-zoom": {
                        "type": "string",
                        "description": "Overrides 'easing' for the 'zoom' property only. See 'easing' for the list of accepted values."
                    }
                },
                "required": [ "time" ]
            },
            "CaptureProperty": {
                "title": "CaptureProperty",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "capture": {
                        "type": "object",
                        "description": "Browser capture settings",
                        "additionalProperties": false,
                        "properties": {
                            "width": {
                                "type": "integer",
                                "description": "Viewport width",
                                "default": 640,
                                "minimum": 50,
                                "maximum": 1920
                            },
                            "height": {
                                "type": "integer",
                                "description": "Viewport height",
                                "default": 360,
                                "minimum": 50,
                                "maximum": 1920
                            },
                            "duration": {
                                "type": "number",
                                "format": "float",
                                "description": "Screen recording duration in seconds. Use 0 to take a screenshot",
                                "default": 0,
                                "minimum": 0,
                                "maximum": 10
                            }
                        },
                        "required": [
                            "width",
                            "height"
                        ]
                    }
                }
            },
            "GenerativeAI": {
                "title": "GenerativeAI",
                "type": "object",
                "additionalProperties": false,
                "properties": {
                    "model": {
                        "type": "string",
                        "description": "Model to use for generation. Check all available models at <a href='https://json2video.com/docs/resources/generative-ai/'>https://json2video.com/docs/resources/generative-ai/</a>"
                    },
                    "model-settings": {
                        "type": "object",
                        "description": "Model settings that will be passed to the model"
                    },
                    "prompt": {
                        "type": "string",
                        "description": "Prompt to generate the asset"
                    },
                    "aspect-ratio": {
                        "type": "string",
                        "description": "Aspect ratio of the generated image",
                        "enum": [ "horizontal", "vertical", "squared" ],
                        "default": "horizontal"
                    },
                    "connection": {
                        "type": "string",
                        "description": "Connection ID to use for generation. If specified, the API Key in the connection will be used. If not specified, the default API Key will be used and credits may be deducted"
                    }
                }
            },
            "preloadItem": {
                "title": "Preload Item",
                "description": "A single preload entry: an asset to be downloaded or generated. Allowed types: image, video, audio, voice, text, html, component.",
                "oneOf": [
                    {
                        "$ref": "#/components/schemas/video"
                    },
                    {
                        "$ref": "#/components/schemas/image"
                    },
                    {
                        "$ref": "#/components/schemas/audio"
                    },
                    {
                        "$ref": "#/components/schemas/voice"
                    },
                    {
                        "$ref": "#/components/schemas/text"
                    },
                    {
                        "$ref": "#/components/schemas/html"
                    },
                    {
                        "$ref": "#/components/schemas/component"
                    }
                ],
                "discriminator": {
                    "propertyName": "type"
                }
            },
            "video": {
                "title": "Video",
                "allOf": [
                    {
                        "type": "object",
                        "required": [
                            "type"
                        ],
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "video"
                                ]
                            },
                            "src": {
                                "type": "string",
                                "format": "uri",
                                "description": "URL to the asset file. Videos can be in MP4, MKV, MOV but MP4 is recommended."
                            }
                        }
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "$ref": "#/components/schemas/GenerativeAI"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "loop": {
                                "type": "integer",
                                "minimum": -1,
                                "example": -1,
                                "description": "Sets the number of loops the video to play. Use -1 for an infinite loop. The default value of 1 plays the video just once."
                            },
                            "seek": {
                                "type": "number",
                                "description": "Seek to the specified time in seconds relative to the begining of the asset. Use negative values to seek backwards",
                                "format": "float",
                                "default": 0
                            }
                        }
                    },
                    {
                        "$ref": "#/components/schemas/AudioElement"
                    }
                ]
            },
            "image": {
                "title": "Image",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "image"
                                ]
                            },
                            "src": {
                                "type": "string",
                                "format": "uri",
                                "description": "URL to the asset file. Images can be in JPG, PNG, GIF or any common image format."
                            }
                        }
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "$ref": "#/components/schemas/GenerativeAI"
                    }
                ]
            },

            "text": {
                "title": "Text",
                "description": "Creates a text element of a given style",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "text"
                                ]
                            },
                            "style": {
                                "type": "string",
                                "control": "component-picker",
                                "description": "Style of the text element. Check all available text style at <a href='https://json2video.com/docs/resources/text/'>https://json2video.com/resources/text/</a>",
                                "example": "003",
                                "default": "001"
                            },
                            "text": {
                                "type": "string",
                                "description": "Text to be printed. The text string does not accept HTML formatting.",
                                "example": "Lorem ipsum dolor sit amet"
                            },
                            "settings": {
                                "type": "object",
                                "control": "component-settings",
                                "dependsOn": {
                                    "style": "__not_empty__"
                                },
                                "description": "Text formatting settings. In general, these are CSS properties such as <code>font-size</code>, <code>colour</code> or <code>font-weight</code>. See the styles to confirm which properties are available.",
                                "default": {},
                                "example": {
                                    "font-size": "60px",
                                    "color": "#FF0000"
                                }
                            },
                            "width": {
                                "type": "integer",
                                "description": "Desired text element width. A value of '-1' inherits movie width",
                                "minimum": -1,
                                "maximum": 1920,
                                "default": -1
                            },
                            "height": {
                                "type": "integer",
                                "description": "Desired text element height. A value of '-1' inherits movie height",
                                "minimum": -1,
                                "maximum": 1080,
                                "default": -1
                            }
                        },
                        "required": [
                            "type", "text"
                        ]
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "duration": {
                                "type": "number",
                                "format": "float",
                                "default": -2,
                                "minimum": -2,
                                "example": -1,
                                "description": "Element's duration in seconds. A value of -1 auto calculates the duration based on the asset/file intrinsic length. A value of -2 sets the element duration to the parent scene or element duration"
                            }
                        }
                    }
                ]
            },
            
            "component": {
                "title": "Component",
                "description": "Creates an element based on the specified feature",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "component"
                                ]
                            },
                            "component": {
                                "type": "string",
                                "control": "component-picker",
                                "description": "ID of the Component element. Check all available components in the <a href='https://json2video.com/docs/resources/basic/'>library</a>",
                                "example": "basic/001"
                            },
                            "settings": {
                                "type": "object",
                                "control": "component-settings",
                                "dependsOn": {
                                    "component": "__not_empty__"
                                },
                                "description": "Settings to be passed to the component"
                            },
                            "width": {
                                "type": "integer",
                                "description": "Desired component element width. A value of '-1' inherits movie width",
                                "minimum": -1,
                                "maximum": 1920,
                                "default": -1
                            },
                            "height": {
                                "type": "integer",
                                "description": "Desired component element height. A value of '-1' inherits movie height",
                                "minimum": -1,
                                "maximum": 1080,
                                "default": -1
                            }
                        },
                        "required": [
                            "type", "component"
                        ]
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "duration": {
                                "type": "number",
                                "format": "float",
                                "default": -2,
                                "minimum": -2,
                                "example": -1,
                                "description": "Element's duration in seconds. A value of -1 auto calculates the duration based on the asset/file intrinsic length. A value of -2 sets the element duration to the parent scene or element duration"
                            }
                        }
                    }
                ]
            },

            "html": {
                "title": "HTML",
                "description": "Creates a video recording or a screenshot of the provided HTML snippet",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "html"
                                ]
                            },
                            "html": {
                                "type": "string",
                                "description": "HTML snippet to render. Compatible with HTML5, CSS3 and Javascript",
                                "example": "&lt;h1&gt;Hello world&lt;/h1&gt;"
                            },
                            "src": {
                                "type": "string",
                                "description": "URL to the web page"
                            },
                            "wait": {
                                "type": "number",
                                "description": "Time in seconds to wait before taking the screenshot",
                                "default": 2,
                                "maximum": 5,
                                "minimum": 0
                            },
                            "tailwindcss": {
                                "type": "boolean",
                                "description": "Enables usage of TailwindCSS for the HTML snippet",
                                "default": false,
                                "example": true
                            },
                            "width": {
                                "type": "integer",
                                "description": "Desired text element width. A value of <code>-1</code> means inherits scenes or movie width",
                                "minimum": -1,
                                "maximum": 1920,
                                "default": -1
                            },
                            "height": {
                                "type": "integer",
                                "description": "Desired text element height. A value of <code>-1</code> means inherits scenes or movie height",
                                "minimum": -1,
                                "maximum": 1920,
                                "default": -1
                            }
                        },
                        "required": [
                            "type"
                        ]
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "duration": {
                                "type": "number",
                                "format": "float",
                                "default": -2,
                                "minimum": -2,
                                "example": -1,
                                "description": "Element's duration in seconds. A value of -1 auto calculates the duration based on the asset/file intrinsic length. A value of -2 sets the element duration to the parent scene or element duration"
                            }
                        }
                    }
                ]
            },
            "audio": {
                "title": "Audio",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "audio"
                                ]
                            },
                            "src": {
                                "type": "string",
                                "format": "uri",
                                "description": "URL to the asset file. Audios can be in MP3, WAV or any common audio format."
                            }
                        }
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/AudioElement"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "loop": {
                                "type": "integer",
                                "minimum": -1,
                                "example": -1,
                                "description": "Sets the number of loops the video to play. Use -1 for an infinite loop. The default value of 1 plays the video just once."
                            },
                            "seek": {
                                "type": "number",
                                "description": "Seek to the specified time in seconds relative to the begining of the asset. Use negative values to seek backwards",
                                "format": "float",
                                "default": 0
                            }
                        }
                    }
                ]
            },
            "voice": {
                "title": "Voice",
                "description": "Creates a voice audio element from the provided text",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "voice"
                                ]
                            },
                            "text": {
                                "type": "string",
                                "description": "The sentence or sentences to be converted to voice audio",
                                "control": "voice-generator"
                            },
                            "voice": {
                                "type": "string",
                                "description": "The voice name to be used. Check <a href=\"/docs/tutorial/voice-elements/\">available voices</a>."
                            },
                            "model": {
                                "type": "string",
                                "description": "The model to use for generation. Check all available models at <a href='https://json2video.com/docs/resources/generative-ai/'>https://json2video.com/docs/resources/generative-ai/</a>"
                            },
                            "connection": {
                                "type": "string",
                                "description": "Connection ID to use for generation. If specified, the API Key in the connection will be used. If not specified, the default API Key will be used and credits may be deducted"
                            }
                        },
                        "required": [
                            "type",
                            "text"
                        ]
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/AudioElement"
                    }
                ]
            },

            "audiogram": {
                "title": "Audiogram",
                "description": "Visualizes the audio of the scene or movie as an audiogram",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "audiogram"
                                ]
                            },
                            "color": {
                                "type": "string",
                                "description": "Color of the audiogram waves in hexadecimal format"
                            },
                            "opacity": {
                                "type": "number",
                                "format": "float",
                                "description": "Opacity of the audiogram",
                                "minimum": 0,
                                "maximum": 1,
                                "default": 0.5
                            },
                            "width": {
                                "type": "integer",
                                "description": "Desired audiogram element width. A value of '-1' inherits movie width",
                                "minimum": -1,
                                "maximum": 1920,
                                "default": -1
                            },
                            "height": {
                                "type": "integer",
                                "description": "Desired audiogram element height. A value of '-1' inherits movie height",
                                "minimum": -1,
                                "maximum": 1080,
                                "default": -1
                            },
                            "amplitude": {
                                "type": "number",
                                "format": "float",
                                "description": "Relative amplitude of the audiogram",
                                "minimum": 0,
                                "maximum": 10,
                                "default": 5
                            }
                        },
                        "required": [
                            "type"
                        ]
                    },
                    {
                        "$ref": "#/components/schemas/BaseElement"
                    },
                    {
                        "$ref": "#/components/schemas/VisualElement"
                    },
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "duration": {
                                "type": "number",
                                "format": "float",
                                "default": -2,
                                "minimum": -2,
                                "example": -1,
                                "description": "Element's duration in seconds. A value of -1 auto calculates the duration based on the asset/file intrinsic length. A value of -2 sets the element duration to the parent scene or element duration"
                            }
                        }
                    }
                ]
            },

            "subtitles": {
                "title": "Subtitles",
                "description": "Adds subtitles to the scene or movie by transcribing the voice audio.",
                "allOf": [
                    {
                        "type": "object",
                        "additionalProperties": false,
                        "properties": {
                            "type": {
                                "type": "string",
                                "enum": [
                                    "subtitles"
                                ]
                            },
                            "comment": {
                                "type": "string",
                                "description": "Use it for your comments"
                            },
                            "language": {
                                "type": "string",
                                "description": "Language of the audio. Use <code>auto</code> to let the API detect the language automatically.",
                                "default": "auto",
                                "enum": [
                                    "auto", "en", "bg", "ca", "cs", "da", "nl", "en-AU", "en-GB", "en-NZ", "en-IN", "en-US",
                                    "et", "fr", "fi", "nl-BE", "de", "de-CH", "el", "hi", "hi-Latn", "hu", "id", "it", "ja",
                                    "ko", "lv", "lt", "ms", "no", "pl", "pt", "pt-BR", "ro", "ru", "sk", "es", "es-419", 
                                    "sv", "th", "tr", "uk", "vi", "zh", "zh-TW"
                                ]
                            },
                            "model": {
                                "type": "string",
                                "description": "Model to use for transcription. If no model is provided, a default model is used."
                            },
                            "captions": {
                                "type": "string",
                                "description": "Captions to use as subtitles. The string can be a URL to a file with the captions or the actual captions content properly encoded. Supported formats are SRT, VTT or ASS. If this property is ommited, the subtitles will be generated automatically from the audio."
                            },
                            "settings": {
                                "type": "object",
                                "description": "Settings to customize the subtitles.",
                                "default": {},
                                "additionalProperties": false,
                                "properties": {
                                    "style": {
                                        "type": "string",
                                        "description": "Style of the subtitles. Check the tutorial for more details.",
                                        "enum": [
                                            "classic",
                                            "classic-progressive",
                                            "classic-one-word",
                                            "boxed-line",
                                            "boxed-word"
                                        ],
                                        "default": "classic"
                                    },
                                    "font-url": {
                                        "type": "string",
                                        "description": "URL to the font file to use for the subtitles. The font file must be in TTF format. The <code>font-family</code> property must match the font family name in the font file."
                                    },
                                    "font-family": {
                                        "type": "string",
                                        "description": "Font family of the subtitles. One of the font families below or a custom font family name if <code>font-url</code> is provided.",
                                        "default": "Arial",
                                        "enum": [
                                            "Arial",
                                            "Arial Bold",
                                            "Oswald Bold",
                                            "NotoSans Bold",
                                            "Simplified Chinese",
                                            "Traditional Chinese",
                                            "Japanese",
                                            "Korean",
                                            "Korean Bold",
                                            "Thai"
                                        ]
                                    },
                                    "font-weight": {
                                        "type": "string",
                                        "description": "Font weight of the subtitles. Check the tutorial for more details.",
                                        "example": "600"
                                    },
                                    "font-size": {
                                        "type": "integer",
                                        "description": "Font size of the subtitles. Usual sizes are between 90 and 150. Defaults to 5% of the movie width."
                                    },
                                    "word-color": {
                                        "type": "string",
                                        "description": "Color of the spoken word",
                                        "default": "#FFFF00"
                                    },
                                    "line-color": {
                                        "type": "string",
                                        "description": "Color of the rest of words in the line",
                                        "default": "#FFFFFF"
                                    },
                                    "outline-color": {
                                        "type": "string",
                                        "description": "Outline color of the subtitles",
                                        "default": "#000000"
                                    },
                                    "outline-width": {
                                        "type": "integer",
                                        "description": "Width of the outline",
                                        "default": 0
                                    },
                                    "shadow-color": {
                                        "type": "string",
                                        "description": "Shadow color of the subtitles",
                                        "default": "#000000"
                                    },
                                    "shadow-offset": {
                                        "type": "integer",
                                        "description": "Offset of the shadow",
                                        "default": 0
                                    },
                                    "box-color": {
                                        "type": "string",
                                        "description": "Color of the box behind the subtitles. Depending on the style, it can be the background color of the spoken word or the full line",
                                        "default": "#000000"
                                    },
                                    "position": {
                                        "type": "string",
                                        "description": "Position of the subtitles",
                                        "default": "bottom-center",
                                        "enum": [ "top-left", "top-center", "top-right", "center-left", "center-center", "center-right", "bottom-left", "bottom-center", "bottom-right", "mid-bottom-center", "mid-top-center", "custom" ]
                                    },
                                    "x": {
                                        "type": "integer",
                                        "description": "X coordinate of the subtitles",
                                        "default": 0
                                    },
                                    "y": {
                                        "type": "integer",
                                        "description": "Y coordinate of the subtitles",
                                        "default": 0
                                    },
                                    "max-words-per-line": {
                                        "type": "integer",
                                        "description": "Maximum number of words per line",
                                        "default": 4
                                    },
                                    "all-caps": {
                                        "type": "boolean",
                                        "description": "Makes the subtitles all caps",
                                        "default": false
                                    },
                                    "keywords": {
                                        "type": "array",
                                        "description": "Keywords provides additional vocabulary to the transcription process. Use it to improve the accuracy of the transcription of non-standard words or phrases.",
                                        "items": {
                                            "type": "string"
                                        }
                                    },
                                    "replace": {
                                        "type": "object",
                                        "description": "Replaces words with the specified replacement. Useful to correct the transcription of non-standard words or phrases."
                                    },
                                    "translate": {
                                        "type": "string",
                                        "description": "Target language code for subtitle translation. The audio will be transcribed in its original language and then the transcription will be translated to this language. Example: <code>es</code> for Spanish, <code>fr</code> for French."
                                    }
                                }
                            }
                        },
                        "required": [
                            "type"
                        ]
                    }
                ]
            }
        }
    }
}