{
  "openapi": "3.1.0",
  "info": {
    "title": "Revid Public API v3",
    "version": "3.6.0",
    "description": "Generate short-form videos programmatically. The API is workflow-driven: pick a `workflow`, provide its `source` input, and optionally tune `media`, `voice`, `captions`, `music`, `avatar`, `options`, and `render`.\n\nHuman docs: https://www.revid.ai/docs\n\nRevid MCP for AI agents: POST /api/mcp — setup guide at https://www.revid.ai/mcp\n\nEvery render call costs 10 credits plus generation costs. Estimate with POST /api/public/v3/calculate-credits (no auth required)."
  },
  "servers": [
    {
      "url": "https://www.revid.ai"
    }
  ],
  "tags": [
    {
      "name": "Create videos",
      "description": "Start renders and estimate their credit cost."
    },
    {
      "name": "Projects",
      "description": "Track, export, and manage projects."
    },
    {
      "name": "Publishing",
      "description": "Schedule or publish rendered videos to social channels."
    },
    {
      "name": "Characters & voices",
      "description": "Consistent characters and voice cloning."
    },
    {
      "name": "Media generation",
      "description": "Standalone image/video generation."
    },
    {
      "name": "Account & billing",
      "description": "Account info and credit packs."
    }
  ],
  "paths": {
    "/api/public/v3/render": {
      "post": {
        "operationId": "postRender",
        "summary": "Create a video",
        "description": "Start a video generation. Returns a project id (pid) immediately; the render continues asynchronously. Use webhookUrl or poll GET /status.\n\n**Cost:** 10 credits per call + generation costs (estimate with /calculate-credits).",
        "tags": [
          "Create videos"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderRequest"
              },
              "examples": {
                "ScriptToVideo": {
                  "summary": "Script to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is my video text"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "pro",
                      "density": "high",
                      "animation": "soft"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "trackName": "Observer"
                    },
                    "render": {
                      "resolution": "1080p",
                      "compression": 18,
                      "frameRate": 30
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "PromptToVideo": {
                  "summary": "Prompt to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "this is my prompt",
                      "stylePrompt": "dark mood",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "ai-video",
                      "quality": "ultra",
                      "density": "high"
                    },
                    "options": {
                      "promptTargetDuration": 30
                    },
                    "characterIds": [
                      "ac873ae7-aec1-4261-b8ef-bbd85547652e"
                    ]
                  }
                },
                "AudioToVideo": {
                  "summary": "Audio to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "audio-to-video",
                    "source": {
                      "url": "https://www.youtube.com/watch?v=ip30oRP9BP0"
                    },
                    "media": {
                      "type": "ai-video",
                      "density": "medium",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "mediaPreset": "DEFAULT",
                      "bRollType": "split-screen"
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom",
                      "autoCrop": true
                    },
                    "options": {
                      "useWholeAudio": true,
                      "hasToTranscript": true,
                      "disableAudio": true
                    },
                    "aspectRatio": "16:9"
                  }
                },
                "MusicToVideo": {
                  "summary": "Music to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "music-to-video",
                    "source": {
                      "url": "https://www.youtube.com/watch?v=ip30oRP9BP0",
                      "prompt": "A neon noir chase through rainy streets that becomes a rooftop performance by the final chorus.",
                      "recordingType": "video"
                    },
                    "media": {
                      "type": "moving-image",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/music-video-reference.jpg",
                          "type": "image",
                          "title": "Reference for the neon rooftop look"
                        }
                      ]
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "soundWave": true,
                      "syncWith": "lyrics"
                    },
                    "aspectRatio": "16:9"
                  }
                },
                "ArticleToVideo": {
                  "summary": "Article to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "article-to-video",
                    "source": {
                      "url": "https://open.spotify.com/track/5Cp75TUMrHF6c8xbhdligS"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "ultra"
                    },
                    "options": {
                      "summarizationPreference": "summarize",
                      "targetDuration": 30
                    },
                    "metadata": {
                      "urlType": "spotify",
                      "duration": 194
                    }
                  }
                },
                "AvatarToVideo": {
                  "summary": "Avatar to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "avatar-to-video",
                    "source": {
                      "text": "this is my text"
                    },
                    "media": {
                      "type": "moving-image",
                      "bRollType": "split-screen",
                      "placeAvatarInContext": true
                    },
                    "avatar": {
                      "enabled": true,
                      "url": "https://cdn.revid.ai/ai-gen/chSmd-WtE.jpg",
                      "mimeType": "image/jpeg"
                    }
                  }
                },
                "StaticBackgroundVideo": {
                  "summary": "Static background video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "static-background-video",
                    "source": {
                      "text": "this is my text"
                    },
                    "media": {
                      "type": "moving-image",
                      "backgroundVideo": {
                        "type": "video",
                        "url": "https://cdn.revid.ai/backgrounds/minecraft/color-upscaled.mp4",
                        "urlLowRes": "https://cdn.revid.ai/backgrounds/minecraft/color_low.mp4",
                        "imagePreview": "https://cdn.revid.ai/backgrounds/minecraft/color_poster.webp",
                        "noReencode": true
                      }
                    }
                  }
                },
                "MotionTransfer": {
                  "summary": "Motion transfer",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "motion-transfer",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1772035872439-video.mp4"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "mediaPreset": "DEFAULT",
                      "useOnlyProvided": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1772035882827-image.jpg",
                          "type": "image",
                          "title": ""
                        }
                      ]
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "metadata": {
                      "duration": 25.32
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "CaptionVideo": {
                  "summary": "Caption video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "caption-video",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1771944925512-video.mp4",
                      "recordingType": "video"
                    },
                    "media": {
                      "type": "moving-image",
                      "bRollType": "split-screen"
                    },
                    "captions": {
                      "enabled": true,
                      "autoCrop": true
                    },
                    "metadata": {
                      "duration": 8.04
                    }
                  }
                },
                "AdGenerator": {
                  "summary": "Ad generator",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "ad-generator",
                    "source": {
                      "prompt": "my ad prompt"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "ultra",
                      "useOnlyProvided": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1771944959344-image.png",
                          "type": "image",
                          "title": ""
                        }
                      ]
                    },
                    "options": {
                      "promptTargetDuration": 30
                    }
                  }
                },
                "RecipeCustomMedia": {
                  "summary": "Recipe: Script with your own media, in order",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is a test"
                    },
                    "media": {
                      "type": "custom",
                      "density": "medium",
                      "imageModel": "cheap",
                      "videoModel": "base",
                      "useOnlyProvided": true,
                      "useProvidedInOrder": true,
                      "turnImagesIntoVideos": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/ai-gen/TAINdpjKn.jpg",
                          "title": "An abstract, beautiful shot of three distinct beams of light merging into a single radiant golden source.",
                          "type": "image"
                        },
                        {
                          "url": "https://cdn.revid.ai/ai-gen/OZxUbirp4.jpg",
                          "title": "Three women appear as silhouettes in front of a giant glowing sun in a dark indigo sky.",
                          "type": "image"
                        },
                        {
                          "url": "https://cdn.revid.ai/ai-gen/xA1PjFVGorg.jpg",
                          "title": "A woman with a sleek black bob stands in a neon-lit glass hallway with rain outside.",
                          "type": "image"
                        }
                      ]
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "position": "bottom"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeReferenceImage": {
                  "summary": "Recipe: Prompt with a reference image",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "this is an example",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "ai-video",
                      "imageModel": "ultra",
                      "videoModel": "ultra",
                      "mediaPreset": "ANIME",
                      "addAudioToVideos": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1777872884798-image.png",
                          "title": "",
                          "type": "image"
                        }
                      ]
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Ali",
                      "position": "bottom"
                    },
                    "options": {
                      "promptTargetDuration": 30
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeStockFootage": {
                  "summary": "Recipe: Script with stock footage",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is my video text"
                    },
                    "media": {
                      "type": "stock-video",
                      "density": "high"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "trackName": "Observer"
                    }
                  }
                },
                "RecipeXLinkedinPost": {
                  "summary": "Recipe: X/LinkedIn post to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "https://x.com/tibo_maker/status/1848647301998284964"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "options": {
                      "summarizationPreference": "summarize"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeVideoQuiz": {
                  "summary": "Recipe: Quiz video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "https://x.com/tibo_maker/status/1848647301998284964"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "advanced": {
                      "customCreationParams": {
                        "quizzData": {
                          "title": "France",
                          "questions": [
                            {
                              "id": "82e14b8f-07ce-4489-9c35-6d9c10872b4e",
                              "question": "What is France",
                              "answers": [
                                {
                                  "id": "a62c6e91-da4b-491a-8f36-ba67caa5838a",
                                  "answer": "a country",
                                  "isCorrect": true
                                },
                                {
                                  "id": "10c89812-22f8-47df-88ef-f11e318fdb1c",
                                  "answer": "a city",
                                  "isCorrect": false
                                }
                              ]
                            }
                          ]
                        }
                      }
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipePdfToVideo": {
                  "summary": "Recipe: PDF to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "caption-video",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1772035824673-application.pdf"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "cheap",
                      "videoModel": "base"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "position": "bottom"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeNewsVideo": {
                  "summary": "Recipe: News to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "news about France",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "options": {
                      "promptTargetDuration": 30,
                      "fetchNews": true
                    },
                    "advanced": {
                      "customCreationParams": {
                        "promptCustomRules": "Use recent factual sources and structure as a professional news report."
                      }
                    },
                    "aspectRatio": "9:16"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ success: 1, pid, workflow, webhookUrl, endpoint, docs }. The webhook receives the final status and video URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderSuccessResponse"
                },
                "example": {
                  "success": 1,
                  "pid": "AbC123xYz",
                  "workflow": "script-to-video",
                  "webhookUrl": "https://your-server.com/revid/webhook",
                  "endpoint": "/api/public/v3/render"
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      },
      "get": {
        "operationId": "getRender",
        "summary": "Get live JSON docs",
        "description": "Returns this API's machine-readable documentation: workflows, defaults, parameter reference, and examples. No auth required.",
        "tags": [
          "Create videos"
        ],
        "responses": {
          "200": {
            "description": "JSON documentation payload (workflows, parameterReference, examples, additionalEndpoints, compatibility).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "JSON documentation payload (workflows, parameterReference, examples, additionalEndpoints, compatibility)."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/calculate-credits": {
      "post": {
        "operationId": "postCalculateCredits",
        "summary": "Estimate credits",
        "description": "Estimate the credit cost of a render without starting it. Accepts the exact same body as POST /render (legacy { creationParams } also accepted). No auth required.",
        "tags": [
          "Create videos"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RenderRequest"
              },
              "examples": {
                "ScriptToVideo": {
                  "summary": "Script to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is my video text"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "pro",
                      "density": "high",
                      "animation": "soft"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "trackName": "Observer"
                    },
                    "render": {
                      "resolution": "1080p",
                      "compression": 18,
                      "frameRate": 30
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "PromptToVideo": {
                  "summary": "Prompt to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "this is my prompt",
                      "stylePrompt": "dark mood",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "ai-video",
                      "quality": "ultra",
                      "density": "high"
                    },
                    "options": {
                      "promptTargetDuration": 30
                    },
                    "characterIds": [
                      "ac873ae7-aec1-4261-b8ef-bbd85547652e"
                    ]
                  }
                },
                "AudioToVideo": {
                  "summary": "Audio to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "audio-to-video",
                    "source": {
                      "url": "https://www.youtube.com/watch?v=ip30oRP9BP0"
                    },
                    "media": {
                      "type": "ai-video",
                      "density": "medium",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "mediaPreset": "DEFAULT",
                      "bRollType": "split-screen"
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom",
                      "autoCrop": true
                    },
                    "options": {
                      "useWholeAudio": true,
                      "hasToTranscript": true,
                      "disableAudio": true
                    },
                    "aspectRatio": "16:9"
                  }
                },
                "MusicToVideo": {
                  "summary": "Music to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "music-to-video",
                    "source": {
                      "url": "https://www.youtube.com/watch?v=ip30oRP9BP0",
                      "prompt": "A neon noir chase through rainy streets that becomes a rooftop performance by the final chorus.",
                      "recordingType": "video"
                    },
                    "media": {
                      "type": "moving-image",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/music-video-reference.jpg",
                          "type": "image",
                          "title": "Reference for the neon rooftop look"
                        }
                      ]
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "soundWave": true,
                      "syncWith": "lyrics"
                    },
                    "aspectRatio": "16:9"
                  }
                },
                "ArticleToVideo": {
                  "summary": "Article to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "article-to-video",
                    "source": {
                      "url": "https://open.spotify.com/track/5Cp75TUMrHF6c8xbhdligS"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "ultra"
                    },
                    "options": {
                      "summarizationPreference": "summarize",
                      "targetDuration": 30
                    },
                    "metadata": {
                      "urlType": "spotify",
                      "duration": 194
                    }
                  }
                },
                "AvatarToVideo": {
                  "summary": "Avatar to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "avatar-to-video",
                    "source": {
                      "text": "this is my text"
                    },
                    "media": {
                      "type": "moving-image",
                      "bRollType": "split-screen",
                      "placeAvatarInContext": true
                    },
                    "avatar": {
                      "enabled": true,
                      "url": "https://cdn.revid.ai/ai-gen/chSmd-WtE.jpg",
                      "mimeType": "image/jpeg"
                    }
                  }
                },
                "StaticBackgroundVideo": {
                  "summary": "Static background video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "static-background-video",
                    "source": {
                      "text": "this is my text"
                    },
                    "media": {
                      "type": "moving-image",
                      "backgroundVideo": {
                        "type": "video",
                        "url": "https://cdn.revid.ai/backgrounds/minecraft/color-upscaled.mp4",
                        "urlLowRes": "https://cdn.revid.ai/backgrounds/minecraft/color_low.mp4",
                        "imagePreview": "https://cdn.revid.ai/backgrounds/minecraft/color_poster.webp",
                        "noReencode": true
                      }
                    }
                  }
                },
                "MotionTransfer": {
                  "summary": "Motion transfer",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "motion-transfer",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1772035872439-video.mp4"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra",
                      "mediaPreset": "DEFAULT",
                      "useOnlyProvided": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1772035882827-image.jpg",
                          "type": "image",
                          "title": ""
                        }
                      ]
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "metadata": {
                      "duration": 25.32
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "CaptionVideo": {
                  "summary": "Caption video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "caption-video",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1771944925512-video.mp4",
                      "recordingType": "video"
                    },
                    "media": {
                      "type": "moving-image",
                      "bRollType": "split-screen"
                    },
                    "captions": {
                      "enabled": true,
                      "autoCrop": true
                    },
                    "metadata": {
                      "duration": 8.04
                    }
                  }
                },
                "AdGenerator": {
                  "summary": "Ad generator",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "ad-generator",
                    "source": {
                      "prompt": "my ad prompt"
                    },
                    "media": {
                      "type": "moving-image",
                      "quality": "ultra",
                      "useOnlyProvided": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1771944959344-image.png",
                          "type": "image",
                          "title": ""
                        }
                      ]
                    },
                    "options": {
                      "promptTargetDuration": 30
                    }
                  }
                },
                "RecipeCustomMedia": {
                  "summary": "Recipe: Script with your own media, in order",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is a test"
                    },
                    "media": {
                      "type": "custom",
                      "density": "medium",
                      "imageModel": "cheap",
                      "videoModel": "base",
                      "useOnlyProvided": true,
                      "useProvidedInOrder": true,
                      "turnImagesIntoVideos": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/ai-gen/TAINdpjKn.jpg",
                          "title": "An abstract, beautiful shot of three distinct beams of light merging into a single radiant golden source.",
                          "type": "image"
                        },
                        {
                          "url": "https://cdn.revid.ai/ai-gen/OZxUbirp4.jpg",
                          "title": "Three women appear as silhouettes in front of a giant glowing sun in a dark indigo sky.",
                          "type": "image"
                        },
                        {
                          "url": "https://cdn.revid.ai/ai-gen/xA1PjFVGorg.jpg",
                          "title": "A woman with a sleek black bob stands in a neon-lit glass hallway with rain outside.",
                          "type": "image"
                        }
                      ]
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "position": "bottom"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeReferenceImage": {
                  "summary": "Recipe: Prompt with a reference image",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "this is an example",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "ai-video",
                      "imageModel": "ultra",
                      "videoModel": "ultra",
                      "mediaPreset": "ANIME",
                      "addAudioToVideos": true,
                      "provided": [
                        {
                          "url": "https://cdn.revid.ai/uploads/1777872884798-image.png",
                          "title": "",
                          "type": "image"
                        }
                      ]
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Ali",
                      "position": "bottom"
                    },
                    "options": {
                      "promptTargetDuration": 30
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeStockFootage": {
                  "summary": "Recipe: Script with stock footage",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "this is my video text"
                    },
                    "media": {
                      "type": "stock-video",
                      "density": "high"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "stability": 0.2,
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "music": {
                      "trackName": "Observer"
                    }
                  }
                },
                "RecipeXLinkedinPost": {
                  "summary": "Recipe: X/LinkedIn post to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "https://x.com/tibo_maker/status/1848647301998284964"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "options": {
                      "summarizationPreference": "summarize"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeVideoQuiz": {
                  "summary": "Recipe: Quiz video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "script-to-video",
                    "source": {
                      "text": "https://x.com/tibo_maker/status/1848647301998284964"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "advanced": {
                      "customCreationParams": {
                        "quizzData": {
                          "title": "France",
                          "questions": [
                            {
                              "id": "82e14b8f-07ce-4489-9c35-6d9c10872b4e",
                              "question": "What is France",
                              "answers": [
                                {
                                  "id": "a62c6e91-da4b-491a-8f36-ba67caa5838a",
                                  "answer": "a country",
                                  "isCorrect": true
                                },
                                {
                                  "id": "10c89812-22f8-47df-88ef-f11e318fdb1c",
                                  "answer": "a city",
                                  "isCorrect": false
                                }
                              ]
                            }
                          ]
                        }
                      }
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipePdfToVideo": {
                  "summary": "Recipe: PDF to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "caption-video",
                    "source": {
                      "url": "https://cdn.revid.ai/uploads/1772035824673-application.pdf"
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "cheap",
                      "videoModel": "base"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "nPczCjzI2devNBz1zQrb",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "position": "bottom"
                    },
                    "aspectRatio": "9:16"
                  }
                },
                "RecipeNewsVideo": {
                  "summary": "Recipe: News to video",
                  "value": {
                    "webhookUrl": "https://your-server.com/revid/webhook",
                    "workflow": "prompt-to-video",
                    "source": {
                      "prompt": "news about France",
                      "durationSeconds": 40
                    },
                    "media": {
                      "type": "moving-image",
                      "density": "medium",
                      "animation": "dynamic",
                      "imageModel": "good",
                      "videoModel": "ultra"
                    },
                    "voice": {
                      "enabled": true,
                      "voiceId": "cgSgspJ2msm6clMCkdW9",
                      "speed": 1
                    },
                    "captions": {
                      "enabled": true,
                      "preset": "Wrap 1",
                      "position": "bottom"
                    },
                    "options": {
                      "promptTargetDuration": 30,
                      "fetchNews": true
                    },
                    "advanced": {
                      "customCreationParams": {
                        "promptCustomRules": "Use recent factual sources and structure as a professional news report."
                      }
                    },
                    "aspectRatio": "9:16"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Estimated credit breakdown for the given payload.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Estimated credit breakdown for the given payload."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/status": {
      "get": {
        "operationId": "getStatus",
        "summary": "Get render status",
        "description": "Poll the status of a project created by POST /render.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "pid",
            "in": "query",
            "required": true,
            "description": "Project id returned by POST /render.",
            "schema": {
              "type": "string",
              "description": "Project id returned by POST /render."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Project status (building/rendering/ready/error), progress, and the output video URL when ready.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Project status (building/rendering/ready/error), progress, and the output video URL when ready."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/projects": {
      "get": {
        "operationId": "getProjects",
        "summary": "List projects",
        "description": "List projects owned by the API key's workspace.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "description": "Maximum number of projects to return.",
            "schema": {
              "type": "integer",
              "default": 100,
              "description": "Maximum number of projects to return."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Array of projects with ids, names, statuses, and output URLs.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Array of projects with ids, names, statuses, and output URLs."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Get account info",
        "description": "Account, credits, subscription, and workspace info for the API key.",
        "tags": [
          "Account & billing"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "{ success, email, totalCredits, user, workspace, credits: { regular, nonExpiring, total }, subscription, usage }.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ success, email, totalCredits, user, workspace, credits: { regular, nonExpiring, total }, subscription, usage }."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/export-video": {
      "post": {
        "operationId": "postExportVideo",
        "summary": "Export project to mp4",
        "description": "Render an mp4 export of an existing project.\n\n**Cost:** 10 credits.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "pid"
                ],
                "properties": {
                  "pid": {
                    "type": "string",
                    "description": "Project id to export. Must belong to the API key user."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Export result with the video file URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Export result with the video file URL."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/rename-project": {
      "post": {
        "operationId": "postRenameProject",
        "summary": "Rename project",
        "description": "Rename a project owned by the API key user.",
        "tags": [
          "Projects"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "pid",
                  "name"
                ],
                "properties": {
                  "pid": {
                    "type": "string",
                    "description": "Project id."
                  },
                  "name": {
                    "type": "string",
                    "description": "New project name."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ success: 1 } on success.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ success: 1 } on success."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/add-to-queue": {
      "post": {
        "operationId": "postAddToQueue",
        "summary": "Schedule publishing",
        "description": "Add a rendered video to your publishing queue; it is scheduled at the next available slot of the channel.",
        "tags": [
          "Publishing"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "videoUrl"
                ],
                "properties": {
                  "videoUrl": {
                    "type": "string",
                    "description": "Public URL of the rendered video to publish."
                  },
                  "channelName": {
                    "type": "string",
                    "description": "Name of a channel configured in your Revid account settings. Mutually exclusive with platform accounts."
                  },
                  "channelId": {
                    "type": "string",
                    "description": "Channel id, alternative to channelName."
                  },
                  "tiktok": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "TikTok target: { username or id, title?, privacy_level? }. privacy_level: PUBLIC_TO_EVERYONE, FOLLOWER_OF_CREATOR, MUTUAL_FOLLOW_FRIENDS, SELF_ONLY."
                  },
                  "youtube": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "YouTube target: { username or id, title?, description? }."
                  },
                  "instagram": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Instagram target: { username or id, caption? }."
                  },
                  "webhook": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Webhook target: { username or id }. Posts the video to your configured webhook."
                  },
                  "extraParams": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Extra fields stored on the scheduled content (title, description, ...)."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Scheduled content entry with the computed publish time.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Scheduled content entry with the computed publish time."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/publish-now": {
      "post": {
        "operationId": "postPublishNow",
        "summary": "Publish immediately",
        "description": "Publish a rendered video right now to a channel or specific platform accounts.",
        "tags": [
          "Publishing"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "videoUrl"
                ],
                "properties": {
                  "videoUrl": {
                    "type": "string",
                    "description": "Public URL of the rendered video to publish."
                  },
                  "channelName": {
                    "type": "string",
                    "description": "Name of a channel configured in your Revid account settings. Mutually exclusive with platform accounts."
                  },
                  "channelId": {
                    "type": "string",
                    "description": "Channel id, alternative to channelName."
                  },
                  "tiktok": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "TikTok target: { username or id, title?, privacy_level? }. privacy_level: PUBLIC_TO_EVERYONE, FOLLOWER_OF_CREATOR, MUTUAL_FOLLOW_FRIENDS, SELF_ONLY."
                  },
                  "youtube": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "YouTube target: { username or id, title?, description? }."
                  },
                  "instagram": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Instagram target: { username or id, caption? }."
                  },
                  "webhook": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Webhook target: { username or id }. Posts the video to your configured webhook."
                  },
                  "extraParams": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Extra fields stored on the scheduled content (title, description, ...)."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Publish result per platform.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Publish result per platform."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/consistent-characters": {
      "get": {
        "operationId": "getConsistentCharacters",
        "summary": "List characters",
        "description": "List saved consistent characters (avatar-based and LoRA-trained), newest first.",
        "tags": [
          "Characters & voices"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Array of { id, name, description, imageUrl, contentType, source: avatar|lora, createdAt }.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Array of { id, name, description, imageUrl, contentType, source: avatar|lora, createdAt }."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "postConsistentCharacters",
        "summary": "Create character",
        "description": "Save a consistent character usable in renders (characterIds) and as a talking avatar.",
        "tags": [
          "Characters & voices"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "description",
                  "imageUrl"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minimum": 3,
                    "description": "Character name (min 3 characters)."
                  },
                  "description": {
                    "type": "string",
                    "minimum": 10,
                    "description": "Character description (min 10 characters) — used by the AI to decide when/how to use the character."
                  },
                  "imageUrl": {
                    "type": "string",
                    "description": "Public URL of the character image."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created character with its id.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Created character with its id."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "deleteConsistentCharacters",
        "summary": "Delete character",
        "description": "Delete a character by id (works for avatar-based and LoRA characters).",
        "tags": [
          "Characters & voices"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "query",
            "required": true,
            "description": "Character id (also accepted in the body).",
            "schema": {
              "type": "string",
              "description": "Character id (also accepted in the body)."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "{ success, deleted: id, source: avatar|lora }.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ success, deleted: id, source: avatar|lora }."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/voice-clone": {
      "post": {
        "operationId": "postVoiceClone",
        "summary": "Clone a voice",
        "description": "Clone a custom voice from a public audio sample. Requires the Elite plan or above (10 voices on Elite, 100 on Enterprise).",
        "tags": [
          "Characters & voices"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "voiceUrl"
                ],
                "properties": {
                  "name": {
                    "type": "string",
                    "minimum": 3,
                    "description": "Voice name (min 3 characters)."
                  },
                  "description": {
                    "type": "string",
                    "description": "Voice description."
                  },
                  "voiceUrl": {
                    "type": "string",
                    "description": "Public URL of the audio sample (mp3, wav, ...)."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ success, voiceId, voice } — use voiceId as voice.voiceId in renders.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ success, voiceId, voice } — use voiceId as voice.voiceId in renders."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/generate-media": {
      "post": {
        "operationId": "postGenerateMedia",
        "summary": "Generate standalone media",
        "description": "Generate images or video clips without creating a video project (same engine as the Revid media generator).",
        "tags": [
          "Media generation"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "mediaType": {
                    "type": "string",
                    "default": "image",
                    "enum": [
                      "image",
                      "video"
                    ],
                    "x-enumDescriptions": {
                      "image": "Generate 1-10 images.",
                      "video": "Generate one video clip."
                    },
                    "description": "What to generate."
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Generation prompt. Aliases: source.prompt, input."
                  },
                  "ratio": {
                    "type": "string",
                    "default": "9:16",
                    "description": "Aspect ratio: 1:1, 9:16, 16:9 (aliases square/portrait/landscape). Alias: aspectRatio."
                  },
                  "imageQuality": {
                    "type": "string",
                    "default": "good",
                    "enum": [
                      "cheap",
                      "good",
                      "ultra"
                    ],
                    "x-enumDescriptions": {
                      "cheap": "Basic image model. (~1 credits)",
                      "good": "Enhanced image model. (~4 credits)",
                      "ultra": "Best image model. (~16 credits)"
                    },
                    "description": "Image model: cheap, good, ultra. Alias: media.imageModel."
                  },
                  "videoQuality": {
                    "type": "string",
                    "default": "base",
                    "enum": [
                      "base",
                      "pro",
                      "ultra",
                      "veo3",
                      "sora2"
                    ],
                    "x-enumDescriptions": {
                      "base": "Fast, basic motion. (~15 credits)",
                      "pro": "Better motion. (~60 credits)",
                      "ultra": "Top general-purpose model. (~200 credits)",
                      "veo3": "Google Veo 3. (~100 credits)",
                      "sora2": "OpenAI Sora 2. (~130 credits)"
                    },
                    "description": "Video model: base, pro, ultra, veo3, sora2. Alias: media.videoModel."
                  },
                  "count": {
                    "type": "integer",
                    "default": 1,
                    "minimum": 1,
                    "maximum": 10,
                    "description": "Number of images (videos: always 1). Aliases: imageCount, options.outputCount."
                  },
                  "duration": {
                    "type": "integer",
                    "default": 5,
                    "minimum": 1,
                    "maximum": 60,
                    "description": "Video duration in seconds (video only)."
                  },
                  "generationPreset": {
                    "type": "string",
                    "description": "Visual style preset slug (same list as media.mediaPreset)."
                  },
                  "firstFrame": {
                    "type": "string",
                    "description": "URL of the first frame to animate from (video only)."
                  },
                  "lastFrame": {
                    "type": "string",
                    "description": "URL of the last frame to animate to (video only)."
                  },
                  "referenceImages": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Reference image URLs (max 4 for images, 9 for videos)."
                  },
                  "referenceVideos": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Reference video URLs (max 3)."
                  },
                  "referenceAudios": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Reference audio URLs (max 3)."
                  },
                  "enableAudio": {
                    "type": "boolean",
                    "default": false,
                    "description": "Generate ambient audio with the video clip."
                  },
                  "selectedCharacters": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "description": "Consistent character ids to feature (max 12). Alias: characterIds."
                  },
                  "improvePrompt": {
                    "type": "boolean",
                    "default": false,
                    "description": "Let the AI rewrite/improve the prompt before generation."
                  },
                  "withTranscript": {
                    "type": "boolean",
                    "default": false,
                    "description": "Return a transcript with the generated media."
                  },
                  "voiceId": {
                    "type": "string",
                    "description": "Voice id when generating media with speech."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "{ success, mediaType, generationOptions, ...generation result with media URLs }.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "{ success, mediaType, generationOptions, ...generation result with media URLs }."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/public/v3/buy-credit-pack": {
      "post": {
        "operationId": "postBuyCreditPack",
        "summary": "Buy credit pack (auto top-up)",
        "description": "Charge the saved payment method for a credit pack. Used for automated top-up flows.",
        "tags": [
          "Account & billing"
        ],
        "security": [
          {
            "ApiKeyAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "source"
                ],
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": [
                      "auto_topup"
                    ],
                    "x-enumDescriptions": {
                      "auto_topup": "The only supported source."
                    },
                    "description": "Must be \"auto_topup\"."
                  }
                },
                "additionalProperties": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Invoice metadata for the purchase.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "additionalProperties": true,
                  "description": "Invoice metadata for the purchase."
                }
              }
            }
          },
          "400": {
            "description": "Validation error — the message names the exact field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          },
          "500": {
            "description": "Internal error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RenderErrorResponse"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "key",
        "description": "Your Revid API key, from https://www.revid.ai/account"
      }
    },
    "schemas": {
      "RenderRequest": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/RenderRequestScriptToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestPromptToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestAudioToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestMusicToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestArticleToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestAvatarToVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestStaticBackgroundVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestMotionTransfer"
          },
          {
            "$ref": "#/components/schemas/RenderRequestCaptionVideo"
          },
          {
            "$ref": "#/components/schemas/RenderRequestAdGenerator"
          }
        ],
        "discriminator": {
          "propertyName": "workflow",
          "mapping": {
            "script-to-video": "#/components/schemas/RenderRequestScriptToVideo",
            "voiceover-to-video": "#/components/schemas/RenderRequestScriptToVideo",
            "prompt-to-video": "#/components/schemas/RenderRequestPromptToVideo",
            "audio-to-video": "#/components/schemas/RenderRequestAudioToVideo",
            "music-to-video": "#/components/schemas/RenderRequestMusicToVideo",
            "article-to-video": "#/components/schemas/RenderRequestArticleToVideo",
            "avatar-to-video": "#/components/schemas/RenderRequestAvatarToVideo",
            "static-background-video": "#/components/schemas/RenderRequestStaticBackgroundVideo",
            "motion-transfer": "#/components/schemas/RenderRequestMotionTransfer",
            "caption-video": "#/components/schemas/RenderRequestCaptionVideo",
            "ad-generator": "#/components/schemas/RenderRequestAdGenerator"
          }
        },
        "description": "The request shape depends on `workflow` — select one to see exactly which fields apply."
      },
      "RenderRequestScriptToVideo": {
        "type": "object",
        "title": "Script to video request",
        "description": "Turn a written script into a voiced, captioned video with AI visuals.\n\nRequires: source.text.\n\n`voiceover-to-video` is an accepted alias for this workflow.\n\nsource.text can also be a URL to an X/Twitter or LinkedIn post: the post content becomes the script.\n\nUse media.type = stock-video for real stock footage instead of AI visuals.\n\nUse media.type = custom with media.provided[] to use only your own images/videos.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "script-to-video",
              "voiceover-to-video"
            ],
            "description": "Turn a written script into a voiced, captioned video with AI visuals. (`voiceover-to-video` accepted as alias)"
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string",
                "description": "The exact script to be spoken. For script-to-video it can also be an X/Twitter or LinkedIn post URL: the post content becomes the script. Workflows: script-to-video, avatar-to-video, static-background-video. Accepted aliases: inputText, input."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "text"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "avatar": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Show a talking avatar in the video. Default: true for avatar-to-video, false otherwise. Accepted aliases: hasAvatar."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Image (png/jpg/webp) or video of the avatar. Accepted aliases: selectedAvatar."
              },
              "mimeType": {
                "type": "string",
                "description": "Mime type of avatar.url. Inferred from the extension when omitted (defaults to video/mp4 for unknown extensions). Accepted aliases: selectedAvatarType."
              },
              "imageModel": {
                "type": "string",
                "default": "good",
                "description": "Model used to animate the avatar. Accepted aliases: avatarImageModel."
              },
              "removeBackground": {
                "type": "boolean",
                "default": false,
                "description": "Remove the avatar's background before compositing. Accepted aliases: removeAvatarBackground."
              }
            },
            "additionalProperties": false,
            "description": "Optional — disabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "summarizationPreference": {
                "type": "string",
                "enum": [
                  "summarize",
                  "summarizeIfLong",
                  "no-summarization"
                ],
                "x-enumDescriptions": {
                  "summarize": "Always summarize to a short script.",
                  "summarizeIfLong": "Summarize only when the source is long.",
                  "no-summarization": "Use the content as-is."
                },
                "description": "How to condense source content into the script. Workflows: article-to-video, script-to-video."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestPromptToVideo": {
        "type": "object",
        "title": "Prompt to video request",
        "description": "Describe the video you want; the AI writes the script and generates everything.\n\nRequires: source.prompt.\n\nTune length with options.promptTargetDuration (seconds, or \"auto\" to let the AI decide).\n\nsource.stylePrompt steers the visual style; source.durationSeconds hints the script length.\n\nPass characterIds to feature your saved consistent characters.\n\nAdd a reference image in media.provided[] to guide the visual generation.\n\nSet advanced.customCreationParams.fetchNews = true to ground the script in recent news.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "prompt-to-video"
            ],
            "description": "Describe the video you want; the AI writes the script and generates everything."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "description": "What the video should be about: the AI writes the script. For music-to-video it is an optional creative brief for the visual storyline. Workflows: prompt-to-video, ad-generator, music-to-video. Accepted aliases: prompt, input."
              },
              "stylePrompt": {
                "type": "string",
                "description": "Visual style instructions, separate from the content prompt (e.g. \"dark mood\", \"pastel watercolor\"). Workflows: prompt-to-video, ad-generator. Accepted aliases: options.stylePrompt, stylePrompt, visualDirection."
              },
              "durationSeconds": {
                "type": "number",
                "minimum": 5,
                "maximum": 1800,
                "default": 40,
                "description": "Hint for the script length the AI writes, in seconds. Workflows: prompt-to-video, ad-generator. Accepted aliases: options.durationSeconds, durationSeconds."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "prompt"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "promptTargetDuration": {
                "oneOf": [
                  {
                    "type": "number",
                    "minimum": 5,
                    "maximum": 1800
                  },
                  {
                    "type": "string",
                    "enum": [
                      "auto"
                    ]
                  }
                ],
                "default": 30,
                "description": "Target video duration in seconds for prompt-driven workflows, or \"auto\" to let the AI choose. Workflows: prompt-to-video, ad-generator. Accepted aliases: promptTargetDuration, options.targetDuration (in prompt workflows)."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "fetchNews": {
                "type": "boolean",
                "default": false,
                "description": "Ground the script in recent news fetched for the prompt topic. Workflows: prompt-to-video."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestAudioToVideo": {
        "type": "object",
        "title": "Audio to video request",
        "description": "Turn a podcast, voice note, or any audio/video URL into an illustrated video.\n\nRequires: source.url.\n\nThe source audio is kept as the voice track; voice generation is not used.\n\noptions.useWholeAudio defaults to true. Set it to false to extract highlight segments instead.\n\nYouTube links are supported as source.url.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "audio-to-video"
            ],
            "description": "Turn a podcast, voice note, or any audio/video URL into an illustrated video."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "recordingType": {
                "type": "string",
                "enum": [
                  "video",
                  "audio"
                ],
                "x-enumDescriptions": {
                  "video": "Treat the source as a video recording.",
                  "audio": "Treat the source as audio-only."
                },
                "description": "Hint for how to treat source.url. Inferred from the file extension when omitted (.mp3/.wav/.m4a/.aac are audio, everything else video). Workflows: audio-to-video, music-to-video, caption-video."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "bRollType": {
                "type": "string",
                "description": "B-roll composition mode: how generated B-roll mixes with the main footage. Common values: split-screen, fullscreen. Workflows: avatar-to-video, audio-to-video, caption-video."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              },
              "autoCrop": {
                "type": "boolean",
                "default": false,
                "description": "Auto-reframe the source video for the target aspect ratio (face tracking). Costs extra credits. Workflows: caption-video, audio-to-video."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — disabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "targetDuration": {
                "type": "integer",
                "minimum": 1,
                "description": "Target output duration in seconds for URL-driven workflows. In prompt workflows this acts as an alias of options.promptTargetDuration. Workflows: article-to-video, audio-to-video, music-to-video, caption-video. Accepted aliases: targetDuration."
              },
              "useWholeAudio": {
                "type": "boolean",
                "description": "Use the full source audio (true) or extract highlight segments (false). Default: true for audio-to-video, false otherwise. Workflows: audio-to-video. Accepted aliases: useWholeAudio."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "hasToTranscript": {
                "type": "boolean",
                "default": false,
                "description": "Force transcription of the source audio (needed for captions on uploaded audio/video). Workflows: audio-to-video, music-to-video, caption-video. Accepted aliases: hasToTranscript."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestMusicToVideo": {
        "type": "object",
        "title": "Music to video request",
        "description": "Generate a music video synced to a track (upload, YouTube, or Spotify link).\n\nRequires: source.url.\n\nThe source track is the audio; the music block controls sync (music.syncWith) and visuals (music.soundWave).\n\nsource.prompt is an optional creative brief for the visual storyline.\n\nmusic.enableLyricsLipSync + music.lipSyncFrequency animate characters singing the lyrics.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "music-to-video"
            ],
            "description": "Generate a music video synced to a track (upload, YouTube, or Spotify link)."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "description": "What the video should be about: the AI writes the script. For music-to-video it is an optional creative brief for the visual storyline. Workflows: prompt-to-video, ad-generator, music-to-video. Accepted aliases: prompt, input."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "recordingType": {
                "type": "string",
                "enum": [
                  "video",
                  "audio"
                ],
                "x-enumDescriptions": {
                  "video": "Treat the source as a video recording.",
                  "audio": "Treat the source as audio-only."
                },
                "description": "Hint for how to treat source.url. Inferred from the file extension when omitted (.mp3/.wav/.m4a/.aac are audio, everything else video). Workflows: audio-to-video, music-to-video, caption-video."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              },
              "soundWave": {
                "type": "boolean",
                "default": false,
                "description": "Overlay an animated waveform visual. Workflows: music-to-video. Accepted aliases: hasSoundWave."
              },
              "syncWith": {
                "type": "string",
                "enum": [
                  "beats",
                  "lyrics"
                ],
                "x-enumDescriptions": {
                  "beats": "Cut on the beat grid.",
                  "lyrics": "Cut on lyric lines."
                },
                "description": "Sync visual cuts to the music. Workflows: music-to-video. Accepted aliases: syncMusicWith."
              },
              "enableLyricsLipSync": {
                "type": "boolean",
                "default": false,
                "description": "Animate characters lip-syncing the lyrics. Workflows: music-to-video. Accepted aliases: options.enableLyricsLipSync, enableLyricsLipSync."
              },
              "lipSyncFrequency": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.3,
                "description": "Fraction of the video duration with lip-synced shots (0.3 = 30%). Workflows: music-to-video. Accepted aliases: options.lipSyncFrequency, lipSyncFrequency."
              },
              "generateLyricsFromPrompt": {
                "type": "boolean",
                "default": false,
                "description": "Generate lyrics from the prompt instead of transcribing the track. Workflows: music-to-video. Accepted aliases: hasToGenerateLyricsFromPrompt."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "options": {
            "type": "object",
            "properties": {
              "targetDuration": {
                "type": "integer",
                "minimum": 1,
                "description": "Target output duration in seconds for URL-driven workflows. In prompt workflows this acts as an alias of options.promptTargetDuration. Workflows: article-to-video, audio-to-video, music-to-video, caption-video. Accepted aliases: targetDuration."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "hasToTranscript": {
                "type": "boolean",
                "default": false,
                "description": "Force transcription of the source audio (needed for captions on uploaded audio/video). Workflows: audio-to-video, music-to-video, caption-video. Accepted aliases: hasToTranscript."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestArticleToVideo": {
        "type": "object",
        "title": "Article to video request",
        "description": "Summarize any web page or article into a narrated short video.\n\nRequires: source.url.\n\nControl summarization with options.summarizationPreference and length with options.targetDuration.\n\nsource.scrapingPrompt gives custom instructions for extracting content from the page.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "article-to-video"
            ],
            "description": "Summarize any web page or article into a narrated short video."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "scrapingPrompt": {
                "type": "string",
                "description": "Custom instructions for extracting content from the source page (e.g. \"focus on the pricing section\"). Workflows: article-to-video. Accepted aliases: options.scrapingPrompt, scrapingPrompt."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "targetDuration": {
                "type": "integer",
                "minimum": 1,
                "description": "Target output duration in seconds for URL-driven workflows. In prompt workflows this acts as an alias of options.promptTargetDuration. Workflows: article-to-video, audio-to-video, music-to-video, caption-video. Accepted aliases: targetDuration."
              },
              "summarizationPreference": {
                "type": "string",
                "enum": [
                  "summarize",
                  "summarizeIfLong",
                  "no-summarization"
                ],
                "x-enumDescriptions": {
                  "summarize": "Always summarize to a short script.",
                  "summarizeIfLong": "Summarize only when the source is long.",
                  "no-summarization": "Use the content as-is."
                },
                "description": "How to condense source content into the script. Workflows: article-to-video, script-to-video."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestAvatarToVideo": {
        "type": "object",
        "title": "Avatar to video request",
        "description": "A talking avatar (from a photo or video) reads your script, with optional B-roll.\n\nRequires: source.text + avatar.url.\n\navatar.url accepts an image (png/jpg/webp) or a video; mimeType is inferred from the extension when omitted.\n\nmedia.bRollType (split-screen, fullscreen) mixes generated B-roll with the avatar.\n\nmedia.placeAvatarInContext = true places the avatar inside the generated scenes.",
        "required": [
          "workflow",
          "source",
          "avatar"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "avatar-to-video"
            ],
            "description": "A talking avatar (from a photo or video) reads your script, with optional B-roll."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string",
                "description": "The exact script to be spoken. For script-to-video it can also be an X/Twitter or LinkedIn post URL: the post content becomes the script. Workflows: script-to-video, avatar-to-video, static-background-video. Accepted aliases: inputText, input."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "text"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "bRollType": {
                "type": "string",
                "description": "B-roll composition mode: how generated B-roll mixes with the main footage. Common values: split-screen, fullscreen. Workflows: avatar-to-video, audio-to-video, caption-video."
              },
              "placeAvatarInContext": {
                "type": "boolean",
                "default": false,
                "description": "Place the avatar inside the generated scenes instead of overlaying it. Workflows: avatar-to-video. Accepted aliases: avatar.placeInContext, placeAvatarInContext."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — disabled by default for this workflow."
          },
          "avatar": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Show a talking avatar in the video. Default: true for avatar-to-video, false otherwise. Accepted aliases: hasAvatar."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "Image (png/jpg/webp) or video of the avatar. Accepted aliases: selectedAvatar."
              },
              "mimeType": {
                "type": "string",
                "description": "Mime type of avatar.url. Inferred from the extension when omitted (defaults to video/mp4 for unknown extensions). Accepted aliases: selectedAvatarType."
              },
              "imageModel": {
                "type": "string",
                "default": "good",
                "description": "Model used to animate the avatar. Accepted aliases: avatarImageModel."
              },
              "removeBackground": {
                "type": "boolean",
                "default": false,
                "description": "Remove the avatar's background before compositing. Accepted aliases: removeAvatarBackground."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestStaticBackgroundVideo": {
        "type": "object",
        "title": "Static background video request",
        "description": "Voiced captions over a looping background (gameplay, satisfying clips, ...).\n\nRequires: source.text or source.url.\n\nSet the loop with media.backgroundVideo ({ type: \"video\", url, ... }). Without it, Revid falls back to default backgrounds.\n\nbackgroundVideo.noReencode = true skips re-encoding for known-good mp4 sources (faster renders).",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "static-background-video"
            ],
            "description": "Voiced captions over a looping background (gameplay, satisfying clips, ...)."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "text": {
                "type": "string",
                "description": "The exact script to be spoken. For script-to-video it can also be an X/Twitter or LinkedIn post URL: the post content becomes the script. Workflows: script-to-video, avatar-to-video, static-background-video. Accepted aliases: inputText, input."
              },
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "backgroundVideo": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/MediaItem"
                  }
                ],
                "description": "The background loop media item ({ type: \"video\", url, urlLowRes?, imagePreview?, noReencode? }). Workflows: static-background-video. Accepted aliases: selectedBackgroundMedia."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestMotionTransfer": {
        "type": "object",
        "title": "Motion transfer request",
        "description": "Transfer the motion of a source video onto a character image (face swap style).\n\nRequires: source.url + media.provided[] with 1 image (the target character).\n\nmedia.provided[] must contain the target character image. The server does not reject a missing image upfront, but generation fails without it.\n\nmetadata.duration (seconds of the source video) speeds up processing.",
        "required": [
          "workflow",
          "source",
          "media"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "motion-transfer"
            ],
            "description": "Transfer the motion of a source video onto a character image (face swap style)."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "required": [
              "provided"
            ],
            "description": "Required for this workflow."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — disabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestCaptionVideo": {
        "type": "object",
        "title": "Caption video request",
        "description": "Add animated captions (and optional B-roll) to an existing video.\n\nRequires: source.url.\n\ncaptions.autoCrop = true reframes the video for vertical formats (face tracking).\n\nPDF URLs are also accepted as source.url: each page becomes a narrated section.\n\nmetadata.duration (seconds) speeds up processing.",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "caption-video"
            ],
            "description": "Add animated captions (and optional B-roll) to an existing video."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "url": {
                "type": "string",
                "format": "uri",
                "description": "The source content URL: audio file, video file, YouTube link, Spotify track, article page, or PDF depending on the workflow. http(s) is enforced; bare domains get https:// prepended. Workflows: audio-to-video, music-to-video, article-to-video, motion-transfer, caption-video, static-background-video."
              },
              "recordingType": {
                "type": "string",
                "enum": [
                  "video",
                  "audio"
                ],
                "x-enumDescriptions": {
                  "video": "Treat the source as a video recording.",
                  "audio": "Treat the source as audio-only."
                },
                "description": "Hint for how to treat source.url. Inferred from the file extension when omitted (.mp3/.wav/.m4a/.aac are audio, everything else video). Workflows: audio-to-video, music-to-video, caption-video."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "required": [
              "url"
            ],
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "bRollType": {
                "type": "string",
                "description": "B-roll composition mode: how generated B-roll mixes with the main footage. Common values: split-screen, fullscreen. Workflows: avatar-to-video, audio-to-video, caption-video."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              },
              "autoCrop": {
                "type": "boolean",
                "default": false,
                "description": "Auto-reframe the source video for the target aspect ratio (face tracking). Costs extra credits. Workflows: caption-video, audio-to-video."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "targetDuration": {
                "type": "integer",
                "minimum": 1,
                "description": "Target output duration in seconds for URL-driven workflows. In prompt workflows this acts as an alias of options.promptTargetDuration. Workflows: article-to-video, audio-to-video, music-to-video, caption-video. Accepted aliases: targetDuration."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "hasToTranscript": {
                "type": "boolean",
                "default": false,
                "description": "Force transcription of the source audio (needed for captions on uploaded audio/video). Workflows: audio-to-video, music-to-video, caption-video. Accepted aliases: hasToTranscript."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "RenderRequestAdGenerator": {
        "type": "object",
        "title": "Ad generator request",
        "description": "Generate a product ad from a prompt and/or product images.\n\nRequires: source.prompt or media.provided[].\n\nProvide product images in media.provided[]: the generation reuses them as visual anchors.\n\nTune length with options.promptTargetDuration (seconds or \"auto\").",
        "required": [
          "workflow",
          "source"
        ],
        "properties": {
          "workflow": {
            "type": "string",
            "enum": [
              "ad-generator"
            ],
            "description": "Generate a product ad from a prompt and/or product images."
          },
          "webhookUrl": {
            "type": "string",
            "format": "uri",
            "example": "https://your-server.com/revid/webhook",
            "description": "Public URL called when the render finishes (success or failure). Strongly recommended over polling. Accepted aliases: webhook."
          },
          "projectId": {
            "type": "string",
            "description": "Reuse an existing project instead of creating a new one. The project must belong to the API key's workspace. Accepted aliases: pid."
          },
          "aspectRatio": {
            "type": "string",
            "default": "9:16",
            "enum": [
              "9:16",
              "16:9",
              "1:1",
              "auto"
            ],
            "x-enumDescriptions": {
              "9:16": "Vertical 9:16 — TikTok, Reels, Shorts. Aliases: portrait, \"9 / 16\".",
              "16:9": "Horizontal 16:9 — YouTube, web. Aliases: landscape, \"16 / 9\".",
              "1:1": "Square 1:1 — feeds. Aliases: square, \"1 / 1\".",
              "auto": "Let Revid choose based on the source content."
            },
            "description": "Output aspect ratio. Accepted aliases: ratio."
          },
          "metadata": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "Free-form object stored with the project and echoed in webhooks. For URL sources, metadata.duration (seconds) speeds up processing."
          },
          "characterIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "IDs of saved consistent characters to feature in the video. Get IDs from GET /api/public/v3/consistent-characters. Selecting characters can force media.imageModel to ultra when the preset requires it. Accepted aliases: selectedCharacters, options.characterIds, options.selectedCharacters."
          },
          "source": {
            "type": "object",
            "properties": {
              "prompt": {
                "type": "string",
                "description": "What the video should be about: the AI writes the script. For music-to-video it is an optional creative brief for the visual storyline. Workflows: prompt-to-video, ad-generator, music-to-video. Accepted aliases: prompt, input."
              },
              "stylePrompt": {
                "type": "string",
                "description": "Visual style instructions, separate from the content prompt (e.g. \"dark mood\", \"pastel watercolor\"). Workflows: prompt-to-video, ad-generator. Accepted aliases: options.stylePrompt, stylePrompt, visualDirection."
              },
              "durationSeconds": {
                "type": "number",
                "minimum": 5,
                "maximum": 1800,
                "default": 40,
                "description": "Hint for the script length the AI writes, in seconds. Workflows: prompt-to-video, ad-generator. Accepted aliases: options.durationSeconds, durationSeconds."
              },
              "websiteToRecord": {
                "type": "string",
                "format": "uri",
                "description": "URL of a website to screen-record as footage for the video. Accepted aliases: websiteToRecord."
              },
              "quizzData": {
                "type": "object",
                "additionalProperties": true,
                "description": "Quiz definition for quiz videos: { title, questions: [{ id, question, answers: [{ id, answer, isCorrect }] }] }. Accepted aliases: options.quizzData, quizzData."
              }
            },
            "additionalProperties": false,
            "description": "Required for this workflow."
          },
          "media": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "moving-image",
                  "ai-video",
                  "stock-video",
                  "custom"
                ],
                "x-enumDescriptions": {
                  "moving-image": "AI images animated with motion effects. Best cost/quality balance, works with media.animation. (~1-16 per image credits)",
                  "ai-video": "Fully AI-generated video clips (most cinematic, highest cost). Forces media.imageModel to ultra. \"video\" is an accepted alias. (~15-400 per clip credits)",
                  "stock-video": "Real stock footage matched to the script. No AI generation cost.",
                  "custom": "Use only the media you supply in media.provided[] (at least one item required)."
                },
                "description": "The visual engine for the video. Default: moving-image for most workflows; ai-video for prompt-to-video and audio-to-video."
              },
              "quality": {
                "type": "string",
                "default": "pro",
                "enum": [
                  "standard",
                  "pro",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "standard": "Fastest and cheapest. moving-image: cheap images + base video. ai-video: good images + base video. Aliases: base, fast.",
                  "pro": "Default. moving-image: good images + ultra video. ai-video: good images + pro video. Aliases: balanced, good, high.",
                  "ultra": "Best quality: ultra images + ultra video everywhere. Alias: best."
                },
                "description": "Convenience profile that picks imageModel + videoModel for you. Explicit media.imageModel / media.videoModel override it."
              },
              "imageModel": {
                "type": "string",
                "enum": [
                  "cheap",
                  "good",
                  "ultra"
                ],
                "x-enumDescriptions": {
                  "cheap": "Basic image model. (~1 credits)",
                  "good": "Enhanced image model — better detail and prompt adherence. (~4 credits)",
                  "ultra": "Best image model — required for consistent characters with most presets. (~16 credits)"
                },
                "description": "Image generation model. Auto-adjusted when needed: ai-video forces ultra, and presets/characters can upgrade it. Accepted aliases: imageGenerationModel."
              },
              "videoModel": {
                "type": "string",
                "enum": [
                  "base",
                  "pro",
                  "ultra",
                  "veo3",
                  "sora2"
                ],
                "x-enumDescriptions": {
                  "base": "Fast, basic motion. (~15 credits)",
                  "pro": "Better motion and coherence. (~60 credits)",
                  "ultra": "Top general-purpose model. (~200 credits)",
                  "veo3": "Google Veo 3 — strong realism and physics. (~100 credits)",
                  "sora2": "OpenAI Sora 2 — strong scene composition. (~130 credits)"
                },
                "description": "Video generation model used when video clips are generated. Accepted aliases: videoGenerationModel."
              },
              "density": {
                "type": "string",
                "enum": [
                  "low",
                  "medium",
                  "high"
                ],
                "x-enumDescriptions": {
                  "low": "Few scene changes. Alias: few.",
                  "medium": "Balanced pacing. Alias: normal.",
                  "high": "Fast-paced, many visuals. Alias: more."
                },
                "description": "How many distinct visuals per minute of video. More visuals = livelier video and higher generation cost. Accepted aliases: mediaMultiplier."
              },
              "animation": {
                "type": "string",
                "default": "soft",
                "enum": [
                  "none",
                  "soft",
                  "dynamic",
                  "depth"
                ],
                "x-enumDescriptions": {
                  "none": "Static images, no motion.",
                  "soft": "Subtle pan/zoom (default).",
                  "dynamic": "Energetic motion and transitions.",
                  "depth": "3D parallax depth effect."
                },
                "description": "How still images are animated. Ignored for other media types. Only applies when media.type = moving-image. Accepted aliases: typeMovingImageAnim."
              },
              "mediaPreset": {
                "type": "string",
                "default": "DEFAULT",
                "description": "Visual style preset slug (e.g. DEFAULT, ANIME, PIXAR, GHIBLI, REALISM, ...). See the preset list in the docs. A preset can override media.imageModel when it requires a specific model. Only applies when media.type = moving-image or ai-video. Accepted aliases: media.generationPreset, options.generationPreset, generationPreset."
              },
              "maxItems": {
                "type": "integer",
                "minimum": 1,
                "description": "Hard cap on the number of generated/selected media items. Accepted aliases: maxNbMedias."
              },
              "provided": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/MediaItem"
                },
                "description": "Your own media items. Used as the only visuals when media.type = custom or media.useOnlyProvided = true; otherwise used as references/anchors. Items: { url (required), type, title, ... }. Accepted aliases: inputMedias."
              },
              "useOnlyProvided": {
                "type": "boolean",
                "default": false,
                "description": "Use only media.provided[] items; disable AI media generation/search. Default: true for motion-transfer and ad-generator. Accepted aliases: options.useOnlyProvidedMedia, useOnlyProvidedMedia."
              },
              "useProvidedInOrder": {
                "type": "boolean",
                "default": false,
                "description": "Map media.provided[] items to script sections in order (no AI picking). Forces useOnlyProvided. Fewer media than sections: adjacent sections are grouped; extra media are ignored. Requires at least one image/video item. Only applies when media.type = custom."
              },
              "mergeVideos": {
                "type": "boolean",
                "default": false,
                "description": "Merge multiple provided videos into one sequence."
              },
              "mergeVideosFull": {
                "type": "boolean",
                "default": false,
                "description": "Merge provided videos keeping their full length."
              },
              "addAudioToVideos": {
                "type": "boolean",
                "description": "Generate ambient audio/sound for AI video clips. Default: true for prompt-to-video with media.type = ai-video, false otherwise."
              },
              "turnImagesIntoVideos": {
                "type": "boolean",
                "default": false,
                "description": "Animate provided still images into video clips."
              },
              "applyStyleTransfer": {
                "type": "boolean",
                "default": false,
                "description": "Re-style provided media to match the selected preset."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "voice": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Generate an AI voice-over for the script. Default: on for script/prompt/article/avatar/static/ad workflows; off for audio/music/caption/motion workflows. Accepted aliases: hasToGenerateVoice."
              },
              "voiceId": {
                "type": "string",
                "default": "cgSgspJ2msm6clMCkdW9",
                "description": "Voice ID (ElevenLabs or cloned voice). Browse voices at revid.ai or clone one via POST /api/public/v3/voice-clone. Accepted aliases: voice.id, selectedVoice."
              },
              "stability": {
                "type": "number",
                "minimum": 0,
                "maximum": 1,
                "default": 0.2,
                "description": "Voice stability. Lower = more expressive, higher = more consistent."
              },
              "speed": {
                "type": "number",
                "minimum": 0.5,
                "maximum": 2,
                "default": 1,
                "description": "Speech speed multiplier."
              },
              "useLegacyModel": {
                "type": "boolean",
                "default": false,
                "description": "Use the previous-generation voice model."
              },
              "enhanceAudio": {
                "type": "boolean",
                "default": false,
                "description": "Post-process the voice track for cleaner audio. Accepted aliases: options.hasToEnhanceAudio, hasToEnhanceAudio."
              },
              "language": {
                "type": "string",
                "description": "Language code for voice-over and script generation (e.g. \"en\", \"fr\", \"es\"). 70+ languages supported. Accepted aliases: options.language, language, lang."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "captions": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "default": true,
                "description": "Burn animated captions into the video. Accepted aliases: disableCaptions (inverted)."
              },
              "preset": {
                "type": "string",
                "default": "Wrap 1",
                "description": "Caption style preset. Available: Basic, Revid, Hormozi, Ali, Wrap 1, Wrap 2, Faceless, Elegant, Difference, Opacity, Playful, Bold Punch, Movie, Outline, Cove, Beat, Floating, Gram, Word by Word."
              },
              "position": {
                "type": "string",
                "default": "bottom",
                "enum": [
                  "top",
                  "middle",
                  "bottom"
                ],
                "x-enumDescriptions": {
                  "top": "Top of the frame.",
                  "middle": "Center of the frame.",
                  "bottom": "Bottom of the frame (default)."
                },
                "description": "Vertical position of the captions."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "music": {
            "type": "object",
            "properties": {
              "enabled": {
                "type": "boolean",
                "description": "Add a background music track. The whole music block also accepts the legacy alias name `audio`. Default: on for script/prompt/article/static/ad/caption/motion workflows; off for audio/music/avatar workflows. Auto-enabled when any other music field is set.. Accepted aliases: audio.enabled, disableAudio (inverted)."
              },
              "trackName": {
                "type": "string",
                "default": "Observer",
                "description": "Name of a track from the Revid library (115+ tracks, e.g. Observer, Snaps, Bright Morning, Chill Wave, Epic Battle Orchestra). Ignored when music.audioUrl is set. Accepted aliases: audio.trackName, selectedAudio."
              },
              "audioUrl": {
                "type": "string",
                "format": "uri",
                "description": "Custom background music URL. Checked for reachability (HEAD request) before the render starts. Accepted aliases: music.url, audioUrl."
              },
              "generateMusic": {
                "type": "boolean",
                "default": false,
                "description": "Generate an AI music track instead of using the library/custom URL. Accepted aliases: music.generate, options.generateMusic, hasToGenerateMusic."
              },
              "generationMusicPrompt": {
                "type": "string",
                "description": "Prompt for AI music generation (style, mood, instruments). Accepted aliases: music.generationPrompt, options.generationMusicPrompt, generationMusicPrompt."
              },
              "musicGenerationModel": {
                "type": "string",
                "default": "base",
                "description": "Model used for AI music generation."
              }
            },
            "additionalProperties": false,
            "description": "Optional — enabled by default for this workflow."
          },
          "options": {
            "type": "object",
            "properties": {
              "promptTargetDuration": {
                "oneOf": [
                  {
                    "type": "number",
                    "minimum": 5,
                    "maximum": 1800
                  },
                  {
                    "type": "string",
                    "enum": [
                      "auto"
                    ]
                  }
                ],
                "default": 30,
                "description": "Target video duration in seconds for prompt-driven workflows, or \"auto\" to let the AI choose. Workflows: prompt-to-video, ad-generator. Accepted aliases: promptTargetDuration, options.targetDuration (in prompt workflows)."
              },
              "outputCount": {
                "type": "integer",
                "minimum": 1,
                "maximum": 10,
                "default": 1,
                "description": "Number of video variations to generate. Each variation consumes credits. Accepted aliases: nbGenerations."
              },
              "disableAudio": {
                "type": "boolean",
                "description": "Hard override: strip background music from the output regardless of the music block. Accepted aliases: disableAudio."
              },
              "disableVoice": {
                "type": "boolean",
                "description": "Hard override: no voice-over regardless of the voice block. Accepted aliases: disableVoice."
              },
              "soundEffects": {
                "type": "boolean",
                "default": false,
                "description": "Generate sound effects matched to the scenes. Accepted aliases: hasToGenerateSoundEffects."
              },
              "addStickers": {
                "type": "boolean",
                "default": false,
                "description": "Add animated stickers/emojis matched to the script. Accepted aliases: addStickers."
              },
              "nsfwFilter": {
                "type": "boolean",
                "default": false,
                "description": "Filter NSFW content in generated media. Accepted aliases: enableNsfwFilter."
              },
              "language": {
                "type": "string",
                "description": "Language override for the whole generation (same as voice.language). Accepted aliases: language, lang, voice.language."
              },
              "watermark": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": true,
                "description": "Custom watermark object forwarded as-is ({ url, position, opacity, ... }). null removes it. Accepted aliases: watermark."
              },
              "selectedPalette": {
                "type": "string",
                "description": "Color palette name for generated visuals."
              },
              "preventSummarization": {
                "type": "boolean",
                "default": false,
                "description": "Never shorten the provided text (overrides summarization heuristics)."
              },
              "hasToGenerateCover": {
                "type": "boolean",
                "default": false,
                "description": "Generate a cover/thumbnail image for the video."
              },
              "coverTextType": {
                "type": "string",
                "default": "layers",
                "description": "Style of the text on the generated cover."
              },
              "hasTextSmallAtBottom": {
                "type": "boolean",
                "default": false,
                "description": "Show a small text line at the bottom of the video."
              },
              "customImageGenerationRulesSlug": {
                "type": "string",
                "description": "Slug of saved custom image generation rules to apply."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "render": {
            "type": "object",
            "properties": {
              "resolution": {
                "type": "string",
                "default": "1080p",
                "enum": [
                  "720p",
                  "1080p",
                  "4k"
                ],
                "x-enumDescriptions": {
                  "720p": "HD — fastest renders.",
                  "1080p": "Full HD (default).",
                  "4k": "Ultra HD — extra credits, slower renders."
                },
                "description": "Output resolution. 4k exports cost extra credits. Accepted aliases: resolution."
              },
              "compression": {
                "type": "number",
                "minimum": 0,
                "maximum": 50,
                "default": 18,
                "description": "H.264 CRF-style compression. Lower = better quality and bigger files. Accepted aliases: compression."
              },
              "frameRate": {
                "type": "number",
                "minimum": 1,
                "maximum": 60,
                "default": 30,
                "description": "Output frame rate. Accepted aliases: frameRate."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          },
          "advanced": {
            "type": "object",
            "properties": {
              "customCreationParams": {
                "type": "object",
                "additionalProperties": true,
                "description": "Expert escape hatch: extra legacy creationParams merged into the final payload. Workflow identity keys (slug, flowType) stay locked. Use only with guidance from the Revid team. Accepted aliases: customCreationParams."
              }
            },
            "additionalProperties": false,
            "description": "Optional."
          }
        },
        "additionalProperties": true
      },
      "MediaItem": {
        "type": "object",
        "required": [
          "url"
        ],
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Public http(s) URL of the media."
          },
          "type": {
            "type": "string",
            "enum": [
              "image",
              "video",
              "audio"
            ],
            "x-enumDescriptions": {
              "image": "Still image (png, jpg, webp, ...).",
              "video": "Video clip (mp4, mov, webm, ...).",
              "audio": "Audio file (mp3, wav, m4a)."
            },
            "description": "Media kind. Inferred from the URL extension when omitted."
          },
          "title": {
            "type": "string",
            "description": "Short description of the media. Used by the AI to decide where the media fits the script."
          },
          "urlLowRes": {
            "type": "string",
            "format": "uri",
            "description": "Optional low-resolution variant used for previews."
          },
          "imagePreview": {
            "type": "string",
            "format": "uri",
            "description": "Optional poster image for video items."
          },
          "noReencode": {
            "type": "boolean",
            "description": "Skip re-encoding for known-good mp4 sources (faster renders)."
          }
        },
        "additionalProperties": true
      },
      "RenderSuccessResponse": {
        "type": "object",
        "required": [
          "success",
          "pid"
        ],
        "properties": {
          "success": {
            "type": "integer",
            "enum": [
              1
            ]
          },
          "pid": {
            "type": "string",
            "description": "Project id — poll GET /api/public/v3/status?pid=... or wait for the webhook."
          },
          "workflow": {
            "type": "string"
          },
          "webhookUrl": {
            "type": "string"
          },
          "endpoint": {
            "type": "string"
          },
          "docs": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "RenderErrorResponse": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "type": "integer",
            "enum": [
              0
            ]
          },
          "error": {
            "type": "string",
            "description": "Human-readable, field-specific message, e.g. \"voice.speed must be between 0.5 and 2.\""
          },
          "docs": {
            "type": "object",
            "additionalProperties": true
          }
        }
      }
    }
  }
}
