{
  "openapi": "3.1.0",
  "info": {
    "title": "Significant Figures API",
    "version": "1.0.0",
    "description": "Personalized video platform. Turn data into animated videos at scale. Create data-driven video templates with 30+ animated primitives, render personalized videos for each recipient, and track engagement — all via REST API.",
    "contact": {
      "name": "Sig Figs Support",
      "url": "https://sigfigsstudio.com",
      "email": "support@sigfigsstudio.com"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "https://app.sigfigsstudio.com",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKeyAuth": []
    }
  ],
  "tags": [
    { "name": "Templates", "description": "Create, list, update, and fork video templates" },
    { "name": "Primitives", "description": "List available animated scene components" },
    { "name": "Prompt Builder", "description": "AI-powered template composition" },
    { "name": "Rendering", "description": "Render single or batch videos" },
    { "name": "Scripts", "description": "AI voiceover script generation" },
    { "name": "Translation", "description": "Translate voiceover scripts" },
    { "name": "Analytics", "description": "Campaign engagement analytics" },
    { "name": "Triggers", "description": "Event-driven video automation" },
    { "name": "Tracking", "description": "Video event tracking" },
    { "name": "Thumbnails", "description": "Generate video thumbnails" }
  ],
  "paths": {
    "/api/templates": {
      "get": {
        "operationId": "listTemplates",
        "summary": "List templates",
        "description": "List built-in and custom templates. Built-in templates are always returned. Custom templates require authentication.",
        "tags": ["Templates"],
        "security": [],
        "parameters": [
          {
            "name": "builtIn",
            "in": "query",
            "schema": { "type": "string", "enum": ["true", "false"], "default": "true" },
            "description": "Whether to include built-in templates"
          }
        ],
        "responses": {
          "200": {
            "description": "Template list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "templates": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/TemplateResponse" }
                    },
                    "total": { "type": "integer" }
                  }
                },
                "example": {
                  "success": true,
                  "templates": [
                    {
                      "id": "emeritus",
                      "name": "Emeritus",
                      "slug": "emeritus",
                      "description": null,
                      "visibility": "built-in",
                      "scenes": [],
                      "tags": [],
                      "usageCount": 0,
                      "isBuiltIn": true
                    }
                  ],
                  "total": 5
                }
              }
            }
          }
        },
        "x-rateLimit": { "limit": 30, "window": "1m", "scope": "ip" }
      },
      "post": {
        "operationId": "createTemplate",
        "summary": "Create a template",
        "description": "Create a new custom template from scratch or fork an existing one. When forking, scenes and defaults are pre-populated from the base template.",
        "tags": ["Templates"],
        "security": [{ "ApiKeyAuth": ["templates:write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/CreateTemplateRequest" },
              "example": {
                "name": "Q1 Sales Recap",
                "description": "Personalized quarterly sales recap video for each rep",
                "visibility": "private",
                "scenes": [
                  {
                    "primitiveId": "title-intro",
                    "label": "Welcome",
                    "defaultDuration": 3,
                    "voScript": "Here's your Q1 recap, [name].",
                    "animationOption": "sequential",
                    "dataRequired": ["name", "title", "photo"]
                  },
                  {
                    "primitiveId": "stat-counters",
                    "label": "Key Metrics",
                    "defaultDuration": 4,
                    "voScript": "You closed [deals_closed] deals worth [revenue].",
                    "animationOption": "count-up",
                    "dataRequired": ["metrics[]"]
                  },
                  {
                    "primitiveId": "bar-race",
                    "label": "Team Rankings",
                    "defaultDuration": 6,
                    "voScript": "Here's how you stacked up against the team.",
                    "animationOption": "animate-on-init",
                    "dataRequired": ["items[]", "values[]"]
                  },
                  {
                    "primitiveId": "cta-card",
                    "label": "Next Quarter",
                    "defaultDuration": 5,
                    "voScript": "Let's make Q2 even bigger.",
                    "animationOption": "slide-up",
                    "dataRequired": ["headline", "subtext", "primaryCtaText", "primaryCtaUrl"]
                  }
                ],
                "dataSlots": [
                  { "key": "name", "label": "Rep Name", "type": "text", "required": true },
                  { "key": "deals_closed", "label": "Deals Closed", "type": "number", "required": true },
                  { "key": "revenue", "label": "Revenue", "type": "text", "required": true }
                ],
                "defaults": {
                  "voiceId": "en-US-GuyNeural",
                  "accentColor": "#10b981",
                  "resolution": "1080p"
                },
                "tags": ["sales", "quarterly"]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Template created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "template": { "$ref": "#/components/schemas/TemplateResponse" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" }
        },
        "x-rateLimit": { "limit": 10, "window": "1m", "scope": "user" }
      }
    },
    "/api/templates/{id}": {
      "get": {
        "operationId": "getTemplate",
        "summary": "Get a template",
        "description": "Retrieve a single template by ID. Private templates are only visible to the owner.",
        "tags": ["Templates"],
        "security": [],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Template details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "template": { "$ref": "#/components/schemas/TemplateResponse" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        },
        "x-rateLimit": { "limit": 30, "window": "1m", "scope": "ip" }
      },
      "patch": {
        "operationId": "updateTemplate",
        "summary": "Update a template (partial)",
        "description": "Partially update a template you own. Only provided fields are updated. Does not increment version.",
        "tags": ["Templates"],
        "security": [{ "ApiKeyAuth": ["templates:write"] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateTemplateRequest" },
              "example": {
                "scenes": [
                  {
                    "primitiveId": "title-intro",
                    "label": "Welcome",
                    "defaultDuration": 3,
                    "animationOption": "sequential"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template updated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "template": { "$ref": "#/components/schemas/TemplateResponse" }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "404": { "$ref": "#/components/responses/NotFound" }
        },
        "x-rateLimit": { "limit": 30, "window": "1m", "scope": "user" }
      },
      "put": {
        "operationId": "replaceTemplate",
        "summary": "Update a template (full)",
        "description": "Full update of a template you own. Increments the template version.",
        "tags": ["Templates"],
        "security": [{ "ApiKeyAuth": ["templates:write"] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/UpdateTemplateRequest" }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Template replaced",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "template": { "$ref": "#/components/schemas/TemplateResponse" }
                  }
                }
              }
            }
          }
        },
        "x-rateLimit": { "limit": 30, "window": "1m", "scope": "user" }
      },
      "delete": {
        "operationId": "deleteTemplate",
        "summary": "Delete a template",
        "description": "Delete a template you own.",
        "tags": ["Templates"],
        "security": [{ "ApiKeyAuth": ["templates:write"] }],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": {
            "description": "Template deleted",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "message": { "type": "string" }
                  }
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        },
        "x-rateLimit": { "limit": 10, "window": "1m", "scope": "user" }
      }
    },
    "/api/primitives": {
      "get": {
        "operationId": "listPrimitives",
        "summary": "List available primitives",
        "description": "List all animated scene components (primitives) available for building templates. No authentication required.",
        "tags": ["Primitives"],
        "security": [],
        "parameters": [
          {
            "name": "category",
            "in": "query",
            "schema": { "type": "string" },
            "description": "Filter by category (e.g., 'Data Viz', 'Text', 'Gamification')"
          },
          {
            "name": "status",
            "in": "query",
            "schema": { "type": "string", "enum": ["production", "beta", "draft", "all"], "default": "production" },
            "description": "Filter by production status"
          }
        ],
        "responses": {
          "200": {
            "description": "Primitive list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "primitives": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/PrimitiveInfo" }
                    },
                    "categories": {
                      "type": "array",
                      "items": { "type": "string" }
                    },
                    "total": { "type": "integer" }
                  }
                },
                "example": {
                  "success": true,
                  "primitives": [
                    {
                      "id": "title-intro",
                      "label": "Title / Intro",
                      "category": "Text",
                      "description": "Name, title, and photo intro",
                      "animationOptions": ["all-at-once", "sequential"],
                      "defaultDuration": 3,
                      "dataInputs": ["name", "title", "photo"],
                      "status": "production"
                    },
                    {
                      "id": "radar",
                      "label": "Radar Chart",
                      "category": "Data Viz",
                      "description": "Multi-axis fingerprint showing relative strengths",
                      "animationOptions": ["per-dimension"],
                      "defaultDuration": 5,
                      "dataInputs": ["categories[]", "values[]"],
                      "status": "production"
                    }
                  ],
                  "categories": ["Text", "Data Viz", "Gamification", "Comparison", "Media", "Engagement", "Narrative", "People", "Branding"],
                  "total": 31
                }
              }
            }
          }
        }
      }
    },
    "/api/prompt-builder": {
      "post": {
        "operationId": "promptBuilder",
        "summary": "AI template composition",
        "description": "Use AI to compose or edit a video template from a natural language description. The AI selects appropriate primitives, configures scenes, and writes voiceover scripts.",
        "tags": ["Prompt Builder"],
        "security": [{ "ApiKeyAuth": ["templates:write"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["prompt", "mode", "currentState"],
                "properties": {
                  "prompt": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Natural language description of the video template to create or how to edit the current one"
                  },
                  "mode": {
                    "type": "string",
                    "enum": ["create", "edit"],
                    "description": "'create' builds from scratch, 'edit' modifies the current template"
                  },
                  "currentState": {
                    "$ref": "#/components/schemas/TemplateResponse",
                    "description": "Current template state (used as context for edit mode)"
                  }
                }
              },
              "example": {
                "prompt": "Create a customer onboarding video with a welcome intro, key metrics about their account, a timeline of milestones ahead, and a CTA to book a kickoff call",
                "mode": "create",
                "currentState": {
                  "id": "",
                  "name": "",
                  "slug": null,
                  "scenes": [],
                  "tags": [],
                  "visibility": "private"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "AI-composed template scenes",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scenes": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/SceneConfig" }
                    },
                    "explanation": { "type": "string" },
                    "suggestedVoiceoverTone": { "type": "string" },
                    "estimatedDuration": { "type": "integer" }
                  }
                },
                "example": {
                  "scenes": [
                    {
                      "primitiveId": "title-intro",
                      "label": "Welcome",
                      "enabled": true,
                      "defaultDuration": 3,
                      "voScript": "Welcome aboard, [name]. We're excited to have [company_name] on the platform.",
                      "animationOption": "sequential",
                      "dataRequired": ["name", "company_name", "photo"]
                    },
                    {
                      "primitiveId": "stat-counters",
                      "label": "Account Overview",
                      "enabled": true,
                      "defaultDuration": 4,
                      "voScript": "Here's a snapshot of your account setup so far.",
                      "animationOption": "count-up",
                      "dataRequired": ["metrics[]"]
                    }
                  ],
                  "explanation": "Created a 4-scene onboarding video: intro → metrics → timeline → CTA.",
                  "suggestedVoiceoverTone": "professional",
                  "estimatedDuration": 17
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        },
        "x-rateLimit": { "limit": 10, "window": "1m", "scope": "user" },
        "x-dailyLimit": { "free": 5, "studio": 50, "enterprise": 500 }
      }
    },
    "/api/render": {
      "post": {
        "operationId": "renderVideo",
        "summary": "Render a video",
        "description": "Create a render job for a single personalized video. The video is rendered asynchronously in the cloud (~60 seconds). Poll GET /api/render/{id} for status. Costs 1 credit.",
        "tags": ["Rendering"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/RenderRequest" },
              "example": {
                "templateId": "client-welcome",
                "data": {
                  "person_name": "Sarah Chen",
                  "company_name": "Acme Corp",
                  "role": "VP of Marketing"
                },
                "scenes": [
                  {
                    "primitiveId": "title-intro",
                    "enabled": true,
                    "voScript": "Welcome to Sig Figs, Sarah. We're thrilled to have Acme Corp on board.",
                    "animationOption": "sequential"
                  },
                  {
                    "primitiveId": "stat-counters",
                    "enabled": true,
                    "voScript": "Here's what's in store for your team.",
                    "animationOption": "count-up"
                  }
                ],
                "brand": {
                  "accentColor": "#10b981",
                  "logoUrl": "https://example.com/logo.png",
                  "showWatermark": false
                },
                "audio": {
                  "includeVoiceover": true,
                  "voiceId": "en-GB-RyanNeural",
                  "musicTrack": null,
                  "musicVolume": 15
                },
                "output": {
                  "resolution": "1080p",
                  "fps": 30
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Render job created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "jobId": { "type": "string", "format": "uuid" },
                    "status": { "type": "string", "enum": ["pending"] },
                    "templateId": { "type": "string" },
                    "displayName": { "type": "string" },
                    "creditsRemaining": { "type": "integer" },
                    "message": { "type": "string" }
                  }
                },
                "example": {
                  "success": true,
                  "jobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                  "status": "pending",
                  "templateId": "client-welcome",
                  "displayName": "Sarah Chen",
                  "creditsRemaining": 49,
                  "message": "Render job created. Video will be ready in ~60 seconds. Poll GET /api/render/a1b2c3d4-e5f6-7890-abcd-ef1234567890 for status."
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "402": {
            "description": "Insufficient credits",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "error": { "type": "string" },
                    "message": { "type": "string" },
                    "credits": { "type": "integer" },
                    "upgradeUrl": { "type": "string" }
                  }
                }
              }
            }
          },
          "429": { "$ref": "#/components/responses/RateLimited" }
        },
        "x-rateLimit": { "limit": 30, "window": "1m", "scope": "user" }
      }
    },
    "/api/render/{id}": {
      "get": {
        "operationId": "getRenderStatus",
        "summary": "Get render status",
        "description": "Poll for render job status. When status is 'complete', the outputUrl contains the video URL.",
        "tags": ["Rendering"],
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Render job status",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/RenderJobStatus" },
                "example": {
                  "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                  "status": "complete",
                  "stage": "done",
                  "progress": 100,
                  "outputUrl": "https://abcdef.public.blob.vercel-storage.com/videos/a1b2c3d4.mp4",
                  "error": null,
                  "authorName": "Sarah Chen",
                  "createdAt": "2026-03-21T12:00:00.000Z",
                  "updatedAt": "2026-03-21T12:01:05.000Z"
                }
              }
            }
          },
          "404": { "$ref": "#/components/responses/NotFound" }
        },
        "x-rateLimit": { "limit": 120, "window": "1m", "scope": "user" }
      }
    },
    "/api/render/batch": {
      "post": {
        "operationId": "renderBatch",
        "summary": "Batch render videos",
        "description": "Create render jobs for multiple recipients from CSV-style row data. Each row becomes one personalized video. Costs 1 credit per video. Tier limits: free=10, studio=100, enterprise=1000.",
        "tags": ["Rendering"],
        "security": [{ "ApiKeyAuth": ["videos:create:batch"] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["templateId", "rows"],
                "properties": {
                  "templateId": { "type": "string", "description": "Built-in or custom template ID" },
                  "headers": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Column headers mapping to template data fields"
                  },
                  "rows": {
                    "type": "array",
                    "items": {
                      "type": "array",
                      "items": { "type": "string" }
                    },
                    "description": "Array of rows, each row is an array of cell values matching headers"
                  }
                }
              },
              "example": {
                "templateId": "client-welcome",
                "headers": ["person_name", "company_name", "role", "email"],
                "rows": [
                  ["Sarah Chen", "Acme Corp", "VP Marketing", "sarah@acme.com"],
                  ["James Wilson", "TechStart", "CEO", "james@techstart.io"],
                  ["Maria Garcia", "DataFlow", "CTO", "maria@dataflow.com"]
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Batch render jobs created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "batchId": { "type": "string", "format": "uuid" },
                    "jobIds": {
                      "type": "array",
                      "items": { "type": "string", "format": "uuid" }
                    },
                    "totalJobs": { "type": "integer" },
                    "status": { "type": "string" },
                    "message": { "type": "string" }
                  }
                },
                "example": {
                  "success": true,
                  "batchId": "b1c2d3e4-f5g6-7890-hijk-lm1234567890",
                  "jobIds": [
                    "j1-uuid",
                    "j2-uuid",
                    "j3-uuid"
                  ],
                  "totalJobs": 3,
                  "status": "pending",
                  "message": "Created 3 render jobs. Rendering in the cloud."
                }
              }
            }
          },
          "402": {
            "description": "Insufficient credits for full batch"
          }
        },
        "x-rateLimit": { "limit": 5, "window": "1m", "scope": "user" }
      },
      "get": {
        "operationId": "getBatchStatus",
        "summary": "Get batch render status",
        "description": "Poll for the status of a batch render job, including per-video progress.",
        "tags": ["Rendering"],
        "parameters": [
          { "name": "batchId", "in": "query", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Batch status with per-job details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "batch": {
                      "type": "object",
                      "properties": {
                        "id": { "type": "string" },
                        "templateId": { "type": "string" },
                        "totalRows": { "type": "integer" },
                        "status": { "type": "string", "enum": ["pending", "processing", "complete", "failed", "partial"] },
                        "progress": {
                          "type": "object",
                          "properties": {
                            "completed": { "type": "integer" },
                            "failed": { "type": "integer" },
                            "processing": { "type": "integer" },
                            "pending": { "type": "integer" },
                            "total": { "type": "integer" },
                            "percent": { "type": "integer" }
                          }
                        },
                        "createdAt": { "type": "string", "format": "date-time" }
                      }
                    },
                    "jobs": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string" },
                          "name": { "type": "string" },
                          "status": { "type": "string" },
                          "progress": { "type": "integer" },
                          "outputUrl": { "type": "string", "nullable": true },
                          "error": { "type": "string", "nullable": true }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/generate-script": {
      "post": {
        "operationId": "generateScript",
        "summary": "Generate voiceover scripts",
        "description": "Use AI to generate voiceover scripts for template scenes. Scripts are personalized based on input data and synced to animation timing.",
        "tags": ["Scripts"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["scenes"],
                "properties": {
                  "scenes": {
                    "type": "array",
                    "items": { "$ref": "#/components/schemas/SceneConfig" },
                    "description": "Scene configurations to generate scripts for"
                  },
                  "inputData": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Sample data values for personalization"
                  },
                  "templateName": { "type": "string" },
                  "templateSlug": { "type": "string" },
                  "tone": {
                    "type": "string",
                    "enum": ["professional", "celebratory", "casual", "inspirational"],
                    "default": "professional"
                  },
                  "sceneIndex": {
                    "type": "integer",
                    "description": "Generate script for a single scene only"
                  }
                }
              },
              "example": {
                "scenes": [
                  {
                    "primitiveId": "title-intro",
                    "label": "Welcome",
                    "defaultDuration": 3,
                    "dataRequired": ["name", "title"]
                  },
                  {
                    "primitiveId": "stat-counters",
                    "label": "Key Numbers",
                    "defaultDuration": 4,
                    "dataRequired": ["metrics[]"]
                  }
                ],
                "inputData": {
                  "name": "Dr. Jane Smith",
                  "title": "Professor of Physics"
                },
                "tone": "celebratory"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Generated scripts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scripts": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "sceneId": { "type": "string" },
                          "voScript": { "type": "string" }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "scripts": [
                    { "sceneId": "0", "voScript": "Meet Dr. Jane Smith, Professor of Physics — a career that's shaped the field." },
                    { "sceneId": "1", "voScript": "The numbers speak for themselves. Let's dive in." }
                  ]
                }
              }
            }
          }
        },
        "x-rateLimit": { "limit": 5, "window": "1m", "scope": "user" }
      }
    },
    "/api/translate": {
      "post": {
        "operationId": "translateScripts",
        "summary": "Translate voiceover scripts",
        "description": "Translate voiceover scripts between supported languages. Results are cached per template+scene for fast repeated access.",
        "tags": ["Translation"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["texts", "sourceLanguage", "targetLanguage"],
                "properties": {
                  "texts": {
                    "type": "array",
                    "items": { "type": "string" },
                    "description": "Array of VO scripts to translate"
                  },
                  "sourceLanguage": { "type": "string", "description": "Source language code (e.g., 'en')" },
                  "targetLanguage": { "type": "string", "description": "Target language code (e.g., 'es')" },
                  "templateId": { "type": "string", "description": "Template ID for cache keying" },
                  "sceneIndexes": {
                    "type": "array",
                    "items": { "type": "integer" },
                    "description": "Scene indices for cache keying"
                  }
                }
              },
              "example": {
                "texts": [
                  "Welcome aboard, Sarah. We're excited to have you.",
                  "Here's your personalized overview."
                ],
                "sourceLanguage": "en",
                "targetLanguage": "es",
                "templateId": "client-welcome"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Translated texts",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "translations": {
                      "type": "array",
                      "items": { "type": "string" }
                    },
                    "cached": { "type": "integer", "description": "Number of translations served from cache" },
                    "generated": { "type": "integer", "description": "Number of translations generated fresh" }
                  }
                },
                "example": {
                  "translations": [
                    "Bienvenida a bordo, Sarah. Estamos emocionados de tenerte.",
                    "Aquí tienes tu resumen personalizado."
                  ],
                  "cached": 0,
                  "generated": 2
                }
              }
            }
          }
        }
      }
    },
    "/api/languages": {
      "get": {
        "operationId": "listLanguages",
        "summary": "List supported languages",
        "description": "List all languages supported for voiceover TTS and translation.",
        "tags": ["Translation"],
        "security": [],
        "responses": {
          "200": {
            "description": "Supported languages",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "languages": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "code": { "type": "string" },
                          "name": { "type": "string" }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "languages": [
                    { "code": "en", "name": "English" },
                    { "code": "en-GB", "name": "English (UK)" },
                    { "code": "es", "name": "Spanish" },
                    { "code": "fr", "name": "French" },
                    { "code": "de", "name": "German" },
                    { "code": "pt", "name": "Portuguese" },
                    { "code": "ja", "name": "Japanese" },
                    { "code": "ko", "name": "Korean" },
                    { "code": "zh", "name": "Chinese (Mandarin)" },
                    { "code": "ar", "name": "Arabic" },
                    { "code": "hi", "name": "Hindi" },
                    { "code": "it", "name": "Italian" },
                    { "code": "nl", "name": "Dutch" },
                    { "code": "pl", "name": "Polish" },
                    { "code": "ru", "name": "Russian" },
                    { "code": "tr", "name": "Turkish" },
                    { "code": "th", "name": "Thai" },
                    { "code": "vi", "name": "Vietnamese" },
                    { "code": "sv", "name": "Swedish" }
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/analytics/campaign/{batchId}/heatmap": {
      "get": {
        "operationId": "getCampaignHeatmap",
        "summary": "Scene engagement heatmap",
        "description": "Get per-scene retention data for a batch campaign. Shows what percentage of viewers reached each scene.",
        "tags": ["Analytics"],
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "Scene retention heatmap",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "scenes": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "index": { "type": "integer" },
                          "retentionPercent": { "type": "integer" },
                          "viewerCount": { "type": "integer" }
                        }
                      }
                    },
                    "totalViews": { "type": "integer" }
                  }
                },
                "example": {
                  "scenes": [
                    { "index": 0, "retentionPercent": 100, "viewerCount": 150 },
                    { "index": 1, "retentionPercent": 87, "viewerCount": 130 },
                    { "index": 2, "retentionPercent": 72, "viewerCount": 108 },
                    { "index": 3, "retentionPercent": 65, "viewerCount": 97 }
                  ],
                  "totalViews": 150
                }
              }
            }
          }
        }
      }
    },
    "/api/analytics/campaign/{batchId}/ab": {
      "get": {
        "operationId": "getAbTestResults",
        "summary": "A/B test results",
        "description": "Get A/B test results for a campaign with multiple template variants. Includes completion rate, CTA click rate, average watch percent, and share rate per variant.",
        "tags": ["Analytics"],
        "parameters": [
          { "name": "batchId", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }
        ],
        "responses": {
          "200": {
            "description": "A/B test results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "abEnabled": { "type": "boolean" },
                    "variants": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": { "type": "string" },
                          "label": { "type": "string" },
                          "splitPercent": { "type": "integer" },
                          "recipientCount": { "type": "integer" },
                          "metrics": {
                            "type": "object",
                            "properties": {
                              "completionRate": { "type": "integer" },
                              "ctaClickRate": { "type": "integer" },
                              "avgWatchPercent": { "type": "integer" },
                              "shareRate": { "type": "integer" }
                            }
                          }
                        }
                      }
                    },
                    "winner": {
                      "type": "object",
                      "nullable": true,
                      "properties": {
                        "variantId": { "type": "string" },
                        "label": { "type": "string" },
                        "metric": { "type": "string" },
                        "lift": { "type": "string" }
                      }
                    }
                  }
                },
                "example": {
                  "abEnabled": true,
                  "variants": [
                    {
                      "id": "v1-id",
                      "label": "Variant A — Celebratory",
                      "splitPercent": 50,
                      "recipientCount": 75,
                      "metrics": { "completionRate": 68, "ctaClickRate": 12, "avgWatchPercent": 82, "shareRate": 5 }
                    },
                    {
                      "id": "v2-id",
                      "label": "Variant B — Professional",
                      "splitPercent": 50,
                      "recipientCount": 75,
                      "metrics": { "completionRate": 54, "ctaClickRate": 8, "avgWatchPercent": 71, "shareRate": 3 }
                    }
                  ],
                  "winner": {
                    "variantId": "v1-id",
                    "label": "Variant A — Celebratory",
                    "metric": "completionRate",
                    "lift": "26%"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/triggers": {
      "get": {
        "operationId": "listTriggers",
        "summary": "List trigger rules",
        "description": "List all event-driven trigger rules for the authenticated user, including recent executions.",
        "tags": ["Triggers"],
        "responses": {
          "200": {
            "description": "Trigger rules list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rules": {
                      "type": "array",
                      "items": { "$ref": "#/components/schemas/TriggerRule" }
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createTrigger",
        "summary": "Create a trigger rule",
        "description": "Create an event-driven trigger that automatically renders and sends personalized videos when conditions are met.",
        "tags": ["Triggers"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "eventType", "condition", "templateId", "channel"],
                "properties": {
                  "name": { "type": "string", "description": "Human-readable trigger name" },
                  "eventType": {
                    "type": "string",
                    "enum": ["milestone", "date", "threshold", "segment"],
                    "description": "Type of event to trigger on"
                  },
                  "condition": {
                    "type": "object",
                    "description": "Condition JSON that is evaluated against ingested event data"
                  },
                  "templateId": { "type": "string", "description": "Template to render when triggered" },
                  "channel": {
                    "type": "string",
                    "enum": ["email", "sms", "webhook"],
                    "description": "Delivery channel"
                  },
                  "throttleDays": {
                    "type": "integer",
                    "default": 30,
                    "description": "Minimum days between triggers for the same recipient"
                  },
                  "campaignId": { "type": "string", "nullable": true }
                }
              },
              "example": {
                "name": "100th Order Celebration",
                "eventType": "milestone",
                "condition": {
                  "field": "total_orders",
                  "op": ">=",
                  "value": 100
                },
                "templateId": "clxxxxxxxxxxxxxxxxxx",
                "channel": "email",
                "throttleDays": 365
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Trigger rule created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rule": { "$ref": "#/components/schemas/TriggerRule" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/events/ingest": {
      "post": {
        "operationId": "ingestEvents",
        "summary": "Ingest events for trigger evaluation",
        "description": "Ingest a batch of events (up to 100). Each event is evaluated against all enabled trigger rules. Matching triggers automatically create render jobs.",
        "tags": ["Triggers"],
        "security": [{ "ApiKeyAuth": [] }],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["events"],
                "properties": {
                  "events": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "type": "object",
                      "required": ["recipientId", "data"],
                      "properties": {
                        "recipientId": { "type": "string", "description": "Unique identifier for the recipient" },
                        "recipientEmail": { "type": "string", "format": "email", "description": "Email for delivery (optional)" },
                        "data": {
                          "type": "object",
                          "additionalProperties": true,
                          "description": "Event data to evaluate against trigger conditions"
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "events": [
                  {
                    "recipientId": "cust_12345",
                    "recipientEmail": "sarah@acme.com",
                    "data": {
                      "total_orders": 100,
                      "lifetime_value": 25000,
                      "customer_since": "2024-01-15"
                    }
                  },
                  {
                    "recipientId": "cust_67890",
                    "recipientEmail": "james@techstart.io",
                    "data": {
                      "total_orders": 50,
                      "lifetime_value": 12000
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Ingestion results",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "processed": { "type": "integer" },
                    "triggered": { "type": "integer" },
                    "throttled": { "type": "integer" },
                    "errors": { "type": "integer" }
                  }
                },
                "example": {
                  "processed": 2,
                  "triggered": 1,
                  "throttled": 0,
                  "errors": 0
                }
              }
            }
          }
        }
      }
    },
    "/api/track": {
      "post": {
        "operationId": "trackEvent",
        "summary": "Track video events",
        "description": "Track viewer engagement events for a video. Used by the video player embed to report watch progress, shares, etc.",
        "tags": ["Tracking"],
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["videoId", "event"],
                "properties": {
                  "videoId": { "type": "string", "description": "Render job ID" },
                  "event": {
                    "type": "string",
                    "enum": [
                      "page_view", "email_opened", "video_started", "video_25",
                      "video_50", "video_75", "video_completed", "video_replayed",
                      "shared", "downloaded", "scene_entered", "remix_started",
                      "remix_completed", "remix_shared"
                    ]
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Optional event metadata (e.g., sceneIndex for scene_entered)"
                  }
                }
              },
              "example": {
                "videoId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                "event": "video_completed",
                "metadata": { "watchTimeSeconds": 45 }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Event tracked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": { "type": "boolean" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/thumbnail": {
      "post": {
        "operationId": "generateThumbnail",
        "summary": "Generate video thumbnails",
        "description": "Generate a static PNG thumbnail and animated GIF from a completed render job.",
        "tags": ["Thumbnails"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["renderJobId"],
                "properties": {
                  "renderJobId": { "type": "string", "description": "Completed render job ID" },
                  "sceneIndex": { "type": "integer", "description": "Scene to capture (optional)" },
                  "startSec": { "type": "number", "default": 0, "description": "Start time in seconds" },
                  "durationSec": { "type": "number", "default": 3, "description": "GIF duration in seconds" }
                }
              },
              "example": {
                "renderJobId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
                "startSec": 2,
                "durationSec": 3
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Thumbnails generated",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "success": { "type": "boolean" },
                    "renderJobId": { "type": "string" },
                    "thumbnailUrl": { "type": "string" },
                    "thumbnailGifUrl": { "type": "string" },
                    "pngSize": { "type": "integer" },
                    "gifSize": { "type": "integer" }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "API key with assigned scopes. Create keys at https://app.sigfigsstudio.com/settings/api-keys"
      }
    },
    "schemas": {
      "SceneConfig": {
        "type": "object",
        "required": ["primitiveId"],
        "properties": {
          "primitiveId": { "type": "string", "description": "Primitive component ID (e.g., 'title-intro', 'radar', 'bar-race')" },
          "label": { "type": "string", "description": "Display label in the builder" },
          "enabled": { "type": "boolean", "default": true, "description": "Whether this scene is included in the render" },
          "defaultDuration": { "type": "number", "description": "Duration in seconds (overridden by VO length when voiceover is enabled)" },
          "voScript": { "type": "string", "nullable": true, "description": "Voiceover script. Supports [variable] substitution syntax." },
          "skipCondition": {
            "type": "object",
            "nullable": true,
            "properties": {
              "field": { "type": "string" },
              "op": { "type": "string", "enum": [">=", "<=", ">", "<", "==", "!=", "exists", "not_exists"] },
              "value": {},
              "skipWhen": { "type": "boolean" }
            },
            "description": "Auto-skip this scene based on data conditions"
          },
          "animationOption": { "type": "string", "description": "Animation variant (must be one of the primitive's animationOptions)" },
          "dataRequired": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Data field keys this scene requires"
          },
          "durationOverride": { "type": "number", "nullable": true },
          "sceneData": { "type": "object", "additionalProperties": true },
          "transition": { "type": "string" },
          "animationBindings": {
            "type": "object",
            "additionalProperties": { "type": "number" },
            "description": "Maps animation event IDs to start timestamps (ms)"
          },
          "wordTimestamps": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "word": { "type": "string" },
                "startMs": { "type": "number" },
                "endMs": { "type": "number" }
              }
            },
            "description": "Word-level TTS timestamps for VO sync"
          }
        }
      },
      "PrimitiveInfo": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "description": "Unique primitive identifier used in SceneConfig.primitiveId" },
          "label": { "type": "string", "description": "Human-readable name" },
          "category": { "type": "string", "description": "Category grouping (e.g., 'Data Viz', 'Text', 'Gamification')" },
          "description": { "type": "string", "description": "What this primitive visualizes" },
          "animationOptions": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Available animation variants for this primitive"
          },
          "defaultDuration": { "type": "number", "description": "Default scene duration in seconds" },
          "dataInputs": {
            "type": "array",
            "items": { "type": "string" },
            "description": "Data field keys this primitive expects. Array fields are suffixed with []."
          },
          "status": { "type": "string", "enum": ["production", "beta", "draft"] }
        }
      },
      "DataSlot": {
        "type": "object",
        "required": ["key", "label", "type", "required"],
        "properties": {
          "key": { "type": "string", "description": "Field key used in [variable] references" },
          "label": { "type": "string", "description": "Display label" },
          "type": { "type": "string", "enum": ["text", "number", "email", "date", "url", "country_code", "array", "object"] },
          "required": { "type": "boolean" },
          "aliases": { "type": "array", "items": { "type": "string" }, "description": "Fuzzy match aliases for CSV column mapping" },
          "description": { "type": "string" },
          "defaultValue": {}
        }
      },
      "TemplateDefaults": {
        "type": "object",
        "properties": {
          "voiceId": { "type": "string" },
          "accentColor": { "type": "string" },
          "secondaryColor": { "type": "string" },
          "logoUrl": { "type": "string", "nullable": true },
          "resolution": { "type": "string", "enum": ["720p", "1080p", "4k"] },
          "fps": { "type": "integer", "enum": [30, 60] },
          "includeVoiceover": { "type": "boolean" }
        }
      },
      "CreateTemplateRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": { "type": "string", "minLength": 1 },
          "description": { "type": "string" },
          "visibility": { "type": "string", "enum": ["private", "unlisted", "public"], "default": "private" },
          "forkFrom": { "type": "string", "description": "Base template ID to fork from (built-in slug or custom template ID)" },
          "scenes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SceneConfig" }
          },
          "dataSlots": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/DataSlot" }
          },
          "defaults": { "$ref": "#/components/schemas/TemplateDefaults" },
          "tags": { "type": "array", "items": { "type": "string" } }
        }
      },
      "UpdateTemplateRequest": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "description": { "type": "string" },
          "visibility": { "type": "string", "enum": ["private", "unlisted", "public"] },
          "scenes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SceneConfig" }
          },
          "dataSlots": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/DataSlot" }
          },
          "defaults": { "$ref": "#/components/schemas/TemplateDefaults" },
          "tags": { "type": "array", "items": { "type": "string" } }
        }
      },
      "TemplateResponse": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "slug": { "type": "string", "nullable": true },
          "description": { "type": "string", "nullable": true },
          "category": { "type": "string" },
          "visibility": { "type": "string" },
          "baseTemplateId": { "type": "string", "nullable": true },
          "scenes": { "type": "array", "items": { "$ref": "#/components/schemas/SceneConfig" } },
          "dataSlots": { "type": "array", "items": { "$ref": "#/components/schemas/DataSlot" }, "nullable": true },
          "defaults": { "$ref": "#/components/schemas/TemplateDefaults", "nullable": true },
          "settings": { "type": "object", "nullable": true },
          "fieldSchema": { "type": "array", "nullable": true },
          "tags": { "type": "array", "items": { "type": "string" } },
          "version": { "type": "integer" },
          "usageCount": { "type": "integer" },
          "forkedCount": { "type": "integer" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "RenderRequest": {
        "type": "object",
        "required": ["templateId", "data"],
        "properties": {
          "templateId": {
            "type": "string",
            "description": "Built-in template slug ('emeritus', 'laureate', 'stride-wrapped', 'monthly-recap', 'client-welcome') or custom template ID"
          },
          "data": {
            "type": "object",
            "additionalProperties": true,
            "description": "Template data — keys depend on the template's data slots and scene requirements"
          },
          "scenes": {
            "type": "array",
            "items": { "$ref": "#/components/schemas/SceneConfig" },
            "description": "Scene overrides. If omitted, template defaults are used."
          },
          "brand": {
            "type": "object",
            "properties": {
              "accentColor": { "type": "string", "pattern": "^#[0-9a-fA-F]{6}$", "default": "#10b981" },
              "secondaryColor": { "type": "string" },
              "logoUrl": { "type": "string", "nullable": true },
              "logoPosition": { "type": "string", "enum": ["top-left", "top-right", "bottom-left", "bottom-right", "none"] },
              "logoSize": { "type": "string", "enum": ["small", "medium", "large"] },
              "logoVisibility": { "type": "string", "enum": ["all", "intro-only", "outro-only", "none"] },
              "showWatermark": { "type": "boolean", "description": "Forced true on free tier" },
              "introEnabled": { "type": "boolean" },
              "outroEnabled": { "type": "boolean" },
              "outroCta": { "type": "string" },
              "outroCtaUrl": { "type": "string" }
            }
          },
          "audio": {
            "type": "object",
            "properties": {
              "includeVoiceover": { "type": "boolean", "default": true },
              "voiceId": {
                "type": "string",
                "enum": ["en-GB-RyanNeural", "en-US-GuyNeural", "en-US-JennyNeural", "en-GB-SoniaNeural", "elevenlabs-custom"],
                "default": "en-GB-RyanNeural"
              },
              "elevenlabsApiKey": { "type": "string", "description": "Required when voiceId is 'elevenlabs-custom' (Studio+ tier)" },
              "elevenlabsVoiceId": { "type": "string", "description": "Required when voiceId is 'elevenlabs-custom'" },
              "musicTrack": { "type": "string", "nullable": true },
              "musicVolume": { "type": "integer", "minimum": 0, "maximum": 100, "default": 15 },
              "mode": { "type": "string", "description": "Audio mode: silent, music-only, tts, custom-voice" },
              "voiceVolume": { "type": "number", "minimum": 0, "maximum": 1 },
              "generatedVoUrl": { "type": "string", "description": "Pre-generated voiceover audio URL" }
            }
          },
          "output": {
            "type": "object",
            "properties": {
              "resolution": { "type": "string", "enum": ["720p", "1080p", "4k"], "default": "1080p" },
              "aspectRatio": { "type": "string", "enum": ["16:9", "9:16", "1:1"], "default": "16:9" },
              "fps": { "type": "integer", "enum": [30, 60], "default": 30 }
            }
          },
          "typography": {
            "type": "object",
            "properties": {
              "fontFamily": { "type": "string" },
              "fontHeading": { "type": "string" },
              "levels": { "type": "object", "additionalProperties": true }
            }
          },
          "colors": { "type": "object", "additionalProperties": { "type": "string" } },
          "animation": {
            "type": "object",
            "properties": {
              "speed": {},
              "timing": { "type": "string" },
              "order": { "type": "string" },
              "transitionIn": { "type": "string" },
              "transitionOut": { "type": "string" },
              "transitionDuration": { "type": "number" },
              "transitionEasing": { "type": "string" }
            }
          },
          "originalJobId": { "type": "string", "description": "For free re-render within 24h of the original" }
        }
      },
      "RenderJobStatus": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "status": { "type": "string", "enum": ["pending", "processing", "complete", "failed"] },
          "stage": { "type": "string", "description": "Current processing stage (queued, rendering, uploading, done)" },
          "progress": { "type": "integer", "minimum": 0, "maximum": 100 },
          "outputUrl": { "type": "string", "nullable": true, "description": "Video URL (available when status is 'complete')" },
          "error": { "type": "string", "nullable": true },
          "authorName": { "type": "string" },
          "createdAt": { "type": "string", "format": "date-time" },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "TriggerRule": {
        "type": "object",
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "eventType": { "type": "string", "enum": ["milestone", "date", "threshold", "segment"] },
          "condition": { "type": "string", "description": "JSON condition string" },
          "templateId": { "type": "string" },
          "channel": { "type": "string", "enum": ["email", "sms", "webhook"] },
          "throttleDays": { "type": "integer" },
          "enabled": { "type": "boolean" },
          "lastFiredAt": { "type": "string", "format": "date-time", "nullable": true },
          "executions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": { "type": "string" },
                "recipientId": { "type": "string" },
                "status": { "type": "string" },
                "firedAt": { "type": "string", "format": "date-time" }
              }
            },
            "description": "Most recent 5 executions"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid request",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" },
                "details": {}
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Authentication required or invalid API key",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" },
                "message": { "type": "string" }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Resource not found",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Rate limit exceeded",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "error": { "type": "string" },
                "retryAfter": { "type": "integer", "description": "Seconds until rate limit resets" }
              }
            }
          }
        }
      }
    }
  }
}
