{
  "openapi": "3.1.0",
  "info": {
    "title": "Syllaby API",
    "version": "2.0.0",
    "description": "The Syllaby API lets you build Syllaby’s content-generation capabilities\ninto your own apps and workflows. This **v2** release covers **faceless\nvideos** and the resources around them — scripts, presets, assets, and\naccount credits. More capabilities will be added over time.\n\n## Typical flow (faceless video)\n**Standard flow (AI-generated or stock visuals):**\n1. **Create** a draft video — `POST /faceless`.\n2. **Add a script** — generate one with `PUT /faceless/{faceless}/scripts`, or supply your own.\n3. **Configure** voice, genre, captions, and visuals — `PATCH /faceless/{faceless}`. Browse the available options at `GET /faceless/options`.\n4. *(Optional)* **Estimate** the credit cost — `GET /faceless/{faceless}/estimate`.\n5. **Render** — `POST /faceless/{faceless}/render` (returns `202`).\n6. **Track progress** — poll `GET /faceless/{id}` and read `data.video.status` (`rendering` → `completed`/`failed`); the `video` object is always embedded. On failure, retry with `POST /faceless/{faceless}/retry`. See **Get your rendered video** below.\n7. *(Optional)* **Export** a restyled cut — `POST /faceless/{faceless}/export`.\n\n**URL-based flow (build a video from a product/web page):**\n`create (type=url-based)` → `scrape-images` *(free)* → `scrape-script` *(charges `CONTENT_PROMPT_REQUESTED`, same as `PUT /scripts`)* → configure → render *(charges)* → poll.\n\n## Build from a URL\nThe `url-based` type lets you build a faceless video from the content of any publicly reachable web page (product listing, blog post, landing page) — Syllaby extracts images and can generate a matching script directly from the page.\n\n**Steps:**\n1. **Create** — `POST /faceless` with `type: \"url-based\"`. The `type` is fixed at creation and cannot be changed later.\n2. **Scrape images** — `POST /faceless/{faceless}/scrape-images` with `{ \"url\": \"https://…\" }`. **Free** — no credits charged. Extracts product/page images and attaches them to the video as ordered assets.\n3. **Scrape script** — `POST /faceless/{faceless}/scrape-script` with the page URL plus generation options (`duration`, `style`, `tone`, `language`). **💳 Charges `CONTENT_PROMPT_REQUESTED` credits** (the same amount as `PUT /faceless/{faceless}/scripts`). Generates and stores a narration script written from the page content. You may skip this step and supply your own script via `PATCH /faceless/{faceless}` instead.\n4. **Configure** — `PATCH /faceless/{faceless}` (voice, captions, transitions, etc.).\n5. **Render** — `POST /faceless/{faceless}/render`. **💳 Charges render credits.** Requires that scrape-images has run at least once (otherwise returns `422 assets`). The scraped images become the visual slides.\n6. **Poll** — `GET /faceless/{id}` until `data.video.status` is `completed`.\n\n> **Social and unsupported URLs are rejected.** URLs pointing to social-media platforms (YouTube, TikTok, Twitter/X, Instagram, Facebook, etc.) and any un-parseable or unreachable page return `422` on both scrape endpoints.\n\n## Get your rendered video\nRendering is asynchronous — the render call returns before the file exists. From request to playable file:\n\n1. **Create** the faceless video — `POST /faceless`. Note the `id` field in the response.\n2. *(Optional)* **Generate a script** — `PUT /faceless/{faceless}/scripts`.\n3. **Render** — `POST /faceless/{faceless}/render`. Returns `202` immediately; `meta.credits` reports the charge.\n4. **Poll** — `GET /faceless/{id}` on a sensible cadence (every 5–10 seconds is plenty). Every response embeds the render state under `data.video` — no `include` parameter needed.\n5. **Done** — when `data.video.status` is `completed`, the playable file is at `data.video.url`. If it is `failed`, the reason is in `data.video.failure` (`code` and `message`); fix what you can and retry with `POST /faceless/{faceless}/retry`.\n\n> **Important — poll with the right identifier.** Use the faceless **`id`** from the create/render response, **not** `video_id`. They are different identifiers: `id` is the faceless video, `video_id` is its underlying video record. Calling `GET /faceless/{video_id}` returns `404`.\n\n## Before you render — checklist\nRendering charges credits and has a few preconditions. The render call validates them **before** anything is charged, so a missed step fails fast with a `402`/`403` (or `422`) and costs nothing. Before calling `POST /faceless/{faceless}/render`:\n\n1. **Script set** — generate one with `PUT /faceless/{faceless}/scripts`, or supply your own via `PATCH /faceless/{faceless}`. Missing → **`403` `A script is required before rendering.`**\n2. **Voice chosen** — set `voice_id` via `PATCH /faceless/{faceless}`. Missing → **`403` `Voice was not provided.`** (or `Voice not found.` for an unknown id).\n3. **Options configured** — genre, captions, and visuals. Genre is **required** for `ai-visuals` / `ai-clips`; missing it → **`422` `A genre is required for AI visuals and AI clips.`** Browse valid ids/slugs at `GET /faceless/options`.\n4. **Credits sufficient** — check the cost against your balance with `GET /faceless/{faceless}/estimate`. Too few → **`402` `INSUFFICIENT-CREDITS`** with `required` and `available` in the error body.\n5. **For `url-based` videos** — run `POST /faceless/{faceless}/scrape-images` at least once before rendering. A url-based render with no scraped assets → **`422` `assets`** (the images become the visual slides; without them the render would produce an empty video).\n\nThe video must also not be **busy** (already rendering or syncing) → **`403` `The video is processing currently. Please try again once finished`**. See each endpoint's *Preconditions & common errors* for the full list.\n\n## Generate a clip from text (text-to-video)\nShort AI video clips from a text prompt, with optional reference frames. From prompt to playable file:\n\n1. **Pick a model** — `GET /text-to-video/models`. Models are gated by your plan; each entry lists its modifier menus (duration, resolution, aspect ratio, audio, reference media) and per-second pricing.\n2. *(Optional)* **Estimate** — `GET /text-to-video/estimate?model=<slug>` (plus any modifiers you will send). The figure is **exactly** what the create call charges for the same parameters — same defaults, same formula. Unlike the faceless render estimate, this is not an approximation.\n3. **Create** — `POST /text-to-video` with the model, a prompt (5–1500 words), and any modifiers. Returns `202` immediately; `meta.credits.cost` is the exact amount charged.\n4. **Poll** — `GET /text-to-video/{id}` with the **`id` from the create response**, every 5–10 seconds.\n5. **Done** — when `data.asset.status` is `success`, the clip is at `data.asset.url`. If it is `failed`, the reason is in `data.asset.failure` and the charge is refunded automatically.\n\n`asset.status` is the field to branch on, and these are its **exact strings**: `draft` (just created — the create call's `202` response carries this) → `processing` (the provider is generating) → terminal `success` (then, and only then, `asset.url` is non-null) or `failed` (`asset.failure` carries the reason).\n## Generate a stock-footage video (B-roll)\nB-roll videos assemble stock footage against a narration script. The flow mirrors the generic faceless flow with the `type` fixed to `b-roll`:\n\n1. **Create** — `POST /b-roll` with a `title`. Keep the returned `id`.\n2. **Add a script** — `PUT /b-roll/{faceless}/scripts` (or supply your own via `PATCH /b-roll/{id}`).\n3. **Configure** — `PATCH /b-roll/{id}` to set voice, captions, transitions, and more.\n4. *(Optional)* **Estimate** — `GET /b-roll/{faceless}/estimate`.\n5. **Render** — `POST /b-roll/{faceless}/render`, then poll `GET /b-roll/{id}` until `data.video.status` is `completed`.\n## Generate an AI-Visuals video\nAI-Visuals videos use AI-generated imagery for each scene. Same lifecycle as B-roll (`type` fixed to `ai-visuals`), plus per-scene asset control:\n\n1. **Create → script → configure → render** — as for B-roll, under `/ai-visuals`. A `genre` is required at render time.\n2. **Swap imagery** — `POST /ai-visuals/{faceless}/assets/upload` to add your own media (file or url).\n3. **Regenerate a scene** — `POST /ai-visuals/{faceless}/assets/{asset}/regenerate` to re-roll a single scene image.\n## Generate a video from a URL (URL-to-Video)\nURL-to-Video builds a video from a web page (`type` fixed to `url-based`). Scrape the page first, then render:\n\n1. **Create** — `POST /url-to-video` with a `title`.\n2. **Scrape images** — `POST /url-to-video/{faceless}/scrape-images` (free; required before rendering).\n3. **Add a script** — `POST /url-to-video/{faceless}/scrape-script` (from the page) or `PUT /url-to-video/{faceless}/scripts` (from a topic).\n4. **Configure → render** — `PATCH /url-to-video/{id}`, then `POST /url-to-video/{faceless}/render` and poll `GET /url-to-video/{id}`.\n## Build a storyboard video (Text-to-Scene)\nText-to-Scene is a storyboard editor: a video is a sequence of scenes you can generate, reorder, and chain for continuous motion.\n\n1. **Create** — `POST /text-to-scene` (`mode` `wizard` or `manual`). Keep the returned `id`.\n2. **Populate** — in `wizard` mode, `POST /text-to-scene/{storyboard}/prompt` generates scenes; in `manual` mode, add them with `POST /text-to-scene/{storyboard}/scenes`.\n3. **Refine** — reorder (`scenes/sort`), assign frames (`scenes/{scene}/frames`), chain scenes (`scenes/{scene}/chain`), and steer style with the moodboard endpoints.\n4. **Generate clips** — `POST /text-to-scene/{storyboard}/clips`, polling each scene's status.\n5. **Render** — `POST /text-to-scene/{storyboard}/render`, then poll `GET /text-to-scene/{id}` until `data.video.status` is `completed`.\n## Clone a voice\nTurn 1–3 audio samples into a reusable narration voice.\n\n1. **Check slots** *(optional)* — `GET /voice-clones/slots`. If `available` is 0, you can buy another when `can_buy` is true (costs `cost` credits).\n2. **Create** — `POST /voice-clones` (`multipart/form-data`) with `terms`, `name`, `gender`, and up to 3 `samples[]`. Add `purchase_addon: true` to buy a slot when yours are full.\n3. **Poll** — `GET /voice-clones/{id}` until `data.status` is `completed`; the sample preview is at `data.preview_url`.\n4. **Use it** — the clone appears among your narration voices for faceless renders.\n## Discover content ideas\nFind and rank content ideas for a keyword.\n\n1. **Discover** — `POST /ideas/discover` with a `keyword` and `network`. **Charges 15 credits** on any fruitful search (including cached re-searches); synchronous and can take up to ~2 minutes.\n2. **List** — `GET /ideas?keyword=…&network=…` returns the ranked ideas. **Free**, paginated, and sortable (`sort=-volume` by default).\n\n> If a discover call times out, do **not** blindly retry — there is no idempotency key and a retry can charge another 15 credits. Reconcile with the free `GET /ideas` first.\n## Create a consistent character\nBuild a reusable AI character from a reference photo.\n\n1. **Pick a genre** *(optional)* — `GET /characters/genres`.\n2. **Create** — `POST /characters` (`multipart/form-data`) with an `image`. Keep the returned `id`.\n3. **Preview** — `POST /characters/{id}/preview` with a `genre_id` (synchronous, up to ~90s, 5/min). Pick a candidate from `data.previews[]`.\n4. **Train** — `POST /characters/{id}/train` with that `preview_id` plus `name`, `age`, `gender`. **Charges 10 credits.** Poll `GET /characters/{id}` until `data.status` is `ready`.\n\n## Authentication\nAll endpoints require a **Bearer token**. Send it on every request:\n\n```http\nAuthorization: Bearer <your-api-token>\n```\n\nGenerate a token from your Syllaby account settings. Treat it like a\npassword — never expose it in client-side code.\n\nThe v2 API is token-only and stateless: authenticate with `Authorization: Bearer <token>` on every request. Do **not** send cookies or a CSRF token — they are ignored.\n\n## Base URL\nProduction requests go to `https://api.syllaby.io/v2`. Every path in this\nreference is relative to that base.\n\n## Subscription required\nEvery generative endpoint requires an **active paid subscription** — reads\nincluded. Two distinct `403` codes tell you exactly why a caller was\nrejected, before any ownership, credit, or validation check runs:\n\n| Code | Who gets it | Message |\n|------|-------------|---------|\n| `PAID-SUBSCRIPTION-REQUIRED` | Subscribed but **on a trial** | `API access requires an active paid subscription. Trials are not eligible — start a paid subscription to unlock the API.` |\n| `SUBSCRIPTION-REQUIRED` | No subscription (never subscribed, expired, or canceled) | `An active subscription is required.` |\n\nThe public API has no free tier and trials are not eligible; access is\nrestored automatically the moment the subscription becomes paid. Only\n`GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable\nwithout a paid subscription.\n\n## Credits\nGenerative actions (rendering, script generation) consume account credits.\nUse the credit-cost and estimate endpoints to check the price before you\nspend, and the credit history endpoint to audit usage.\nCredits consumed through the public API are tagged at the ledger level, so\nAPI-originated spend is distinguishable from in-app usage. Audit it with\n`GET /credits/history` — each entry records the action and the credits charged —\nand look up the per-action price list with `GET /credits/costs`.\n\n## Responses & errors\nResponses are JSON wrapped in a `{ message, status, data }` envelope.\nErrors use standard HTTP status codes — `400` (bad request, e.g. an\n`include` value outside the endpoint's allowlist), `401` (unauthenticated),\n`402` (payment required — insufficient credits), `404` (not found),\n`422` (validation), and `429` (rate limited).\n\nError payloads include a stable machine-readable `error.code`:\n\n| Code | Meaning |\n|------|---------|\n| `GEN-UNAUTHORIZED` | Missing, invalid, or revoked API key (`401`). |\n| `GEN-FORBIDDEN` | Authenticated but not allowed to act on this resource (`403`). |\n| `GEN-NOT-FOUND` | Resource does not exist or is not yours (`404`). |\n| `GEN-WRONG-ARGS` | Malformed request arguments (`400`). |\n| `GEN-API-ERROR` | Unexpected server-side error (`5xx`). |\n| `SUBSCRIPTION-REQUIRED` | No active subscription (`403`). |\n| `PAID-SUBSCRIPTION-REQUIRED` | Trial subscription — the API is paid-only (`403`). |\n| `INSUFFICIENT-CREDITS` | Not enough credits for the requested action (`402`). |\n| `EMAIL-NOT-VERIFIED` | Account email address not verified yet (`403`). |\n| `FEATURE-NOT-ALLOWED` | Feature not included in the current plan (`403`). |\n| `REACH-PLAN-LIMIT` / `REACH-PLAN-STORAGE-LIMIT` / `REACH-PLAN-PUBLISH-LIMIT` | A plan quota was exhausted (`403`). |\n\n## Rate limiting\nRequests are rate limited **per API token** — 30 requests per minute by\ndefault. Every response carries `X-RateLimit-Limit` and\n`X-RateLimit-Remaining` headers so you can pace requests proactively.\nWhen you exceed the limit the API responds with `429 Too Many Requests`\nplus `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix\ntimestamp when the window resets) — back off until then and retry.\nThe `scrape-script` and `scrape-images` endpoints additionally draw from a\nshared scraping capacity pool; when it is exhausted they return `429`\nindependently of your per-token allowance — retry later.\n\n## MCP server\nPrefer working from an AI agent? The official\n[`@syllaby-ai/mcp-server`](https://www.npmjs.com/package/@syllaby-ai/mcp-server)\nexposes this entire API as Model Context Protocol tools for Claude, Cursor,\nand any MCP-compatible client — installable via npm, the MCP Registry,\nSmithery, or as a desktop extension. Set `SYLLABY_API_KEY` and point\n`SYLLABY_API_BASE_URL` at this API's base URL.\n\n## Changelog\n- **2026-07-04** — Trial subscriptions are rejected with the dedicated\n  `PAID-SUBSCRIPTION-REQUIRED` code; scene `duration` validates against the\n  clip engine's supported values; `POST /text-to-scene/{storyboard}/scenes`\n  persists `raw_video_prompt` and `duration` on create; `GET /faceless/options`\n  accepts both CSV and array syntax for `only`.\n- **2026-07-02** — Public API restricted to paid subscriptions (trials excluded).\n  Render duration is floored at 1 second.\n- **2026-07-01** — Dedicated B-roll, AI-Visuals, URL-to-Video, and Text-to-Scene modules."
  },
  "servers": [
    {
      "url": "https://api.syllaby.io/v2",
      "description": "Production"
    },
    {
      "url": "https://api.syllaby-stg.com/v2",
      "description": "Staging"
    }
  ],
  "security": [
    {
      "http": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "operationId": "getMyAccount",
        "summary": "Get current account",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/MeResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "name": "Jane Doe",
                    "email": "jane@example.com",
                    "email_verified": true,
                    "credits": {
                      "remaining": 120,
                      "total": 150,
                      "extra": 0
                    },
                    "subscription": {
                      "exists": true,
                      "active": true,
                      "trial": false,
                      "plan": "Pro",
                      "ends_at": "2026-02-01T00:00:00+00:00"
                    },
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns the authenticated user's public account profile: identity, credit balance, and a high-level subscription summary (no billing-provider internals)."
      }
    },
    "/credits/costs": {
      "get": {
        "operationId": "listCreditCosts",
        "summary": "List credit costs",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "description": "Map of feature key to its credit cost. Each value is an object with a `credits` count and an optional `free` allowance.",
                      "additionalProperties": {
                        "type": "object",
                        "properties": {
                          "credits": {
                            "type": "integer",
                            "description": "Credits charged per use of the feature."
                          },
                          "free": {
                            "type": "integer",
                            "description": "Number of free uses granted before credits are charged, if any."
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "idea_discovery": {
                      "credits": 15
                    },
                    "avatar": {
                      "credits": 30
                    },
                    "faceless": {
                      "credits": 13
                    },
                    "image_regenerations": {
                      "credits": 1,
                      "free": 3
                    },
                    "thumbnail_generation": {
                      "credits": 3
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns the per-feature credit cost map so you can show users what each action will cost before they spend credits."
      }
    },
    "/credits/history": {
      "get": {
        "operationId": "listCreditHistory",
        "summary": "List credit history",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    }
                  },
                  "required": [
                    "status",
                    "message"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "label": "Faceless video",
                      "content_type": "Faceless video generated",
                      "credit_spend": "-30",
                      "transaction_type": "Debit",
                      "created_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ],
                  "meta": {
                    "current_page": 1,
                    "per_page": 15,
                    "total": 1
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns the authenticated user's credit ledger (debits and credits), newest first by default. Pass `order=ASC` to reverse, and `per_page` to set the page size (default 12, max 50).",
        "parameters": [
          {
            "name": "order",
            "in": "query",
            "required": false,
            "description": "Sort direction by date. `DESC` (newest first, default) or `ASC`.",
            "schema": {
              "type": "string",
              "enum": [
                "ASC",
                "DESC"
              ],
              "default": "DESC"
            },
            "example": "DESC"
          },
          {
            "name": "per_page",
            "in": "query",
            "required": false,
            "description": "Number of entries per page. Defaults to 12; capped at 50.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 12
            },
            "example": 12
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "description": "Page number of the paginated ledger (see `links`/`meta` in the response).",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "example": 2
          },
          {
            "name": "source",
            "in": "query",
            "required": false,
            "description": "Filter entries by origin. Use `api` to see only spend made through the public API.",
            "schema": {
              "type": "string"
            },
            "example": "api"
          }
        ]
      }
    },
    "/account/auto-topup": {
      "get": {
        "operationId": "getAutoTopUp",
        "summary": "Get auto top-up preference",
        "tags": [
          "Account"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/AutoTopUpResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "enabled": true,
                    "type": "dynamic-credits",
                    "plan_id": null,
                    "units": 5,
                    "enabled_at": "2026-01-01T12:00:00.000000Z",
                    "consecutive_failures": 0
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns the authenticated account's auto top-up preference: whether it's enabled, how it's configured, and its failure/enablement history.\n\nAuto top-up automatically purchases more credits when your **API-originated** balance runs low — credits spent through the v2 API count toward the trigger; credits spent in the Syllaby app do not. It fires once your balance drops below **10%** of your monthly plan credits, purchasing either a fixed credit pack (`type: extra-credits`) or a custom amount (`type: dynamic-credits`), depending on how it's configured. Purchased credits land in your account's **extra credits**, on top of your plan allowance, and a notification is sent for both successful and failed attempts.\n\n**Safeguards:** at most **3** successful top-ups per UTC calendar day; a failed charge starts a **24-hour cooldown** before the next attempt is made; and **3 consecutive failures** disable the preference automatically (`enabled` flips to `false` — `consecutive_failures` tells you how close it is).\n\nSee `PUT /account/auto-topup` for how enabling/disabling works and what a lapsed subscription means for this preference."
      },
      "put": {
        "operationId": "updateAutoTopUp",
        "summary": "Update auto top-up preference",
        "tags": [
          "Account"
        ],
        "requestBody": {
          "description": "`enabled` is always required. Disabling accepts just `enabled: false`; enabling additionally requires `type`, plus `plan_id` or `units` depending on it.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "enabled"
                ],
                "properties": {
                  "enabled": {
                    "type": "boolean",
                    "description": "Turn auto top-up on or off. `false` disables it immediately; every other field is ignored when disabling."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "extra-credits",
                      "dynamic-credits"
                    ],
                    "description": "Required when `enabled` is `true`. Purchase mode: `extra-credits` buys a fixed one-time credit pack (set `plan_id`), `dynamic-credits` buys a custom amount (set `units`)."
                  },
                  "plan_id": {
                    "type": "integer",
                    "description": "Required when `type` is `extra-credits`. Identifier of an active one-time credit-pack plan."
                  },
                  "units": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Required when `type` is `dynamic-credits`. Number of pricing units to purchase — 100 credits per unit. Up to 100 units, only preset values are accepted (1, 2, 3, 4, 5, 10, 20, 30, 50, 100); above 100 (up to 199,999) any integer is accepted."
                  }
                }
              },
              "example": {
                "enabled": true,
                "type": "dynamic-credits",
                "units": 5
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/AutoTopUpResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "enabled": true,
                    "type": "dynamic-credits",
                    "plan_id": null,
                    "units": 5,
                    "enabled_at": "2026-01-01T12:00:00.000000Z",
                    "consecutive_failures": 0
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Enables, reconfigures, or disables auto top-up. Counters (`consecutive_failures`, the daily success count) survive toggling — disabling and re-enabling neither resets the failure history nor bypasses the daily cap.\n\n**Disabling** — send `{ \"enabled\": false }`. Every other field is ignored, and the existing `type`/`plan_id`/`units` configuration is preserved for a future re-enable.\n\n**Enabling** (`enabled: true`) additionally requires:\n- `type` — `extra-credits` (also requires `plan_id`, an active one-time credit-pack plan) or `dynamic-credits` (also requires `units`).\n- A saved default payment method on the account. Without one, the request fails with `422` (`A saved payment method is required to enable auto top-up.`).\n\n**A lapsed subscription blocks this whole endpoint** — `GET` and `PUT /account/auto-topup` both sit behind the paid-subscription gate (`403`, below), the same as every other v2 endpoint. The preference itself is retained while lapsed and can still be reviewed or changed from the Syllaby web app; auto top-up resumes automatically once the subscription is active again."
      }
    },
    "/faceless/options": {
      "get": {
        "operationId": "listFacelessOptions",
        "description": "**Reference data** — the slugs/ids for Step 3 (Configure).\n\nReturns all reference data for building a faceless video in one payload, split into two layers. `mandatory` holds the inputs a typical render needs — aspect_ratios, genres, image_engines, voices. `optional` holds the styling and advanced groups — fonts, transitions, backgrounds, caption effects and positions, overlays, watermark positions, animations, sound effects, volumes, clip engines, and characters. Use the returned slugs/ids when creating, updating, or rendering a video.",
        "summary": "List faceless options",
        "tags": [
          "Faceless Videos"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "description": "Available option groups, split into the ones a render needs and the rest.",
                      "properties": {
                        "mandatory": {
                          "type": "object",
                          "description": "Option groups a typical render needs — pick from these.",
                          "properties": {
                            "aspect_ratios": {
                              "type": "array",
                              "description": "Output frame ratios a render can target.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "slug": {
                                    "type": "string",
                                    "description": "Aspect-ratio value to send (e.g. \"9:16\")."
                                  },
                                  "label": {
                                    "type": "string",
                                    "description": "Human-readable orientation label (e.g. \"Portrait\")."
                                  }
                                }
                              }
                            },
                            "genres": {
                              "type": "array",
                              "description": "Visual genres/styles that drive the image-prompt look.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Identifier of the genre to send as `genre_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the genre."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable slug for the genre."
                                  }
                                }
                              }
                            },
                            "image_engines": {
                              "type": "array",
                              "description": "Text-to-image engines available for image-based renders.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Identifier of the engine to send as `image_engine_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the engine."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable slug for the engine."
                                  },
                                  "type": {
                                    "type": "string",
                                    "description": "Engine category (e.g. \"text-to-image\")."
                                  },
                                  "cost": {
                                    "type": "integer",
                                    "description": "Credit cost multiplier applied when this engine is used."
                                  }
                                }
                              }
                            },
                            "voices": {
                              "type": "array",
                              "description": "Narration voices available for the video.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Identifier of the voice to send as `voice_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the voice."
                                  },
                                  "language": {
                                    "type": "string",
                                    "description": "Spoken language of the voice."
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Voice gender."
                                  }
                                }
                              }
                            }
                          }
                        },
                        "optional": {
                          "type": "object",
                          "description": "Styling and advanced option groups — all optional.",
                          "properties": {
                            "fonts": {
                              "type": "array",
                              "description": "Caption font families.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "transitions": {
                              "type": "array",
                              "description": "Transitions applied between scenes.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "backgrounds": {
                              "type": "array",
                              "description": "Background assets that can sit behind the video.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Identifier of the background to send as `background_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the background."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable slug for the background."
                                  }
                                }
                              }
                            },
                            "caption_effects": {
                              "type": "array",
                              "description": "Visual effects applied to on-screen captions.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "caption_positions": {
                              "type": "array",
                              "description": "On-screen placements for captions.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "overlays": {
                              "type": "array",
                              "description": "Overlay styles applied over the video.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "watermark_positions": {
                              "type": "array",
                              "description": "Placements available for a watermark.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "animations": {
                              "type": "array",
                              "description": "Image animation styles (e.g. pan/zoom).",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "sfx": {
                              "type": "array",
                              "description": "Sound-effect tracks that can be layered onto the video.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "volumes": {
                              "type": "array",
                              "description": "Background-music volume levels.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "name": {
                                    "type": "string",
                                    "description": "Human-readable label for the option."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable identifier to send back when configuring a render."
                                  }
                                }
                              }
                            },
                            "clip_engines": {
                              "type": "array",
                              "description": "Text-to-video (clip) engines available for clip-based renders.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Identifier of the engine to send as `clip_engine_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the engine."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable slug for the engine."
                                  },
                                  "description": {
                                    "type": "string",
                                    "description": "Short description of the engine."
                                  },
                                  "type": {
                                    "type": "string",
                                    "description": "Engine category (e.g. \"text-to-video\")."
                                  },
                                  "cost": {
                                    "type": "array",
                                    "description": "Credit pricing for the engine. Each entry gives a `credits_per_second` rate, optionally conditional on the selected `resolution` and/or `audio` toggle — the entry matching your render settings applies.",
                                    "items": {
                                      "type": "object",
                                      "properties": {
                                        "credits_per_second": {
                                          "type": "number",
                                          "description": "Credits charged per second of generated clip."
                                        },
                                        "resolution": {
                                          "type": "string",
                                          "description": "Resolution this rate applies to, when pricing varies by resolution."
                                        },
                                        "audio": {
                                          "type": "string",
                                          "enum": [
                                            "on",
                                            "off"
                                          ],
                                          "description": "Audio toggle this rate applies to, when pricing varies by audio."
                                        }
                                      },
                                      "required": [
                                        "credits_per_second"
                                      ]
                                    }
                                  }
                                }
                              }
                            },
                            "characters": {
                              "type": "array",
                              "description": "Consistent AI characters you can cast in the video.",
                              "items": {
                                "type": "object",
                                "properties": {
                                  "id": {
                                    "type": "integer",
                                    "description": "Numeric identifier of the character."
                                  },
                                  "uuid": {
                                    "type": "string",
                                    "description": "Stable UUID of the character to send as `character_id`."
                                  },
                                  "name": {
                                    "type": "string",
                                    "description": "Display name of the character."
                                  },
                                  "slug": {
                                    "type": "string",
                                    "description": "Stable slug for the character."
                                  },
                                  "gender": {
                                    "type": "string",
                                    "description": "Character gender — `male`, `female`, `neutral`, or `unknown` when none was supplied at creation."
                                  },
                                  "status": {
                                    "type": "string",
                                    "description": "Readiness state of the character (e.g. \"ready\")."
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "mandatory": {
                      "aspect_ratios": [
                        {
                          "slug": "9:16",
                          "label": "Portrait"
                        }
                      ],
                      "genres": [
                        {
                          "id": 3,
                          "name": "Cinematic",
                          "slug": "cinematic"
                        }
                      ],
                      "image_engines": [
                        {
                          "id": 5,
                          "name": "Hyperflux",
                          "slug": "hyperflux",
                          "type": "text-to-image",
                          "cost": 2
                        }
                      ],
                      "voices": [
                        {
                          "id": 12,
                          "name": "Aria",
                          "language": "english",
                          "gender": "female"
                        }
                      ]
                    },
                    "optional": {
                      "fonts": [
                        {
                          "name": "Inter",
                          "slug": "inter"
                        }
                      ],
                      "transitions": [
                        {
                          "name": "Fade",
                          "slug": "fade"
                        }
                      ],
                      "backgrounds": [
                        {
                          "id": 7,
                          "name": "Studio",
                          "slug": "studio"
                        }
                      ],
                      "caption_effects": [
                        {
                          "name": "None",
                          "slug": "none"
                        }
                      ],
                      "caption_positions": [
                        {
                          "name": "Center",
                          "slug": "center"
                        }
                      ],
                      "overlays": [
                        {
                          "name": "None",
                          "slug": "none"
                        }
                      ],
                      "watermark_positions": [
                        {
                          "name": "Bottom Right",
                          "slug": "bottom-right"
                        }
                      ],
                      "animations": [
                        {
                          "name": "Pan In (Zoom In)",
                          "slug": "pan-in"
                        }
                      ],
                      "sfx": [
                        {
                          "name": "None",
                          "slug": "none"
                        }
                      ],
                      "volumes": [
                        {
                          "name": "Medium",
                          "slug": "medium"
                        }
                      ],
                      "clip_engines": [
                        {
                          "id": 23,
                          "name": "Veo 3.1 Fast",
                          "slug": "veo-3-1-fast",
                          "description": "Faster generation with last frame support.",
                          "type": "text-to-video",
                          "cost": [
                            {
                              "audio": "on",
                              "credits_per_second": 4
                            },
                            {
                              "audio": "off",
                              "credits_per_second": 3
                            }
                          ]
                        }
                      ],
                      "characters": [
                        {
                          "id": 2,
                          "uuid": "chr_123",
                          "name": "Maya",
                          "slug": "maya",
                          "gender": "female",
                          "status": "ready"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "parameters": [
          {
            "name": "only",
            "in": "query",
            "required": false,
            "description": "Return only the named option groups. Accepts CSV (`only=voices,genres`) or array (`only[]=voices&only[]=genres`) syntax. Group names: aspect_ratios, genres, image_engines, voices, fonts, transitions, backgrounds, caption_effects, caption_positions, overlays, watermark_positions, animations, sfx, volumes, clip_engines, characters.",
            "schema": {
              "type": "string"
            },
            "example": "voices,genres"
          },
          {
            "name": "summary",
            "in": "query",
            "required": false,
            "description": "When true, return per-group item counts instead of the full payloads — useful to size a follow-up `only` request.",
            "schema": {
              "type": "boolean"
            },
            "example": true
          }
        ]
      }
    },
    "/faceless": {
      "post": {
        "operationId": "createFacelessVideo",
        "summary": "Create a faceless video",
        "tags": [
          "Faceless Videos"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateFacelessRequest"
              },
              "example": {
                "title": "My first faceless video",
                "type": "ai-visuals"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Step 1 of 7 · Create.**\n\nCreates a new faceless video in draft state. Returns the created video — with its render state embedded under `data.video` — so you can configure it (script, voice, visuals) and then render it. This does not start rendering.\n\n**Required:** `title` and `type` — name the video and choose how its visuals are sourced (`type` is fixed at creation and cannot be changed later).\n\nKeep the returned **`id`**: it is the identifier for every follow-up call, including polling `GET /faceless/{id}` (do not use `video_id` for that).\n\n**Requires an active subscription** — no active subscription → `403` `SUBSCRIPTION-REQUIRED` `An active subscription is required.`; the public API has no free tier, so subscribe before creating a video.\n\n→ **Next:** Step 2 — add a script with `PUT /faceless/{faceless}/scripts` (or supply your own via `PATCH /faceless/{faceless}`)."
      }
    },
    "/faceless/{faceless}/scripts": {
      "put": {
        "operationId": "generateFacelessScript",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateFacelessScriptRequest"
              },
              "example": {
                "topic": "Morning routines for better focus",
                "tone": "professional",
                "style": "educational",
                "language": "english",
                "duration": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "description": "Present on credit-charging endpoints.",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "description": "Credit accounting for this operation.",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The exact credits charged for generating the script."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your credit balance after the charge."
                            }
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "anyOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "array",
                          "items": {}
                        },
                        {
                          "type": "null"
                        }
                      ]
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "GEN-API-ERROR"
                        },
                        "status": {
                          "type": "integer",
                          "const": 500
                        }
                      },
                      "required": [
                        "code",
                        "status"
                      ]
                    }
                  },
                  "required": [
                    "message",
                    "error"
                  ]
                }
              }
            }
          }
        },
        "summary": "Generate a faceless script",
        "x-badges": [
          {
            "name": "Charges credits"
          }
        ],
        "description": "**Step 2 of 7 · Add a script.** *(Alternative: skip this generated-script step and supply a full custom script verbatim via `PATCH /faceless/{faceless}` — set the `script` field.)*\n\n💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\n**Before you can generate a script:** create a faceless video first (`POST /faceless`). This charges credits, so make sure your balance is sufficient — `meta.credits.cost` is the exact amount charged.\n\nGenerates a narration script for the faceless video from a topic, tone, style, language, and target duration, and stores it on the video.\n\n**Note the method:** this endpoint is a `PUT` (idempotent replace of the video's script), not a `POST` — each call regenerates the script and overwrites the previous one.\n\n**Preconditions & common errors:**\n- **No active subscription** → `403` `SUBSCRIPTION-REQUIRED` `An active subscription is required.` — checked before anything else; the public API has no free tier.\n- **Video busy** (rendering or syncing) → `403` — you cannot regenerate the script while the video is processing.\n- **Not your video** → `403`.\n- **Insufficient credits** → `402` with code `INSUFFICIENT-CREDITS` and `required` / `available` in the error body.\n- **Missing required fields** (`topic`, `tone`, `style`, `language`, `duration`) → `422`; `topic` is capped at 500 characters.\n\n→ **Next:** Step 3 — configure voice, genre, captions, and visuals with `PATCH /faceless/{faceless}`."
      }
    },
    "/faceless/{faceless}/scrape-images": {
      "post": {
        "operationId": "scrapeFacelessImages",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "description": "The URL to extract images from.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Publicly reachable web page URL to extract product/page images from. Social-media URLs (YouTube, TikTok, Twitter/X, Instagram, Facebook, etc.) are rejected with `422`.",
                    "example": "https://www.amazon.com/dp/B0CXYZ1234"
                  }
                }
              },
              "example": {
                "url": "https://www.amazon.com/dp/B0CXYZ1234"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "assets": [
                      {
                        "id": 1,
                        "user_id": 1,
                        "type": "faceless_background",
                        "status": "success",
                        "order": 0,
                        "media": [
                          {
                            "id": 5,
                            "name": "scene-1",
                            "file_name": "scene-1.png",
                            "mime_type": "image/png",
                            "extension": "png",
                            "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                          }
                        ],
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Scrape images from a URL",
        "description": "**URL-based flow · Step A · Scrape images** *(free)* — extract images from a web page and attach them to a `url-based` video. Required before rendering.\n\n**Free — no credits charged.** Extracts images from the supplied web page URL and attaches them to the `url-based` faceless video as ordered assets. A subsequent `GET /faceless/{faceless}/assets` will list them.\n\n**This endpoint is only valid for `url-based` videos.** Calling it on any other type returns `422`.\n\n**Before you can render a `url-based` video:** you must call this endpoint at least once. A render attempted without scraped assets returns `422 assets`.\n\n**Preconditions & common errors:**\n- **Not a `url-based` video** → `422 faceless` — this step only makes sense for `url-based` videos; the type is fixed at creation.\n- **Social-media or unsupported URL** (YouTube, TikTok, Twitter/X, Instagram, Facebook, etc.) → `422 url`.\n- **Page un-parseable or unreachable** → `422`.\n- **Not your video** → `403`.\n\n→ **Next for url-based:** Step B — generate a script from the same URL with `POST /faceless/{faceless}/scrape-script` (or supply your own via `PATCH /faceless/{faceless}`), then configure (`PATCH`) and render."
      }
    },
    "/faceless/{faceless}/scrape-script": {
      "post": {
        "operationId": "scrapeFacelessScript",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "description": "The URL to generate a script from, plus generation options.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url",
                  "duration",
                  "style",
                  "tone",
                  "language"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "description": "Publicly reachable web page URL to extract script content from. Social-media URLs are rejected with `422`.",
                    "example": "https://www.amazon.com/dp/B0CXYZ1234"
                  },
                  "duration": {
                    "type": "integer",
                    "enum": [
                      30,
                      60,
                      180,
                      300,
                      600,
                      900
                    ],
                    "description": "Target length of the generated script in seconds. Must be one of 30, 60, 180, 300, 600, or 900.",
                    "example": 60
                  },
                  "style": {
                    "type": "string",
                    "description": "Narrative style for the generated script (free-form text, max 255 chars). Examples: educational, storytelling, listicle, conversational, motivational.",
                    "example": "educational"
                  },
                  "tone": {
                    "type": "string",
                    "description": "Tone of voice for the generated script. Examples: professional, friendly, casual, authoritative.",
                    "example": "friendly"
                  },
                  "language": {
                    "type": "string",
                    "description": "Language for the generated script (e.g. \"english\").",
                    "example": "english"
                  }
                }
              },
              "example": {
                "url": "https://www.amazon.com/dp/B0CXYZ1234",
                "duration": 60,
                "style": "educational",
                "tone": "friendly",
                "language": "english"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The exact credits charged for generating the script from the page content. Matches the `CONTENT_PROMPT_REQUESTED` event amount — the same charge as `PUT /faceless/{faceless}/scripts`."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your credit balance after the charge."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "This product helps you focus throughout the day.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Scrape a script from a URL",
        "description": "**URL-based flow · Step B · Scrape script** 💳 — generate a narration script from a web page. Charges `CONTENT_PROMPT_REQUESTED` credits (same as `PUT /faceless/{faceless}/scripts`).\n\n💳 Charges credits (`CONTENT_PROMPT_REQUESTED` — the same amount as `PUT /faceless/{faceless}/scripts`). The response `meta.credits` shows the cost and your remaining balance.\n\nGenerates a narration script directly from the content of the supplied web page URL and stores it on the `url-based` faceless video. Use this as an alternative to `PUT /faceless/{faceless}/scripts` when the script should be grounded in page content rather than a free-form topic.\n\n**Note:** this endpoint works on any faceless video type, not just `url-based` — it generates and stores a script regardless of type. You may also skip both scrape-script and `PUT /scripts` and supply your own script verbatim via `PATCH /faceless/{faceless}`.\n\n**Preconditions & common errors:**\n- **No active subscription** → `403` `SUBSCRIPTION-REQUIRED` `An active subscription is required.` — checked before anything else; the public API has no free tier.\n- **Social-media or unsupported URL** → `422 url`.\n- **Page un-parseable or unreachable** → `422`.\n- **Not your video** → `403`.\n- **Insufficient credits** → `402` with code `INSUFFICIENT-CREDITS` and `required` / `available` in the error body.\n- **Missing required fields** (`url`, `duration`, `style`, `tone`, `language`) → `422`.\n\n→ **Next for url-based:** Step 3 — configure voice, captions, and visuals with `PATCH /faceless/{faceless}`, then render."
      }
    },
    "/faceless/{faceless}": {
      "patch": {
        "operationId": "updateFacelessVideo",
        "summary": "Update a faceless video",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFacelessRequest"
              },
              "example": {
                "voice_id": 12,
                "genre_id": 3,
                "script": "Three habits that quietly improve your focus.",
                "transition": "fade",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Step 3 of 7 · Configure.**\n\n**Before you can update:** the video must not be busy — you cannot edit it while it is rendering or syncing. Wait until it leaves those states.\n\nUpdates the configuration of a faceless video (script, voice, genre, captions, transitions, and more). Only the fields you send are changed.\n\n**Render-only settings:** the caption `effect` and the `overlay` are **not** updatable here — this endpoint silently ignores them (the request succeeds with `200`, but the stored value is unchanged). Set them in the render request body (`POST /faceless/{faceless}/render`) instead.\n\n→ **Next:** Step 4 — *(optional)* estimate the cost with `GET /faceless/{faceless}/estimate`, or skip to Step 5 — render with `POST /faceless/{faceless}/render`."
      }
    },
    "/faceless/{faceless}/estimate": {
      "get": {
        "operationId": "estimateRenderCredits",
        "summary": "Estimate render credits",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "voice_id",
            "in": "query",
            "required": false,
            "description": "What-if override: estimate against this narration voice instead of the one stored on the faceless. Discover voices at `GET /faceless/options?only=voices`.",
            "schema": {
              "type": "integer"
            },
            "example": 12
          },
          {
            "name": "image_engine_id",
            "in": "query",
            "required": false,
            "description": "What-if override: estimate against this text-to-image engine instead of the stored one. Discover engines at `GET /faceless/options?only=image_engines`.",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "clip_engine_id",
            "in": "query",
            "required": false,
            "description": "What-if override: estimate against this text-to-video (clip) engine instead of the stored one. Discover engines at `GET /faceless/options?only=clip_engines`.",
            "schema": {
              "type": "integer"
            },
            "example": 9
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "The required value for the resource."
                        },
                        "available": {
                          "type": "string",
                          "description": "The available value for the resource."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "The sufficient value for the resource."
                        }
                      },
                      "required": [
                        "required",
                        "available",
                        "sufficient"
                      ],
                      "description": "Estimated required credits, available balance, and whether the balance is sufficient."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 30,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string"
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string"
                        },
                        "status": {
                          "type": "integer",
                          "const": 422
                        }
                      },
                      "required": [
                        "code",
                        "status"
                      ]
                    }
                  },
                  "required": [
                    "message",
                    "error"
                  ]
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Step 4 of 7 · Estimate** *(optional)*.\n\nEstimates the number of credits required to render the given faceless video and compares it against the caller's available balance.\n\n**Before calling:** the faceless must already have a **script** and a **voice** configured. Set them with `PUT /faceless/{faceless}/scripts` (or `PATCH /faceless/{faceless}`) and `PATCH /faceless/{faceless}` (e.g. `{ \"voice_id\": 12 }`). By default the estimate reads from the stored faceless.\n\n**What-if overrides (query params):** pass `voice_id`, `image_engine_id`, and/or `clip_engine_id` as query parameters to estimate against a different configuration without saving it — e.g. `?voice_id=12&clip_engine_id=9`. Only these three inputs affect the estimate; `duration`, `genre`, and `aspect_ratio` do not, so they are not accepted here.\n\n**Common errors:**\n- **No script** (and no voiceover generated yet) → `422` `A script is required before rendering.`\n- **No voice** → `422` `Voice was not provided.` (or `Voice not found.` when the stored `voice_id` does not exist).\n- **Not your video** → `403`.\n\n**Accuracy:** for per-second (clip-engine) renders the estimate is an approximation — the exact charge is computed during rendering and recorded in the credit ledger (`GET /credits/history`), which is the authoritative record of what was charged.\n\n→ **Next:** Step 5 — render with `POST /faceless/{faceless}/render`."
      }
    },
    "/faceless/{faceless}/render": {
      "post": {
        "operationId": "renderFacelessVideo",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "description": "Present on credit-charging endpoints.",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "description": "Credit accounting for this operation.",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The credits that will be charged for this render. The charge runs asynchronously inside the render pipeline; if the render fails before the charge step, nothing is charged. For per-second (clip-engine) renders this is an approximation — the exact charge is computed during rendering, and the credit ledger (`GET /credits/history`) is the authoritative record.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your credit balance. The render charge runs asynchronously (charged renders are refunded if rendering later fails), so this is the pre-charge balance."
                            }
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Whoops! Something went wrong."
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "GEN-API-ERROR"
                        },
                        "status": {
                          "type": "integer",
                          "const": 500
                        }
                      },
                      "required": [
                        "code",
                        "status"
                      ]
                    }
                  },
                  "required": [
                    "message",
                    "error"
                  ]
                }
              }
            }
          }
        },
        "summary": "Render a faceless video",
        "x-badges": [
          {
            "name": "Charges credits"
          }
        ],
        "description": "**Step 5 of 7 · Render.**\n\n💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\n**Before you can render:** first create a faceless video (`POST /faceless`), then generate or supply its script (`PUT /faceless/{faceless}/scripts`) and configure its options — voice, genre, captions, and visuals (`PATCH /faceless/{faceless}`). Optionally call the estimate endpoint first to check the credit cost against your balance.\n\nStarts rendering the faceless video asynchronously and charges the required credits — `meta.credits.cost` is the amount that will be charged once the pipeline reaches the charge step. For per-second clip-engine renders (`ai-clips`) this is an approximation; the exact charge is computed during rendering and recorded in `GET /credits/history` (the authoritative record). Returns immediately with HTTP 202 while generation runs in the background.\n\n**To track progress:** poll `GET /faceless/{id}` — use the faceless **`id`**, not `video_id` — and read `data.video.status` (the `video` object is always embedded). It moves from `rendering` to `completed` (or `failed`). When complete, the playable file is at `data.video.url`; on failure, `data.video.failure` carries the reason. The faceless object itself has no status field; the render lifecycle lives on the embedded `video`. See the **Get your rendered video** guide in the introduction.\n\n**Preconditions & common errors** (checked before any charge):\n- **No script** → `403` `A script is required before rendering.` — set one with `PUT /faceless/{faceless}/scripts` or `PATCH /faceless/{faceless}`.\n- **No voice** → `403` `Voice was not provided.` (or `Voice not found.` when `voice_id` does not exist) — set it with `PATCH /faceless/{faceless}`.\n- **Insufficient credits** → `402` with code `INSUFFICIENT-CREDITS` and `required` / `available` in the error body — check first with `GET /faceless/{faceless}/estimate`.\n- **Video busy** (already rendering or syncing) → `403` `The video is processing currently. Please try again once finished`.\n- **Storage full** → `403` `Please remove some files first` (code `REACH-PLAN-STORAGE-LIMIT`).\n- **No active subscription** → `403` `SUBSCRIPTION-REQUIRED` `An active subscription is required.` — the public API has no free tier; subscribe before generating.\n- **Missing genre** on an `ai-visuals` / `ai-clips` render — no genre set at creation or via `PATCH`, and none in the render body → `422` `A genre is required for AI visuals and AI clips.` A genre configured earlier is reused automatically, so you do **not** need to resend `genre_id` on every render.\n- **Invalid `image_engine_id`** (unknown id, or an engine that isn't a `text-to-image` engine) → `422` on the `image_engine_id` key, e.g. `The selected image engine id is invalid.`\n- **Missing image engine** on an `ai-visuals` / `ai-clips` render — no `image_engine_id` in the body and none saved on the video → `422` `An image engine is required for AI visuals and AI clips.` Like the genre, an engine configured earlier is reused automatically.\n- **`url-based` video with no scraped assets** → `422` `assets` — call `POST /faceless/{faceless}/scrape-images` first; without scraped images the render would produce an empty video.\n- **Missing required fields** (`script`, `duration`, `aspect_ratio`) → `422`.\n\n→ **Next:** Step 6 — track progress by polling `GET /faceless/{id}` (use the faceless `id`, not `video_id`).",
        "requestBody": {
          "description": "Render configuration for the faceless video. Every field is optional: `script`, `duration`, and `aspect_ratio` are auto-filled from the saved draft when omitted (configure it first via `PUT /faceless/{faceless}/scripts` and `PATCH /faceless/{faceless}`), so a fully-configured video can be rendered with an empty body. A `422` is only returned when a required value is missing from both the body and the draft.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "script": {
                    "type": "string",
                    "description": "Narration script text for the video. Optional — falls back to the draft's stored script when omitted."
                  },
                  "duration": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Target video length in seconds (a positive integer). Optional — falls back to the draft's estimated duration when omitted. Not restricted to the script-generation presets (those fixed values apply only to PUT /faceless/{faceless}/scripts)."
                  },
                  "aspect_ratio": {
                    "type": "string",
                    "description": "Output aspect ratio. Optional — falls back to the draft's stored aspect ratio when omitted. Allowed values are listed under faceless options (aspect_ratios).",
                    "example": "9:16"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Optional title for the video."
                  },
                  "voice_id": {
                    "type": "integer",
                    "description": "Identifier of the narration voice (see faceless options)."
                  },
                  "background_id": {
                    "type": "integer",
                    "description": "Identifier of the background asset (see faceless options)."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "b-roll",
                      "url-based",
                      "ai-visuals",
                      "ai-clips"
                    ],
                    "description": "Faceless video type — controls how the visuals are sourced (stock b-roll, a source URL, AI-generated images, or AI-generated clips)."
                  },
                  "genre_id": {
                    "type": "integer",
                    "description": "Identifier of the genre/style that drives the image-prompt look. REQUIRED for image-based renders (`type` of `ai-visuals` or `ai-clips`); optional for `b-roll` / `url-based` renders that don't use a genre. Allowed values are listed under faceless options (genres).",
                    "example": 3
                  },
                  "character_id": {
                    "type": "integer",
                    "description": "Identifier of the consistent character (see faceless options)."
                  },
                  "image_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-image engine (see faceless options)."
                  },
                  "clip_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
                  },
                  "transition": {
                    "type": "string",
                    "description": "Transition slug applied between scenes. Allowed values are listed under faceless options (transitions)."
                  },
                  "animation": {
                    "type": "string",
                    "description": "Per-image motion effect slug. Allowed values are listed under faceless options (animations)."
                  },
                  "overlay": {
                    "type": "string",
                    "description": "Overlay style slug applied over the video. Allowed values are listed under faceless options (overlays). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                  },
                  "sfx": {
                    "type": "string",
                    "description": "Sound-effect slug applied to the video. Allowed values are listed under faceless options (sfx)."
                  },
                  "ai_labels": {
                    "type": "boolean",
                    "description": "Whether AI-content disclosure labels are applied on publish."
                  },
                  "custom_description": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Custom caption/description applied to published posts."
                  },
                  "destination_id": {
                    "type": "integer",
                    "description": "Identifier of the destination folder/resource to file the video under."
                  },
                  "captions": {
                    "type": "object",
                    "description": "Caption styling. Only `font_family`, `font_color`, `font_url`, `position`, and `effect` are honored; any other caption keys are ignored.",
                    "properties": {
                      "font_family": {
                        "type": "string",
                        "description": "Caption font family slug (see faceless options)."
                      },
                      "font_color": {
                        "type": "string",
                        "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
                      },
                      "font_url": {
                        "type": "string",
                        "description": "URL of a custom font file to use for captions."
                      },
                      "position": {
                        "type": "string",
                        "description": "On-screen caption position slug. Allowed values are listed under faceless options (caption_positions)."
                      },
                      "effect": {
                        "type": "string",
                        "description": "Caption effect slug applied to on-screen text. Allowed values are listed under faceless options (caption_effects). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                      }
                    }
                  },
                  "watermark": {
                    "type": "object",
                    "description": "Watermark image and placement. Provide exactly one source — `id`, `url`, or `file` (mutually exclusive).",
                    "properties": {
                      "id": {
                        "type": "integer",
                        "description": "Identifier of a watermark asset you own. Mutually exclusive with `url` and `file`."
                      },
                      "url": {
                        "type": "string",
                        "description": "Remote URL of the watermark image. Mutually exclusive with `id` and `file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded watermark image file (jpg, jpeg, png, webp; max 5 MB). Mutually exclusive with `id` and `url`."
                      },
                      "position": {
                        "type": "string",
                        "description": "Watermark placement slug. Allowed values are listed under faceless options (watermark_positions)."
                      },
                      "opacity": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Watermark opacity as a percentage (0–100)."
                      }
                    }
                  },
                  "music_id": {
                    "type": "integer",
                    "description": "Identifier of a background music track (media id). Mutually exclusive with `music.url` and `music.file`."
                  },
                  "music": {
                    "type": "object",
                    "description": "Background music source. Provide exactly one of `url` or `file`, and only when `music_id` is omitted (all three are mutually exclusive).",
                    "properties": {
                      "url": {
                        "type": "string",
                        "description": "Remote URL of a music track. Mutually exclusive with `music_id` and `music.file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded music file (mp3, wav, aac, m4a, ogg; max 20 MB). Mutually exclusive with `music_id` and `music.url`."
                      }
                    }
                  },
                  "volume": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "description": "Background-music volume level. Required when any music source is set."
                  },
                  "publications": {
                    "type": "array",
                    "description": "Social posts to schedule for the rendered video.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "channel_id": {
                          "type": "integer",
                          "description": "Identifier of the connected social channel to publish to."
                        },
                        "scheduled_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Future timestamp to publish the post, or null to publish immediately."
                        }
                      }
                    }
                  },
                  "assets": {
                    "type": "array",
                    "description": "Explicit ordered media assets to compose the video from. Orders must start at 0 and be consecutive with no gaps.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "order"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Identifier of the media asset."
                        },
                        "order": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "Zero-based position of the asset in the sequence."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "script": "Three small habits that quietly improve your focus every day.",
                "duration": 60,
                "aspect_ratio": "9:16",
                "type": "ai-visuals",
                "title": "Focus habits",
                "voice_id": 12,
                "genre_id": 3,
                "image_engine_id": 1,
                "clip_engine_id": 2,
                "transition": "fade",
                "animation": "pan-in",
                "overlay": "none",
                "sfx": "whoosh",
                "volume": "medium",
                "music_id": 8,
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                },
                "publications": [
                  {
                    "channel_id": 5,
                    "scheduled_at": "2025-02-01T18:30:00Z"
                  }
                ],
                "assets": [
                  {
                    "id": 101,
                    "order": 0
                  },
                  {
                    "id": 102,
                    "order": 1
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/faceless/{id}": {
      "get": {
        "operationId": "getFacelessVideo",
        "summary": "Get a faceless video",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          },
          {
            "name": "include",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated list of related resources to embed. Allowed values: `video`, `captions`, `media`, `music`, `voice`, `background`, `genre`, `watermark`, `character`, `assets`. Any other value is rejected with `400 Bad Request`. Note that `video` is always embedded in the response — you never need `include` to read render progress.",
            "example": "captions,voice"
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": "https://cdn.syllaby.dev/videos/10/final.mp4",
                      "status": "completed",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": "2026-01-01T12:05:00.000000Z",
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Step 6 of 7 · Track progress.**\n\nReturns a single faceless video you own. The render state is always embedded under `data.video` — no `include` needed: `url` (null until the render completes), `status`, and `failure` (`code` + `message`, non-null only when the render failed).\n\nUse the `include` query parameter to embed further related resources; values outside the documented allowlist are rejected with `400 Bad Request`.\n\nResponds with `404 Not Found` when the id does not exist **or** belongs to another account. Make sure you pass the faceless **`id`** (from the create/render response), not `video_id` — they are different identifiers, and polling with `video_id` is the most common cause of unexpected 404s.\n\n→ **Next:** when `data.video.status` is `completed`, you have your video — *(optional)* Step 7, export a restyled cut with `POST /faceless/{faceless}/export`. If it is `failed`, retry with `POST /faceless/{faceless}/retry`."
      }
    },
    "/faceless/{faceless}/retry": {
      "post": {
        "operationId": "retryFacelessRender",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "description": "Present on credit-charging endpoints.",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "description": "Credit accounting for this operation.",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The credits charged for the retry. For a video that had already been exported this is the exact export-fix amount charged (`0` when nothing qualified for a charge). For an un-exported video the charge runs asynchronously, so this is the preflight estimate that will be charged.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your credit balance at the time of the response. When the charge runs asynchronously (retry of an un-exported video) this is the pre-charge balance."
                            }
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 1,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Retry a faceless render",
        "x-badges": [
          {
            "name": "Charges credits"
          }
        ],
        "description": "**Step 6 of 7 · Track progress — retry a failed render.**\n\n💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\n**Before you can retry:** the embedded video must have **failed** — fetch `GET /faceless/{id}` and check that `data.video.status` is `failed` (the reason is in `data.video.failure`). The video must also not be busy (rendering or syncing). Retry does nothing for drafts or already-completed videos.\n\nRe-attempts rendering for a faceless video that previously failed. Returns HTTP 202 with the video state embedded under `data.video` while the retry runs asynchronously; track it the same way as render.\n\n**Credits:** for a video that had already been exported, `meta.credits.cost` is the exact export-fix amount charged — `0` when nothing qualified for a charge. For a video that has not been exported, the charge runs asynchronously inside the render pipeline, so `cost` is the preflight estimate that will be charged.\n\n**Preconditions & common errors:**\n- **Video not in a failed state** → `403` `Only failed videos can be re-tried. Please create a new video instead.` — only a `failed` render can be retried.\n- **Video busy** (rendering or syncing) → `403` `The video is still being processed. Please wait until it is finished.`\n- **Insufficient credits** → `402` with code `INSUFFICIENT-CREDITS` and `required` / `available` in the error body.\n- **Not your video** → `403` `You are not allowed to re-generate this video`.\n\n→ **Next:** keep polling `GET /faceless/{id}` until `data.video.status` is `completed`."
      }
    },
    "/faceless/{faceless}/export": {
      "post": {
        "operationId": "exportFacelessVideo",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "description": "Restyling options for the export. All fields are optional; omit a field to keep the rendered video's current styling. Note: unlike render, the watermark accepts only an existing asset `id` (no upload), and music is selected by `music_id` only.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "transition": {
                    "type": "string",
                    "description": "Transition slug applied between scenes. Allowed values are listed under faceless options (transitions)."
                  },
                  "overlay": {
                    "type": "string",
                    "description": "Overlay style slug applied over the video. Allowed values are listed under faceless options (overlays)."
                  },
                  "sfx": {
                    "type": "string",
                    "description": "Sound-effect slug applied to the video. Allowed values are listed under faceless options (sfx)."
                  },
                  "music_id": {
                    "type": "integer",
                    "description": "Identifier of a background music track (media id)."
                  },
                  "volume": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "description": "Background-music volume level. Required when `music_id` is set."
                  },
                  "captions": {
                    "type": "object",
                    "description": "Caption styling. Only `font_family`, `font_color`, `font_url`, `position`, and `effect` are honored; any other caption keys are ignored.",
                    "properties": {
                      "font_family": {
                        "type": "string",
                        "description": "Caption font family slug (see faceless options)."
                      },
                      "font_color": {
                        "type": "string",
                        "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
                      },
                      "font_url": {
                        "type": "string",
                        "description": "URL of a custom font file to use for captions."
                      },
                      "position": {
                        "type": "string",
                        "description": "On-screen caption position slug. Allowed values are listed under faceless options (caption_positions)."
                      },
                      "effect": {
                        "type": "string",
                        "description": "Caption effect slug applied to on-screen text. Allowed values are listed under faceless options (caption_effects)."
                      }
                    }
                  },
                  "watermark": {
                    "type": "object",
                    "description": "Watermark asset and placement. References an existing asset you own.",
                    "properties": {
                      "id": {
                        "type": "integer",
                        "description": "Identifier of a watermark asset you own."
                      },
                      "position": {
                        "type": "string",
                        "description": "Watermark placement slug. Allowed values are listed under faceless options (watermark_positions)."
                      },
                      "opacity": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Watermark opacity as a percentage (0–100)."
                      }
                    }
                  }
                }
              },
              "example": {
                "transition": "fade",
                "volume": "medium",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "description": "Present on credit-charging endpoints.",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "description": "Credit accounting for this operation.",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The exact credits charged for this export — `0` when nothing changed enough to charge (unchanged options, music, and watermark)."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your credit balance after the charge."
                            }
                          }
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "faceless",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 50,
                      "remaining": 830
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Internal Error"
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "GEN-API-ERROR"
                        },
                        "status": {
                          "type": "integer",
                          "const": 500
                        }
                      },
                      "required": [
                        "code",
                        "status"
                      ]
                    }
                  },
                  "required": [
                    "message",
                    "error"
                  ]
                }
              }
            }
          }
        },
        "summary": "Export a faceless video",
        "x-badges": [
          {
            "name": "Charges credits"
          }
        ],
        "description": "**Step 7 of 7 · Export a restyled cut** *(optional)*.\n\n💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\n**Before you can export:** the video must already be rendered, and must not currently be busy (rendering or syncing).\n\nRebuilds the rendered faceless video source with the supplied styling (captions, watermark, music, transitions) and queues an export. Returns HTTP 202 with the video state embedded under `data.video` while the export runs asynchronously.\n\n**Credits:** `meta.credits.cost` is the exact amount charged — `0` when nothing changed enough to charge (unchanged options, music, and watermark).\n\n**Preconditions & common errors:**\n- **Video not rendered** (still a draft — never rendered) → `403` `The video must be rendered before it can be exported.` Export restyles an already-built video; render it first (`POST /faceless/{faceless}/render`).\n- **Video busy** (rendering or syncing) → `403` `The video is still being processed`.\n- **Not your video** → `403` `You are not allowed to export this video`.\n- **Insufficient credits** (only when the restyle qualifies for a charge) → `402` with code `INSUFFICIENT-CREDITS`.\n\n→ This is the final step. Track the export the same way — poll `GET /faceless/{id}`."
      }
    },
    "/faceless/{faceless}/assets": {
      "get": {
        "operationId": "listFacelessAssets",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "index",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Zero-based scene position; returns only the asset at that position.",
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                      },
                      "description": "The faceless video's ordered media assets."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "user_id": 1,
                      "type": "faceless_background",
                      "status": "success",
                      "order": 0,
                      "media": [
                        {
                          "id": 5,
                          "name": "scene-1",
                          "file_name": "scene-1.png",
                          "mime_type": "image/png",
                          "extension": "png",
                          "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                        }
                      ],
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "List faceless assets",
        "description": "**Reference** — inspect rendered assets (populated after Step 6).\n\nLists the media assets (images, clips) that make up the faceless video, ordered by scene. Pass `index` to fetch the asset at a single scene position.\n\n**Note:** assets are produced during rendering — expect an empty list until the video has been rendered at least once."
      }
    },
    "/faceless/{faceless}/assets/{asset}": {
      "get": {
        "operationId": "getFacelessAsset",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "asset",
            "in": "path",
            "required": true,
            "description": "The asset ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "type": "faceless_background",
                    "status": "success",
                    "order": 0,
                    "media": [
                      {
                        "id": 5,
                        "name": "scene-1",
                        "file_name": "scene-1.png",
                        "mime_type": "image/png",
                        "extension": "png",
                        "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Get a faceless asset",
        "description": "**Reference** — inspect a single rendered asset (populated after Step 6).\n\nReturns a single media asset belonging to the faceless video."
      }
    },
    "/presets/faceless": {
      "get": {
        "operationId": "listFacelessPresets",
        "summary": "List faceless presets",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "include",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated list of related resources to embed. Allowed values: `music`, `voice`, `background`, `watermark`, `genre`. Any other value is rejected with `400 Bad Request`.",
            "example": "music,voice"
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "const": "Success.",
                          "description": "Human-readable status message for the response."
                        },
                        "status": {
                          "type": "integer",
                          "const": 200,
                          "description": "HTTP status code echoed in the response body."
                        },
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/FacelessPresetResource"
                          },
                          "description": "The authenticated user's saved faceless presets."
                        }
                      },
                      "required": [
                        "message",
                        "status",
                        "data"
                      ]
                    },
                    {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "const": "Success.",
                          "description": "Human-readable status message for the response."
                        },
                        "status": {
                          "type": "integer",
                          "const": 200,
                          "description": "HTTP status code echoed in the response body."
                        },
                        "data": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "minItems": 0,
                          "maxItems": 0,
                          "additionalItems": false,
                          "description": "The authenticated user's saved faceless presets."
                        }
                      },
                      "required": [
                        "message",
                        "status",
                        "data"
                      ]
                    }
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "user_id": 1,
                      "name": "My default preset",
                      "voice_id": 12,
                      "genre_id": 3,
                      "orientation": "portrait",
                      "font_family": "inter",
                      "font_color": "#FFFFFF",
                      "volume": "medium",
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Reusable presets** — saved defaults you can apply at Step 1 (Create).\n\nLists the authenticated user's saved faceless presets, newest first. A preset bundles reusable defaults (voice, genre, captions, watermark, etc.) you can apply when creating videos.\n\nUse the `include` query parameter to embed related resources; values outside the documented allowlist are rejected with `400 Bad Request`."
      },
      "post": {
        "operationId": "createFacelessPreset",
        "summary": "Create a faceless preset",
        "tags": [
          "Faceless Videos"
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManageFacelessPresetRequest"
              },
              "example": {
                "name": "My default preset",
                "voice_id": 12,
                "genre_id": 3,
                "orientation": "portrait",
                "font_family": "inter",
                "font_color": "#FFFFFF",
                "volume": "medium"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessPresetResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "name": "My default preset",
                    "voice_id": 12,
                    "genre_id": 3,
                    "orientation": "portrait",
                    "font_family": "inter",
                    "font_color": "#FFFFFF",
                    "volume": "medium",
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Reusable presets** — saved defaults you can apply at Step 1 (Create).\n\nCreates a reusable faceless preset for the authenticated user from the supplied defaults.\n\n**`name` is required on create** — omitting it returns `422`. (On update, `PATCH /presets/faceless/{preset}`, `name` is optional.) All other fields are optional; `duration` must be a positive integer (≥ 1) and `font_color` must be either `default` or a hex value (e.g. `#ffffff`)."
      }
    },
    "/presets/faceless/{preset}": {
      "patch": {
        "operationId": "updateFacelessPreset",
        "summary": "Update a faceless preset",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "preset",
            "in": "path",
            "required": true,
            "description": "The preset ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManageFacelessPresetRequest"
              },
              "example": {
                "name": "Updated preset",
                "voice_id": 14,
                "volume": "high"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessPresetResource"
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "name": "My default preset",
                    "voice_id": 12,
                    "genre_id": 3,
                    "orientation": "portrait",
                    "font_family": "inter",
                    "font_color": "#FFFFFF",
                    "volume": "medium",
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "**Reusable presets.**\n\nUpdates a faceless preset you own. Only the fields you send are changed."
      },
      "delete": {
        "operationId": "deleteFacelessPreset",
        "tags": [
          "Faceless Videos"
        ],
        "parameters": [
          {
            "name": "preset",
            "in": "path",
            "required": true,
            "description": "The preset ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "204": {
            "description": "No content"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Delete a faceless preset",
        "description": "**Reusable presets.**\n\nPermanently deletes a faceless preset you own. Responds with HTTP 204 on success."
      }
    },
    "/text-to-video/models": {
      "get": {
        "tags": [
          "Text to Video"
        ],
        "responses": {
          "200": {
            "description": "The models available to the caller's plan.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "status",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "description": "Text-to-video models available to the caller's plan.",
                      "items": {
                        "type": "object",
                        "description": "A text-to-video model.",
                        "properties": {
                          "id": {
                            "type": "integer",
                            "description": "Unique numeric identifier of the model."
                          },
                          "slug": {
                            "type": "string",
                            "description": "Stable model identifier. Pass it as `model` on the create and estimate endpoints."
                          },
                          "name": {
                            "type": "string",
                            "description": "Display name of the model."
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Human-readable description of what the model is best at."
                          },
                          "modifiers": {
                            "type": "object",
                            "description": "Menus of accepted generation modifiers, keyed by modifier name (`duration`, `resolution`, `aspect_ratio`, `audio`, and — when supported — `first_frame`, `last_frame`, `image`, `video`). Menu entries list their allowed `options` and the `default` used when the field is omitted; media entries list the accepted kinds and `max_count`. A modifier missing from this map is not supported by the model and is rejected with `422`.",
                            "additionalProperties": {
                              "type": "object",
                              "description": "One modifier menu.",
                              "properties": {
                                "type": {
                                  "type": "string",
                                  "description": "Menu kind (e.g. \"select\", \"toggle\", \"media\")."
                                },
                                "default": {
                                  "description": "Value applied when the modifier is omitted from a request."
                                },
                                "options": {
                                  "type": "array",
                                  "description": "Allowed values for the modifier.",
                                  "items": {}
                                },
                                "accept": {
                                  "type": "array",
                                  "description": "Accepted media kinds (media modifiers only).",
                                  "items": {
                                    "type": "string"
                                  }
                                },
                                "max_count": {
                                  "type": "integer",
                                  "description": "Maximum number of media items accepted (media modifiers only)."
                                },
                                "required": {
                                  "type": "boolean",
                                  "description": "Whether the modifier must be provided (media modifiers only)."
                                }
                              }
                            }
                          },
                          "pricing": {
                            "type": "array",
                            "description": "Per-second pricing tiers. The tier whose modifier values (e.g. `resolution`) match the request applies; the clip then costs `credits_per_second × duration`, rounded up. `GET /text-to-video/estimate` returns the exact resulting charge.",
                            "items": {
                              "type": "object",
                              "description": "One pricing tier: a `credits_per_second` rate plus the modifier values it applies to (e.g. `resolution`).",
                              "properties": {
                                "credits_per_second": {
                                  "type": "number",
                                  "description": "Credits charged per second of generated video at this tier."
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 7,
                      "slug": "veo-3-fast",
                      "name": "Veo 3 Fast",
                      "description": "Fast general-purpose clips with optional native audio.",
                      "modifiers": {
                        "duration": {
                          "type": "select",
                          "default": 8,
                          "options": [
                            4,
                            6,
                            8
                          ]
                        },
                        "resolution": {
                          "type": "select",
                          "default": "720p",
                          "options": [
                            "720p",
                            "1080p"
                          ]
                        },
                        "aspect_ratio": {
                          "type": "select",
                          "default": "16:9",
                          "options": [
                            "16:9",
                            "9:16"
                          ]
                        },
                        "audio": {
                          "type": "toggle",
                          "default": "off"
                        },
                        "first_frame": {
                          "type": "media",
                          "accept": [
                            "image"
                          ],
                          "max_count": 1,
                          "required": false
                        }
                      },
                      "pricing": [
                        {
                          "resolution": "720p",
                          "credits_per_second": 4
                        },
                        {
                          "resolution": "1080p",
                          "credits_per_second": 6
                        }
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "operationId": "listTextToVideoModels",
        "summary": "List text-to-video models",
        "description": "**Step 1 of 4 · Choose a model.**\n\nReturns the text-to-video models available on **your subscription plan** — models outside the plan are omitted entirely (and rejected with `422` by the create and estimate endpoints).\n\nEach model carries everything needed to assemble a valid create request:\n\n- **`modifiers`** — the menus of accepted generation options, keyed by modifier name. Menu modifiers (`duration`, `resolution`, `aspect_ratio`, `audio`) list their allowed `options` and the `default` applied when you omit the field. Media modifiers (`first_frame`, `last_frame`, `image`, `video`) appear only when the model supports them, with the accepted kinds and `max_count`.\n- **`pricing`** — per-second pricing tiers. The tier whose modifier values (e.g. `resolution`) match your request applies, and the clip costs `credits_per_second × duration`, rounded up. Use `GET /text-to-video/estimate` for the exact figure — it always equals the charge.\n\n→ **Next:** Step 2 — *(optional)* estimate the cost with `GET /text-to-video/estimate`, or skip to Step 3 — create the clip with `POST /text-to-video`."
      }
    },
    "/text-to-video/estimate": {
      "get": {
        "tags": [
          "Text to Video"
        ],
        "parameters": [
          {
            "name": "model",
            "in": "query",
            "required": true,
            "description": "Slug of the text-to-video model (from `GET /text-to-video/models`).",
            "schema": {
              "type": "string"
            },
            "example": "veo-3-fast"
          },
          {
            "name": "duration",
            "in": "query",
            "required": false,
            "description": "Clip length in seconds. Defaults to the model's `duration` default — pass the value you will send on create so the figures match.",
            "schema": {
              "type": "integer"
            },
            "example": 8
          },
          {
            "name": "resolution",
            "in": "query",
            "required": false,
            "description": "Output resolution. Defaults to the model's `resolution` default.",
            "schema": {
              "type": "string"
            },
            "example": "1080p"
          },
          {
            "name": "aspect_ratio",
            "in": "query",
            "required": false,
            "description": "Output aspect ratio. Defaults to the model's `aspect_ratio` default.",
            "schema": {
              "type": "string"
            },
            "example": "16:9"
          },
          {
            "name": "audio",
            "in": "query",
            "required": false,
            "description": "Native-audio setting. Defaults to the model's `audio` default.",
            "schema": {
              "type": "string"
            },
            "example": "off"
          }
        ],
        "responses": {
          "200": {
            "description": "The exact charge for the clip, against the caller's balance.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "status",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "Exact credits the clip will cost — `POST /text-to-video` charges precisely this amount for the same model and modifiers."
                        },
                        "available": {
                          "type": "integer",
                          "description": "Credits currently available on your account."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "Whether your available balance covers the required amount."
                        }
                      },
                      "description": "Exact credits the clip will cost, your available balance, and whether the balance covers it."
                    }
                  }
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 32,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "description": "The `model` is unknown, inactive, or not available on your plan — the response does not distinguish \"does not exist\" from \"plan-blocked\".",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Error overview."
                    },
                    "error": {
                      "type": "object",
                      "description": "Machine-readable error details.",
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable error code — `GEN-WRONG-ARGS` here."
                        },
                        "status": {
                          "type": "integer",
                          "description": "HTTP status code echoed in the error body."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "The selected model is invalid.",
                  "error": {
                    "code": "GEN-WRONG-ARGS",
                    "status": 422
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "operationId": "estimateTextToVideoCredits",
        "summary": "Estimate clip credits",
        "description": "**Step 2 of 4 · Estimate** *(optional)*.\n\nDry-run credit estimate for a text-to-video clip, compared against your available balance.\n\n**The estimate equals the charge — exactly.** Defaults are applied exactly as `POST /text-to-video` applies them (any omitted modifier falls back to the model's `default`), and the same pricing formula runs, so `required` is the precise amount the create call will deduct for the same `model` and modifiers. The charge is synchronous, so there is no drift — unlike the faceless render estimate, which approximates per-second renders.\n\n⚠️ Modifiers are **flat query keys** (`?model=veo-3-fast&duration=4`), not nested — the create endpoint's `modifiers[duration]` form is ignored here, and the estimate silently falls back to the engine defaults.\n\nResponds with `422` when the `model` is unknown, inactive, or not available on your plan.\n\n→ **Next:** Step 3 — create the clip with `POST /text-to-video`."
      }
    },
    "/text-to-video": {
      "post": {
        "tags": [
          "Text to Video"
        ],
        "requestBody": {
          "description": "The model, prompt, and any generation modifiers for the clip. Media modifiers are HTTPS URLs — fetched and validated before the charge.",
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "model",
                  "prompt"
                ],
                "properties": {
                  "model": {
                    "type": "string",
                    "description": "Slug of the text-to-video model to use (from `GET /text-to-video/models`). Unknown models — and models outside your plan — are rejected with `422`."
                  },
                  "prompt": {
                    "type": "string",
                    "description": "Text prompt describing the clip — between 5 and 1,500 words."
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Optional title for the clip. Defaults to \"Untitled video <current date/time>\"."
                  },
                  "modifiers": {
                    "type": "object",
                    "description": "Generation modifiers. All fields are optional — an omitted menu modifier falls back to the model's `default`. Values must come from the model's menus, and media modifiers are accepted only when the model supports them (`422` otherwise).",
                    "properties": {
                      "duration": {
                        "type": "integer",
                        "description": "Clip length in seconds — one of the model's `duration` options. The credit cost scales with it."
                      },
                      "resolution": {
                        "type": "string",
                        "description": "Output resolution — one of the model's `resolution` options (e.g. \"720p\", \"1080p\"). Pricing tiers often key off this."
                      },
                      "aspect_ratio": {
                        "type": "string",
                        "description": "Output aspect ratio — one of the model's `aspect_ratio` options (e.g. \"16:9\", \"9:16\")."
                      },
                      "audio": {
                        "type": "string",
                        "description": "Whether the model generates native audio — one of the model's `audio` options."
                      },
                      "first_frame": {
                        "type": "string",
                        "description": "URL of an image (jpeg/png/webp, max 10 MB) to pin as the clip's first frame. Must be an http(s) URL on a publicly reachable host (standard ports, no credentials) — private/internal addresses are rejected. The file is downloaded and validated before any credits are charged, so a bad URL costs nothing."
                      },
                      "last_frame": {
                        "type": "string",
                        "description": "URL of an image (jpeg/png/webp, max 10 MB) to pin as the clip's last frame. Must be an http(s) URL on a publicly reachable host (standard ports, no credentials) — private/internal addresses are rejected. The file is downloaded and validated before any credits are charged, so a bad URL costs nothing."
                      },
                      "image": {
                        "type": "array",
                        "description": "URLs of reference images (jpeg/png/webp, max 10 MB each) to guide generation. The model's `image` menu caps how many are accepted.",
                        "items": {
                          "type": "string",
                          "description": "Reference image URL. Must be an http(s) URL on a publicly reachable host (standard ports, no credentials) — private/internal addresses are rejected. The file is downloaded and validated before any credits are charged, so a bad URL costs nothing."
                        }
                      },
                      "video": {
                        "type": "array",
                        "description": "URLs of reference videos (mp4/quicktime/webm, max 25 MB each) to guide generation. The model's `video` menu caps how many are accepted.",
                        "items": {
                          "type": "string",
                          "description": "Reference video URL. Must be an http(s) URL on a publicly reachable host (standard ports, no credentials) — private/internal addresses are rejected. The file is downloaded and validated before any credits are charged, so a bad URL costs nothing."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "model": "veo-3-fast",
                "prompt": "A flagship smartphone rotating slowly on a marble pedestal, studio lighting, shallow depth of field, macro details on the camera array.",
                "title": "Phone hero shot",
                "modifiers": {
                  "duration": 8,
                  "resolution": "1080p",
                  "aspect_ratio": "16:9"
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "The clip, queued for generation. `meta.credits.cost` is the exact charge.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "status",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "description": "A text-to-video clip.",
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Unique numeric identifier of the clip. Use it to poll `GET /text-to-video/{id}`."
                        },
                        "title": {
                          "type": "string",
                          "description": "Title of the clip. Defaults to \"Untitled video <date time>\" when not supplied at creation."
                        },
                        "type": {
                          "type": "string",
                          "description": "Video type discriminator — always `text_to_video` for this resource."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "rendering",
                            "completed",
                            "failed"
                          ],
                          "description": "Clip-level lifecycle status: `rendering` while the clip is generated and composed, `completed` when done, `failed` when generation failed. The deliverable itself is tracked on `asset.status`."
                        },
                        "asset": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "description": "Generation state of the underlying clip asset — the deliverable lives here. Null only when no generation is attached to the record.",
                          "properties": {
                            "status": {
                              "type": "string",
                              "enum": [
                                "draft",
                                "processing",
                                "success",
                                "failed"
                              ],
                              "description": "Asset lifecycle status: `draft` (queued, generation not started), `processing` (generating), `success` (file ready at `url`), or `failed` (reason in `failure`; the charge is refunded automatically)."
                            },
                            "url": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "description": "Playable URL of the generated clip (mp4). Populated once `status` is `success`; null while queued/processing and on failure."
                            },
                            "failure": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "description": "Human-readable reason the generation failed. Non-null only when `status` is `failed`."
                            }
                          }
                        },
                        "created_at": {
                          "type": "string",
                          "description": "ISO-8601 timestamp when the clip was created."
                        },
                        "updated_at": {
                          "type": "string",
                          "description": "ISO-8601 timestamp when the clip was last updated."
                        }
                      }
                    },
                    "meta": {
                      "type": "object",
                      "description": "Operation metadata — the credit charge for this call.",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "description": "The credit charge for this operation and your resulting balance.",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "The exact credits charged for this clip. The charge is synchronous, so this always equals the figure `GET /text-to-video/estimate` returns for the same model and modifiers. If generation later fails, the charge is refunded automatically."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Your plan credit balance after the charge — the estimate endpoint's `available` additionally includes extra credits, so reconcile against the credit history (`GET /credits/history`) for exact accounting."
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 42,
                    "title": "Phone hero shot",
                    "type": "text_to_video",
                    "status": "rendering",
                    "asset": {
                      "status": "draft",
                      "url": null,
                      "failure": null
                    },
                    "created_at": "2026-01-01T12:00:00.000Z",
                    "updated_at": "2026-01-01T12:00:00.000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 48,
                      "remaining": 72
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "description": "Insufficient credits — the API has no free-clip allowance, so every clip is charged. `error.required` and `error.available` carry the figures (the same numbers the estimate endpoint reports).",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Error overview."
                    },
                    "error": {
                      "type": "object",
                      "description": "Machine-readable error details.",
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable error code — `INSUFFICIENT-CREDITS` here."
                        },
                        "status": {
                          "type": "integer",
                          "description": "HTTP status code echoed in the error body."
                        },
                        "required": {
                          "type": "integer",
                          "description": "Credits the clip would cost — equals the estimate for the same parameters."
                        },
                        "available": {
                          "type": "integer",
                          "description": "Credits currently available on the account."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Insufficient credits available.",
                  "error": {
                    "code": "INSUFFICIENT-CREDITS",
                    "status": 402,
                    "required": 48,
                    "available": 10
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden — two distinct causes share this status:\n\n1. **No active subscription** (code `SUBSCRIPTION-REQUIRED`, message \"An active subscription is required.\") — checked first by the active-subscription gate, before any other logic. The v2 public API has no free tier.\n2. **Plan-limit failure** (code `REACH-PLAN-STORAGE-LIMIT`) — the subscription is active but the account's storage is full. (Insufficient credits are reported as `402` — see above.)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Error overview."
                    },
                    "error": {
                      "type": "object",
                      "description": "Machine-readable error details.",
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable error code — `SUBSCRIPTION-REQUIRED` (no active subscription) or `REACH-PLAN-STORAGE-LIMIT` (storage full)."
                        },
                        "status": {
                          "type": "integer",
                          "description": "HTTP status code echoed in the error body."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "An active subscription is required.",
                  "error": {
                    "code": "SUBSCRIPTION-REQUIRED",
                    "status": 403
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "operationId": "createTextToVideo",
        "summary": "Create a text-to-video clip",
        "description": "**Step 3 of 4 · Generate.**\n\n💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance — `cost` is the **exact** amount charged (the charge is synchronous, and always equals the estimate endpoint's figure for the same parameters).\n\nGenerates a short AI video clip from a text prompt using the chosen model. Returns `202 Accepted` immediately with the same shape as `GET /text-to-video/{id}` while generation runs in the background.\n\n**Validation happens before the charge.** Modifier values must come from the model's menus, and media modifiers are accepted only when the model supports them — violations are `422`s. Media URLs (`first_frame`, `last_frame`, `image`, `video`) are downloaded and validated (type, size, frame constraints) **before** any credits are charged: an unreachable URL, a disallowed type, or an oversized file fails the request with `422` and **nothing is charged**. Each `image[]` / `video[]` entry must be a non-null https URL string — a JSON `null` element is rejected with `422` on the offending key (e.g. `modifiers.image.0`).\n\n**Requires an active subscription.** Unsubscribed accounts are rejected with `403` `SUBSCRIPTION-REQUIRED` before any credit check; the public API has no free tier. Subscribed accounts with an insufficient balance get `402` `INSUFFICIENT-CREDITS` carrying the `required` and `available` figures. If generation later fails, the charge is refunded automatically.\n\n**To track progress:** poll `GET /text-to-video/{id}` with the **`id` from this response**, every 5–10 seconds. The playable file appears at `data.asset.url` when `data.asset.status` is `success`.\n\n→ **Next:** Step 4 — track progress by polling `GET /text-to-video/{id}` with the `id` from this response."
      }
    },
    "/text-to-video/{id}": {
      "get": {
        "tags": [
          "Text to Video"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Identifier of the text-to-video clip — the `id` field from the create response.",
            "schema": {
              "type": "integer"
            },
            "example": 42
          }
        ],
        "responses": {
          "200": {
            "description": "The clip with its current generation state.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message",
                    "status",
                    "data"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "description": "A text-to-video clip.",
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Unique numeric identifier of the clip. Use it to poll `GET /text-to-video/{id}`."
                        },
                        "title": {
                          "type": "string",
                          "description": "Title of the clip. Defaults to \"Untitled video <date time>\" when not supplied at creation."
                        },
                        "type": {
                          "type": "string",
                          "description": "Video type discriminator — always `text_to_video` for this resource."
                        },
                        "status": {
                          "type": "string",
                          "enum": [
                            "rendering",
                            "completed",
                            "failed"
                          ],
                          "description": "Clip-level lifecycle status: `rendering` while the clip is generated and composed, `completed` when done, `failed` when generation failed. The deliverable itself is tracked on `asset.status`."
                        },
                        "asset": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "description": "Generation state of the underlying clip asset — the deliverable lives here. Null only when no generation is attached to the record.",
                          "properties": {
                            "status": {
                              "type": "string",
                              "enum": [
                                "draft",
                                "processing",
                                "success",
                                "failed"
                              ],
                              "description": "Asset lifecycle status: `draft` (queued, generation not started), `processing` (generating), `success` (file ready at `url`), or `failed` (reason in `failure`; the charge is refunded automatically)."
                            },
                            "url": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "description": "Playable URL of the generated clip (mp4). Populated once `status` is `success`; null while queued/processing and on failure."
                            },
                            "failure": {
                              "type": [
                                "string",
                                "null"
                              ],
                              "description": "Human-readable reason the generation failed. Non-null only when `status` is `failed`."
                            }
                          }
                        },
                        "created_at": {
                          "type": "string",
                          "description": "ISO-8601 timestamp when the clip was created."
                        },
                        "updated_at": {
                          "type": "string",
                          "description": "ISO-8601 timestamp when the clip was last updated."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 42,
                    "title": "Phone hero shot",
                    "type": "text_to_video",
                    "status": "completed",
                    "asset": {
                      "status": "success",
                      "url": "https://cdn.syllaby.dev/clips/42/clip.mp4",
                      "failure": null
                    },
                    "created_at": "2026-01-01T12:00:00.000Z",
                    "updated_at": "2026-01-01T12:00:00.000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "description": "Not found — returned uniformly when the id does not exist, belongs to another account, is not a text-to-video clip, or is not numeric. The response never distinguishes those cases.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "message"
                  ],
                  "properties": {
                    "message": {
                      "type": "string",
                      "description": "Error overview."
                    },
                    "error": {
                      "type": "object",
                      "description": "Machine-readable error details.",
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable error code — `GEN-NOT-FOUND` here."
                        },
                        "status": {
                          "type": "integer",
                          "description": "HTTP status code echoed in the error body."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "message": "Resource Not Found",
                  "error": {
                    "code": "GEN-NOT-FOUND",
                    "status": 404
                  }
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "operationId": "getTextToVideo",
        "summary": "Get a text-to-video clip",
        "description": "**Step 4 of 4 · Track progress.**\n\nReturns a single text-to-video clip you own — this is the polling endpoint. Use the **`id` from the create response**; polling every 5–10 seconds is plenty.\n\n**Where to look:** the deliverable lives on `data.asset`, and its `status` is the field to branch on — match these **exact strings**:\n- `draft` — just created, generation not started yet (the create call's `202` response carries this).\n- `processing` — the provider is generating the clip.\n- `success` — terminal. Then, and only then, `data.asset.url` is non-null and playable.\n- `failed` — terminal. `data.asset.failure` carries the reason, and the charge has been refunded automatically.\n\nThe clip-level `status` tracks the overall video record (`rendering` → `completed`/`failed`).\n\nResponds with a uniform `404` when the id does not exist, belongs to another account, is not a text-to-video clip, or is not numeric — the response never distinguishes those cases.\n\n→ **Done** when `data.asset.status` is `success` — the clip is at `data.asset.url`. On `failed`, the charge is auto-refunded; adjust and create again."
      }
    },
    "/b-roll": {
      "post": {
        "operationId": "createBrollVideo",
        "tags": [
          "B-roll"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBrollRequest"
              },
              "example": {
                "title": "My B-roll video"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Create a B-roll video",
        "description": "Creates a new B-roll video in draft state (its `type` is fixed at `b-roll` and cannot be changed later). Returns the created video with its render state embedded under `data.video`. Keep the returned `id` — it identifies the video in every follow-up call, including polling `GET /b-roll/{id}`.\n\n**Requires an active subscription** — the public API has no free tier."
      }
    },
    "/b-roll/{faceless}/scripts": {
      "put": {
        "operationId": "generateBrollScript",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateFacelessScriptRequest"
              },
              "example": {
                "topic": "Morning routines for better focus",
                "tone": "professional",
                "style": "educational",
                "language": "english",
                "duration": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Generate a B-roll script",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nGenerates a narration script for the B-roll video from a topic, tone, style, language, and target duration, and stores it on the video. This is a `PUT` — each call regenerates and overwrites the previous script."
      }
    },
    "/b-roll/{id}": {
      "get": {
        "operationId": "getBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": "https://cdn.syllaby.dev/videos/10/final.mp4",
                      "status": "completed",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": "2026-01-01T12:00:00.000000Z",
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Get a B-roll video",
        "description": "Returns a single B-roll video you own. The render state is embedded under `data.video`: `url` (null until the render completes), `status`, and `failure`. Responds with `404` when the id does not exist or belongs to another account. Pass the faceless `id` (not `video_id`)."
      },
      "patch": {
        "operationId": "updateBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFacelessRequest"
              },
              "example": {
                "voice_id": 12,
                "genre_id": 3,
                "script": "Three habits that quietly improve your focus.",
                "transition": "fade",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Update a B-roll video",
        "description": "Updates the B-roll video's configuration (script, voice, genre, captions, transitions, and more). Only the fields you send are changed. The video must not be busy (rendering or syncing)."
      }
    },
    "/b-roll/{faceless}/estimate": {
      "get": {
        "operationId": "estimateBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "The required value for the resource."
                        },
                        "available": {
                          "type": "string",
                          "description": "The available value for the resource."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "The sufficient value for the resource."
                        }
                      },
                      "required": [
                        "required",
                        "available",
                        "sufficient"
                      ],
                      "description": "Estimated required credits, available balance, and whether the balance is sufficient."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 30,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Estimate B-roll render credits",
        "description": "Estimates the credits required to render the B-roll video and compares them against your available balance. The video must already have a script and a voice configured."
      }
    },
    "/b-roll/{faceless}/render": {
      "post": {
        "operationId": "renderBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Render a B-roll video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nStarts rendering the B-roll video asynchronously and returns HTTP 202. Track progress by polling `GET /b-roll/{id}` and reading `data.video.status` (`rendering` → `completed`/`failed`); the playable file appears at `data.video.url` on completion. Common preconditions checked before any charge: a script and voice must be set, credits must be sufficient (`402`), and the video must not be busy.\n\n**Fields omitted from the render body are filled from the video's saved configuration** — a value set at creation, via `PATCH /b-roll/{id}`, or on a previous render is reused automatically, and an explicit body value always wins.",
        "requestBody": {
          "description": "Render configuration for the faceless video. Every field is optional: `script`, `duration`, and `aspect_ratio` are auto-filled from the saved draft when omitted (configure it first via `PUT /faceless/{faceless}/scripts` and `PATCH /faceless/{faceless}`), so a fully-configured video can be rendered with an empty body. A `422` is only returned when a required value is missing from both the body and the draft.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "script": {
                    "type": "string",
                    "description": "Narration script text for the video. Optional — falls back to the draft's stored script when omitted."
                  },
                  "duration": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Target video length in seconds (a positive integer). Optional — falls back to the draft's estimated duration when omitted. Not restricted to the script-generation presets (those fixed values apply only to PUT /faceless/{faceless}/scripts)."
                  },
                  "aspect_ratio": {
                    "type": "string",
                    "description": "Output aspect ratio. Optional — falls back to the draft's stored aspect ratio when omitted. Allowed values are listed under faceless options (aspect_ratios).",
                    "example": "9:16"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Optional title for the video."
                  },
                  "voice_id": {
                    "type": "integer",
                    "description": "Identifier of the narration voice (see faceless options)."
                  },
                  "background_id": {
                    "type": "integer",
                    "description": "Identifier of the background asset (see faceless options)."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "b-roll",
                      "url-based",
                      "ai-visuals",
                      "ai-clips"
                    ],
                    "description": "Faceless video type — controls how the visuals are sourced (stock b-roll, a source URL, AI-generated images, or AI-generated clips)."
                  },
                  "genre_id": {
                    "type": "integer",
                    "description": "Identifier of the genre/style that drives the image-prompt look. REQUIRED for image-based renders (`type` of `ai-visuals` or `ai-clips`); optional for `b-roll` / `url-based` renders that don't use a genre. Allowed values are listed under faceless options (genres).",
                    "example": 3
                  },
                  "character_id": {
                    "type": "integer",
                    "description": "Identifier of the consistent character (see faceless options)."
                  },
                  "image_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-image engine (see faceless options)."
                  },
                  "clip_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
                  },
                  "transition": {
                    "type": "string",
                    "description": "Transition slug applied between scenes. Allowed values are listed under faceless options (transitions)."
                  },
                  "animation": {
                    "type": "string",
                    "description": "Per-image motion effect slug. Allowed values are listed under faceless options (animations)."
                  },
                  "overlay": {
                    "type": "string",
                    "description": "Overlay style slug applied over the video. Allowed values are listed under faceless options (overlays). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                  },
                  "sfx": {
                    "type": "string",
                    "description": "Sound-effect slug applied to the video. Allowed values are listed under faceless options (sfx)."
                  },
                  "ai_labels": {
                    "type": "boolean",
                    "description": "Whether AI-content disclosure labels are applied on publish."
                  },
                  "custom_description": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Custom caption/description applied to published posts."
                  },
                  "destination_id": {
                    "type": "integer",
                    "description": "Identifier of the destination folder/resource to file the video under."
                  },
                  "captions": {
                    "type": "object",
                    "description": "Caption styling. Only `font_family`, `font_color`, `font_url`, `position`, and `effect` are honored; any other caption keys are ignored.",
                    "properties": {
                      "font_family": {
                        "type": "string",
                        "description": "Caption font family slug (see faceless options)."
                      },
                      "font_color": {
                        "type": "string",
                        "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
                      },
                      "font_url": {
                        "type": "string",
                        "description": "URL of a custom font file to use for captions."
                      },
                      "position": {
                        "type": "string",
                        "description": "On-screen caption position slug. Allowed values are listed under faceless options (caption_positions)."
                      },
                      "effect": {
                        "type": "string",
                        "description": "Caption effect slug applied to on-screen text. Allowed values are listed under faceless options (caption_effects). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                      }
                    }
                  },
                  "watermark": {
                    "type": "object",
                    "description": "Watermark image and placement. Provide exactly one source — `id`, `url`, or `file` (mutually exclusive).",
                    "properties": {
                      "id": {
                        "type": "integer",
                        "description": "Identifier of a watermark asset you own. Mutually exclusive with `url` and `file`."
                      },
                      "url": {
                        "type": "string",
                        "description": "Remote URL of the watermark image. Mutually exclusive with `id` and `file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded watermark image file (jpg, jpeg, png, webp; max 5 MB). Mutually exclusive with `id` and `url`."
                      },
                      "position": {
                        "type": "string",
                        "description": "Watermark placement slug. Allowed values are listed under faceless options (watermark_positions)."
                      },
                      "opacity": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Watermark opacity as a percentage (0–100)."
                      }
                    }
                  },
                  "music_id": {
                    "type": "integer",
                    "description": "Identifier of a background music track (media id). Mutually exclusive with `music.url` and `music.file`."
                  },
                  "music": {
                    "type": "object",
                    "description": "Background music source. Provide exactly one of `url` or `file`, and only when `music_id` is omitted (all three are mutually exclusive).",
                    "properties": {
                      "url": {
                        "type": "string",
                        "description": "Remote URL of a music track. Mutually exclusive with `music_id` and `music.file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded music file (mp3, wav, aac, m4a, ogg; max 20 MB). Mutually exclusive with `music_id` and `music.url`."
                      }
                    }
                  },
                  "volume": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "description": "Background-music volume level. Required when any music source is set."
                  },
                  "publications": {
                    "type": "array",
                    "description": "Social posts to schedule for the rendered video.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "channel_id": {
                          "type": "integer",
                          "description": "Identifier of the connected social channel to publish to."
                        },
                        "scheduled_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Future timestamp to publish the post, or null to publish immediately."
                        }
                      }
                    }
                  },
                  "assets": {
                    "type": "array",
                    "description": "Explicit ordered media assets to compose the video from. Orders must start at 0 and be consecutive with no gaps.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "order"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Identifier of the media asset."
                        },
                        "order": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "Zero-based position of the asset in the sequence."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "script": "Three small habits that quietly improve your focus every day.",
                "duration": 60,
                "aspect_ratio": "9:16",
                "type": "ai-visuals",
                "title": "Focus habits",
                "voice_id": 12,
                "genre_id": 3,
                "image_engine_id": 1,
                "clip_engine_id": 2,
                "transition": "fade",
                "animation": "pan-in",
                "overlay": "none",
                "sfx": "whoosh",
                "volume": "medium",
                "music_id": 8,
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                },
                "publications": [
                  {
                    "channel_id": 5,
                    "scheduled_at": "2025-02-01T18:30:00Z"
                  }
                ],
                "assets": [
                  {
                    "id": 101,
                    "order": 0
                  },
                  {
                    "id": 102,
                    "order": 1
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/b-roll/{faceless}/retry": {
      "post": {
        "operationId": "retryBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 1,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Retry a B-roll render",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRe-attempts rendering for a B-roll video whose embedded video previously failed (`data.video.status` is `failed`). Returns HTTP 202; track it the same way as render. Only failed renders can be retried."
      }
    },
    "/b-roll/{faceless}/export": {
      "post": {
        "operationId": "exportBrollVideo",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportFacelessRequest"
              },
              "example": {
                "transition": "fade",
                "volume": "medium",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "b-roll",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 50,
                      "remaining": 830
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Export a B-roll video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRebuilds the rendered B-roll video with the supplied styling (captions, watermark, music, transitions) and queues an export. Returns HTTP 202. The video must already be rendered and not currently busy."
      }
    },
    "/b-roll/{faceless}/assets": {
      "get": {
        "operationId": "listBrollAssets",
        "tags": [
          "B-roll"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "index",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Zero-based scene position; returns only the asset at that position.",
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                      },
                      "description": "The B-roll video's ordered media assets."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "user_id": 1,
                      "type": "faceless_background",
                      "status": "success",
                      "order": 0,
                      "media": [
                        {
                          "id": 5,
                          "name": "scene-1",
                          "file_name": "scene-1.png",
                          "mime_type": "image/png",
                          "extension": "png",
                          "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                        }
                      ],
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "List B-roll assets",
        "description": "Lists the media assets (images, clips) that make up the B-roll video, ordered by scene. Assets are produced during rendering — expect an empty list until the video has been rendered at least once."
      }
    },
    "/ai-visuals": {
      "post": {
        "operationId": "createAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAiVisualsRequest"
              },
              "example": {
                "title": "My AI-Visuals video"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Create a AI-Visuals video",
        "description": "Creates a new AI-Visuals video in draft state (its `type` is fixed at `ai-visuals` and cannot be changed later). Returns the created video with its render state embedded under `data.video`. Keep the returned `id` — it identifies the video in every follow-up call, including polling `GET /ai-visuals/{id}`.\n\n**Requires an active subscription** — the public API has no free tier."
      }
    },
    "/ai-visuals/{faceless}/scripts": {
      "put": {
        "operationId": "generateAiVisualsScript",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateFacelessScriptRequest"
              },
              "example": {
                "topic": "Morning routines for better focus",
                "tone": "professional",
                "style": "educational",
                "language": "english",
                "duration": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Generate a AI-Visuals script",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nGenerates a narration script for the AI-Visuals video from a topic, tone, style, language, and target duration, and stores it on the video. This is a `PUT` — each call regenerates and overwrites the previous script."
      }
    },
    "/ai-visuals/{id}": {
      "get": {
        "operationId": "getAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": "https://cdn.syllaby.dev/videos/10/final.mp4",
                      "status": "completed",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": "2026-01-01T12:00:00.000000Z",
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Get a AI-Visuals video",
        "description": "Returns a single AI-Visuals video you own. The render state is embedded under `data.video`: `url` (null until the render completes), `status`, and `failure`. Responds with `404` when the id does not exist or belongs to another account. Pass the faceless `id` (not `video_id`)."
      },
      "patch": {
        "operationId": "updateAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFacelessRequest"
              },
              "example": {
                "voice_id": 12,
                "genre_id": 3,
                "script": "Three habits that quietly improve your focus.",
                "transition": "fade",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Update a AI-Visuals video",
        "description": "Updates the AI-Visuals video's configuration (script, voice, genre, captions, transitions, and more). Only the fields you send are changed. The video must not be busy (rendering or syncing)."
      }
    },
    "/ai-visuals/{faceless}/estimate": {
      "get": {
        "operationId": "estimateAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "The required value for the resource."
                        },
                        "available": {
                          "type": "string",
                          "description": "The available value for the resource."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "The sufficient value for the resource."
                        }
                      },
                      "required": [
                        "required",
                        "available",
                        "sufficient"
                      ],
                      "description": "Estimated required credits, available balance, and whether the balance is sufficient."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 30,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Estimate AI-Visuals render credits",
        "description": "Estimates the credits required to render the AI-Visuals video and compares them against your available balance. The video must already have a script and a voice configured."
      }
    },
    "/ai-visuals/{faceless}/render": {
      "post": {
        "operationId": "renderAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Render a AI-Visuals video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nStarts rendering the AI-Visuals video asynchronously and returns HTTP 202. Track progress by polling `GET /ai-visuals/{id}` and reading `data.video.status` (`rendering` → `completed`/`failed`); the playable file appears at `data.video.url` on completion. Common preconditions checked before any charge: a script and voice must be set, credits must be sufficient (`402`), and the video must not be busy.\n\n**Fields omitted from the render body are filled from the video's saved configuration** — a value set at creation, via `PATCH /ai-visuals/{id}`, or on a previous render is reused automatically, and an explicit body value always wins. For `ai-visuals`, `genre_id` and `image_engine_id` are **required** in that combined sense: each must resolve from the render body or the saved draft, and a render that resolves neither returns `422` on that key. Browse valid ids at `GET /faceless/options`.",
        "requestBody": {
          "description": "Render configuration for the faceless video. Every field is optional: `script`, `duration`, and `aspect_ratio` are auto-filled from the saved draft when omitted (configure it first via `PUT /faceless/{faceless}/scripts` and `PATCH /faceless/{faceless}`), so a fully-configured video can be rendered with an empty body. A `422` is only returned when a required value is missing from both the body and the draft.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "script": {
                    "type": "string",
                    "description": "Narration script text for the video. Optional — falls back to the draft's stored script when omitted."
                  },
                  "duration": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Target video length in seconds (a positive integer). Optional — falls back to the draft's estimated duration when omitted. Not restricted to the script-generation presets (those fixed values apply only to PUT /faceless/{faceless}/scripts)."
                  },
                  "aspect_ratio": {
                    "type": "string",
                    "description": "Output aspect ratio. Optional — falls back to the draft's stored aspect ratio when omitted. Allowed values are listed under faceless options (aspect_ratios).",
                    "example": "9:16"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Optional title for the video."
                  },
                  "voice_id": {
                    "type": "integer",
                    "description": "Identifier of the narration voice (see faceless options)."
                  },
                  "background_id": {
                    "type": "integer",
                    "description": "Identifier of the background asset (see faceless options)."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "b-roll",
                      "url-based",
                      "ai-visuals",
                      "ai-clips"
                    ],
                    "description": "Faceless video type — controls how the visuals are sourced (stock b-roll, a source URL, AI-generated images, or AI-generated clips)."
                  },
                  "genre_id": {
                    "type": "integer",
                    "description": "Identifier of the genre/style that drives the image-prompt look. REQUIRED for image-based renders (`type` of `ai-visuals` or `ai-clips`); optional for `b-roll` / `url-based` renders that don't use a genre. Allowed values are listed under faceless options (genres).",
                    "example": 3
                  },
                  "character_id": {
                    "type": "integer",
                    "description": "Identifier of the consistent character (see faceless options)."
                  },
                  "image_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-image engine (see faceless options)."
                  },
                  "clip_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
                  },
                  "transition": {
                    "type": "string",
                    "description": "Transition slug applied between scenes. Allowed values are listed under faceless options (transitions)."
                  },
                  "animation": {
                    "type": "string",
                    "description": "Per-image motion effect slug. Allowed values are listed under faceless options (animations)."
                  },
                  "overlay": {
                    "type": "string",
                    "description": "Overlay style slug applied over the video. Allowed values are listed under faceless options (overlays). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                  },
                  "sfx": {
                    "type": "string",
                    "description": "Sound-effect slug applied to the video. Allowed values are listed under faceless options (sfx)."
                  },
                  "ai_labels": {
                    "type": "boolean",
                    "description": "Whether AI-content disclosure labels are applied on publish."
                  },
                  "custom_description": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Custom caption/description applied to published posts."
                  },
                  "destination_id": {
                    "type": "integer",
                    "description": "Identifier of the destination folder/resource to file the video under."
                  },
                  "captions": {
                    "type": "object",
                    "description": "Caption styling. Only `font_family`, `font_color`, `font_url`, `position`, and `effect` are honored; any other caption keys are ignored.",
                    "properties": {
                      "font_family": {
                        "type": "string",
                        "description": "Caption font family slug (see faceless options)."
                      },
                      "font_color": {
                        "type": "string",
                        "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
                      },
                      "font_url": {
                        "type": "string",
                        "description": "URL of a custom font file to use for captions."
                      },
                      "position": {
                        "type": "string",
                        "description": "On-screen caption position slug. Allowed values are listed under faceless options (caption_positions)."
                      },
                      "effect": {
                        "type": "string",
                        "description": "Caption effect slug applied to on-screen text. Allowed values are listed under faceless options (caption_effects). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                      }
                    }
                  },
                  "watermark": {
                    "type": "object",
                    "description": "Watermark image and placement. Provide exactly one source — `id`, `url`, or `file` (mutually exclusive).",
                    "properties": {
                      "id": {
                        "type": "integer",
                        "description": "Identifier of a watermark asset you own. Mutually exclusive with `url` and `file`."
                      },
                      "url": {
                        "type": "string",
                        "description": "Remote URL of the watermark image. Mutually exclusive with `id` and `file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded watermark image file (jpg, jpeg, png, webp; max 5 MB). Mutually exclusive with `id` and `url`."
                      },
                      "position": {
                        "type": "string",
                        "description": "Watermark placement slug. Allowed values are listed under faceless options (watermark_positions)."
                      },
                      "opacity": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Watermark opacity as a percentage (0–100)."
                      }
                    }
                  },
                  "music_id": {
                    "type": "integer",
                    "description": "Identifier of a background music track (media id). Mutually exclusive with `music.url` and `music.file`."
                  },
                  "music": {
                    "type": "object",
                    "description": "Background music source. Provide exactly one of `url` or `file`, and only when `music_id` is omitted (all three are mutually exclusive).",
                    "properties": {
                      "url": {
                        "type": "string",
                        "description": "Remote URL of a music track. Mutually exclusive with `music_id` and `music.file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded music file (mp3, wav, aac, m4a, ogg; max 20 MB). Mutually exclusive with `music_id` and `music.url`."
                      }
                    }
                  },
                  "volume": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "description": "Background-music volume level. Required when any music source is set."
                  },
                  "publications": {
                    "type": "array",
                    "description": "Social posts to schedule for the rendered video.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "channel_id": {
                          "type": "integer",
                          "description": "Identifier of the connected social channel to publish to."
                        },
                        "scheduled_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Future timestamp to publish the post, or null to publish immediately."
                        }
                      }
                    }
                  },
                  "assets": {
                    "type": "array",
                    "description": "Explicit ordered media assets to compose the video from. Orders must start at 0 and be consecutive with no gaps.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "order"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Identifier of the media asset."
                        },
                        "order": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "Zero-based position of the asset in the sequence."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "script": "Three small habits that quietly improve your focus every day.",
                "duration": 60,
                "aspect_ratio": "9:16",
                "type": "ai-visuals",
                "title": "Focus habits",
                "voice_id": 12,
                "genre_id": 3,
                "image_engine_id": 1,
                "clip_engine_id": 2,
                "transition": "fade",
                "animation": "pan-in",
                "overlay": "none",
                "sfx": "whoosh",
                "volume": "medium",
                "music_id": 8,
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                },
                "publications": [
                  {
                    "channel_id": 5,
                    "scheduled_at": "2025-02-01T18:30:00Z"
                  }
                ],
                "assets": [
                  {
                    "id": 101,
                    "order": 0
                  },
                  {
                    "id": 102,
                    "order": 1
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/ai-visuals/{faceless}/retry": {
      "post": {
        "operationId": "retryAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 1,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Retry a AI-Visuals render",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRe-attempts rendering for a AI-Visuals video whose embedded video previously failed (`data.video.status` is `failed`). Returns HTTP 202; track it the same way as render. Only failed renders can be retried."
      }
    },
    "/ai-visuals/{faceless}/export": {
      "post": {
        "operationId": "exportAiVisualsVideo",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportFacelessRequest"
              },
              "example": {
                "transition": "fade",
                "volume": "medium",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "ai-visuals",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 50,
                      "remaining": 830
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Export a AI-Visuals video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRebuilds the rendered AI-Visuals video with the supplied styling (captions, watermark, music, transitions) and queues an export. Returns HTTP 202. The video must already be rendered and not currently busy."
      }
    },
    "/ai-visuals/{faceless}/assets": {
      "get": {
        "operationId": "listAiVisualsAssets",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "index",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Zero-based scene position; returns only the asset at that position.",
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                      },
                      "description": "The AI-Visuals video's ordered media assets."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "user_id": 1,
                      "type": "faceless_background",
                      "status": "success",
                      "order": 0,
                      "media": [
                        {
                          "id": 5,
                          "name": "scene-1",
                          "file_name": "scene-1.png",
                          "mime_type": "image/png",
                          "extension": "png",
                          "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                        }
                      ],
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "List AI-Visuals assets",
        "description": "Lists the media assets (images, clips) that make up the AI-Visuals video, ordered by scene. Assets are produced during rendering — expect an empty list until the video has been rendered at least once."
      }
    },
    "/ai-visuals/{faceless}/assets/upload": {
      "post": {
        "operationId": "uploadAiVisualsAsset",
        "description": "Attaches a media asset to the AI-Visuals video. Provide EITHER a multipart `file` upload OR a remote `url` to transload — exactly one. Accepts image and video files, subject to your storage quota.",
        "summary": "Upload an AI-Visuals asset",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadFacelessAssetRequest"
              },
              "example": {
                "url": "https://cdn.example.com/media/clip.mp4"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/UploadFacelessAssetRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "type": "faceless_background",
                    "status": "success",
                    "order": 0,
                    "media": [
                      {
                        "id": 5,
                        "name": "scene-1",
                        "file_name": "scene-1.png",
                        "mime_type": "image/png",
                        "extension": "png",
                        "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/ai-visuals/{faceless}/assets/{asset}/regenerate": {
      "post": {
        "operationId": "regenerateAiVisualsAsset",
        "summary": "Regenerate an AI-Visuals asset",
        "tags": [
          "AI-Visuals"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "asset",
            "in": "path",
            "required": true,
            "description": "The asset ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegenerateFacelessAssetRequest"
              },
              "example": {
                "prompt": "A neon city skyline at dusk, cinematic lighting."
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "type": "faceless_background",
                    "status": "success",
                    "order": 0,
                    "media": [
                      {
                        "id": 5,
                        "name": "scene-1",
                        "file_name": "scene-1.png",
                        "mime_type": "image/png",
                        "extension": "png",
                        "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 1,
                      "remaining": 874
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "💳 Charges credits beyond the engine's free-generation allowance. The response `meta.credits` shows the cost and your remaining balance.\n\nRegenerates a single AI-Visuals scene image. The engine and image-generation settings come from the stored video; you may optionally override the prompt."
      }
    },
    "/url-to-video": {
      "post": {
        "operationId": "createUrlToVideo",
        "tags": [
          "URL-to-Video"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUrlToVideoRequest"
              },
              "example": {
                "title": "My URL-to-Video video"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Create a URL-to-Video video",
        "description": "Creates a new URL-to-Video video in draft state (its `type` is fixed at `url-based` and cannot be changed later). Returns the created video with its render state embedded under `data.video`. Keep the returned `id` — it identifies the video in every follow-up call, including polling `GET /url-to-video/{id}`.\n\n**Requires an active subscription** — the public API has no free tier."
      }
    },
    "/url-to-video/{faceless}/scrape-images": {
      "post": {
        "operationId": "scrapeUrlToVideoImages",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScrapeImagesRequest"
              },
              "example": {
                "url": "https://www.amazon.com/dp/B0CXYZ1234"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "assets": [
                      {
                        "id": 1,
                        "user_id": 1,
                        "type": "faceless_background",
                        "status": "success",
                        "order": 0,
                        "media": [
                          {
                            "id": 5,
                            "name": "scene-1",
                            "file_name": "scene-1.png",
                            "mime_type": "image/png",
                            "extension": "png",
                            "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                          }
                        ],
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Scrape images from a URL",
        "description": "**Free — no credits charged.** Extracts images from the supplied web page URL and attaches them to the URL-to-Video as ordered assets. You must call this at least once before rendering a URL-to-Video. Social-media URLs are rejected with `422`."
      }
    },
    "/url-to-video/{faceless}/scrape-script": {
      "post": {
        "operationId": "scrapeUrlToVideoScript",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ScrapeScriptRequest"
              },
              "example": {
                "url": "https://www.amazon.com/dp/B0CXYZ1234",
                "duration": 60,
                "style": "educational",
                "tone": "friendly",
                "language": "english"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "This product helps you focus throughout the day.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Scrape a script from a URL",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nGenerates a narration script directly from the content of the supplied web page URL and stores it on the video. Social-media URLs are rejected with `422`."
      }
    },
    "/url-to-video/{faceless}/scripts": {
      "put": {
        "operationId": "generateUrlToVideoScript",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateFacelessScriptRequest"
              },
              "example": {
                "topic": "Morning routines for better focus",
                "tone": "professional",
                "style": "educational",
                "language": "english",
                "duration": 60
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "draft",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 5,
                      "remaining": 875
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Generate a URL-to-Video script",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nGenerates a narration script for the URL-to-Video video from a topic, tone, style, language, and target duration, and stores it on the video. This is a `PUT` — each call regenerates and overwrites the previous script."
      }
    },
    "/url-to-video/{id}": {
      "get": {
        "operationId": "getUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": "https://cdn.syllaby.dev/videos/10/final.mp4",
                      "status": "completed",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": "2026-01-01T12:00:00.000000Z",
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Get a URL-to-Video video",
        "description": "Returns a single URL-to-Video video you own. The render state is embedded under `data.video`: `url` (null until the render completes), `status`, and `failure`. Responds with `404` when the id does not exist or belongs to another account. Pass the faceless `id` (not `video_id`)."
      },
      "patch": {
        "operationId": "updateUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateFacelessRequest"
              },
              "example": {
                "voice_id": 12,
                "genre_id": 3,
                "script": "Three habits that quietly improve your focus.",
                "transition": "fade",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Update a URL-to-Video video",
        "description": "Updates the URL-to-Video video's configuration (script, voice, genre, captions, transitions, and more). Only the fields you send are changed. The video must not be busy (rendering or syncing)."
      }
    },
    "/url-to-video/{faceless}/estimate": {
      "get": {
        "operationId": "estimateUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "The required value for the resource."
                        },
                        "available": {
                          "type": "string",
                          "description": "The available value for the resource."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "The sufficient value for the resource."
                        }
                      },
                      "required": [
                        "required",
                        "available",
                        "sufficient"
                      ],
                      "description": "Estimated required credits, available balance, and whether the balance is sufficient."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 30,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Estimate URL-to-Video render credits",
        "description": "Estimates the credits required to render the URL-to-Video video and compares them against your available balance. The video must already have a script and a voice configured."
      }
    },
    "/url-to-video/{faceless}/render": {
      "post": {
        "operationId": "renderUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Render a URL-to-Video video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nStarts rendering the URL-to-Video video asynchronously and returns HTTP 202. Track progress by polling `GET /url-to-video/{id}` and reading `data.video.status` (`rendering` → `completed`/`failed`); the playable file appears at `data.video.url` on completion. Common preconditions checked before any charge: a script and voice must be set, credits must be sufficient (`402`), and the video must not be busy.\n\n**Fields omitted from the render body are filled from the video's saved configuration** — a value set at creation, via `PATCH /url-to-video/{id}`, or on a previous render is reused automatically, and an explicit body value always wins.",
        "requestBody": {
          "description": "Render configuration for the faceless video. Every field is optional: `script`, `duration`, and `aspect_ratio` are auto-filled from the saved draft when omitted (configure it first via `PUT /faceless/{faceless}/scripts` and `PATCH /faceless/{faceless}`), so a fully-configured video can be rendered with an empty body. A `422` is only returned when a required value is missing from both the body and the draft.",
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "script": {
                    "type": "string",
                    "description": "Narration script text for the video. Optional — falls back to the draft's stored script when omitted."
                  },
                  "duration": {
                    "type": "integer",
                    "minimum": 1,
                    "description": "Target video length in seconds (a positive integer). Optional — falls back to the draft's estimated duration when omitted. Not restricted to the script-generation presets (those fixed values apply only to PUT /faceless/{faceless}/scripts)."
                  },
                  "aspect_ratio": {
                    "type": "string",
                    "description": "Output aspect ratio. Optional — falls back to the draft's stored aspect ratio when omitted. Allowed values are listed under faceless options (aspect_ratios).",
                    "example": "9:16"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Optional title for the video."
                  },
                  "voice_id": {
                    "type": "integer",
                    "description": "Identifier of the narration voice (see faceless options)."
                  },
                  "background_id": {
                    "type": "integer",
                    "description": "Identifier of the background asset (see faceless options)."
                  },
                  "type": {
                    "type": "string",
                    "enum": [
                      "b-roll",
                      "url-based",
                      "ai-visuals",
                      "ai-clips"
                    ],
                    "description": "Faceless video type — controls how the visuals are sourced (stock b-roll, a source URL, AI-generated images, or AI-generated clips)."
                  },
                  "genre_id": {
                    "type": "integer",
                    "description": "Identifier of the genre/style that drives the image-prompt look. REQUIRED for image-based renders (`type` of `ai-visuals` or `ai-clips`); optional for `b-roll` / `url-based` renders that don't use a genre. Allowed values are listed under faceless options (genres).",
                    "example": 3
                  },
                  "character_id": {
                    "type": "integer",
                    "description": "Identifier of the consistent character (see faceless options)."
                  },
                  "image_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-image engine (see faceless options)."
                  },
                  "clip_engine_id": {
                    "type": "integer",
                    "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
                  },
                  "transition": {
                    "type": "string",
                    "description": "Transition slug applied between scenes. Allowed values are listed under faceless options (transitions)."
                  },
                  "animation": {
                    "type": "string",
                    "description": "Per-image motion effect slug. Allowed values are listed under faceless options (animations)."
                  },
                  "overlay": {
                    "type": "string",
                    "description": "Overlay style slug applied over the video. Allowed values are listed under faceless options (overlays). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                  },
                  "sfx": {
                    "type": "string",
                    "description": "Sound-effect slug applied to the video. Allowed values are listed under faceless options (sfx)."
                  },
                  "ai_labels": {
                    "type": "boolean",
                    "description": "Whether AI-content disclosure labels are applied on publish."
                  },
                  "custom_description": {
                    "type": "string",
                    "maxLength": 255,
                    "description": "Custom caption/description applied to published posts."
                  },
                  "destination_id": {
                    "type": "integer",
                    "description": "Identifier of the destination folder/resource to file the video under."
                  },
                  "captions": {
                    "type": "object",
                    "description": "Caption styling. Only `font_family`, `font_color`, `font_url`, `position`, and `effect` are honored; any other caption keys are ignored.",
                    "properties": {
                      "font_family": {
                        "type": "string",
                        "description": "Caption font family slug (see faceless options)."
                      },
                      "font_color": {
                        "type": "string",
                        "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
                      },
                      "font_url": {
                        "type": "string",
                        "description": "URL of a custom font file to use for captions."
                      },
                      "position": {
                        "type": "string",
                        "description": "On-screen caption position slug. Allowed values are listed under faceless options (caption_positions)."
                      },
                      "effect": {
                        "type": "string",
                        "description": "Caption effect slug applied to on-screen text. Allowed values are listed under faceless options (caption_effects). Render-body-only: set it here (or on export) — `PATCH /faceless/{faceless}` silently ignores it."
                      }
                    }
                  },
                  "watermark": {
                    "type": "object",
                    "description": "Watermark image and placement. Provide exactly one source — `id`, `url`, or `file` (mutually exclusive).",
                    "properties": {
                      "id": {
                        "type": "integer",
                        "description": "Identifier of a watermark asset you own. Mutually exclusive with `url` and `file`."
                      },
                      "url": {
                        "type": "string",
                        "description": "Remote URL of the watermark image. Mutually exclusive with `id` and `file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded watermark image file (jpg, jpeg, png, webp; max 5 MB). Mutually exclusive with `id` and `url`."
                      },
                      "position": {
                        "type": "string",
                        "description": "Watermark placement slug. Allowed values are listed under faceless options (watermark_positions)."
                      },
                      "opacity": {
                        "type": "integer",
                        "minimum": 0,
                        "maximum": 100,
                        "description": "Watermark opacity as a percentage (0–100)."
                      }
                    }
                  },
                  "music_id": {
                    "type": "integer",
                    "description": "Identifier of a background music track (media id). Mutually exclusive with `music.url` and `music.file`."
                  },
                  "music": {
                    "type": "object",
                    "description": "Background music source. Provide exactly one of `url` or `file`, and only when `music_id` is omitted (all three are mutually exclusive).",
                    "properties": {
                      "url": {
                        "type": "string",
                        "description": "Remote URL of a music track. Mutually exclusive with `music_id` and `music.file`."
                      },
                      "file": {
                        "type": "string",
                        "format": "binary",
                        "description": "Uploaded music file (mp3, wav, aac, m4a, ogg; max 20 MB). Mutually exclusive with `music_id` and `music.url`."
                      }
                    }
                  },
                  "volume": {
                    "type": "string",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "description": "Background-music volume level. Required when any music source is set."
                  },
                  "publications": {
                    "type": "array",
                    "description": "Social posts to schedule for the rendered video.",
                    "items": {
                      "type": "object",
                      "properties": {
                        "channel_id": {
                          "type": "integer",
                          "description": "Identifier of the connected social channel to publish to."
                        },
                        "scheduled_at": {
                          "type": "string",
                          "format": "date-time",
                          "description": "Future timestamp to publish the post, or null to publish immediately."
                        }
                      }
                    }
                  },
                  "assets": {
                    "type": "array",
                    "description": "Explicit ordered media assets to compose the video from. Orders must start at 0 and be consecutive with no gaps.",
                    "items": {
                      "type": "object",
                      "required": [
                        "id",
                        "order"
                      ],
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Identifier of the media asset."
                        },
                        "order": {
                          "type": "integer",
                          "minimum": 0,
                          "description": "Zero-based position of the asset in the sequence."
                        }
                      }
                    }
                  }
                }
              },
              "example": {
                "script": "Three small habits that quietly improve your focus every day.",
                "duration": 60,
                "aspect_ratio": "9:16",
                "type": "ai-visuals",
                "title": "Focus habits",
                "voice_id": 12,
                "genre_id": 3,
                "image_engine_id": 1,
                "clip_engine_id": 2,
                "transition": "fade",
                "animation": "pan-in",
                "overlay": "none",
                "sfx": "whoosh",
                "volume": "medium",
                "music_id": 8,
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                },
                "publications": [
                  {
                    "channel_id": 5,
                    "scheduled_at": "2025-02-01T18:30:00Z"
                  }
                ],
                "assets": [
                  {
                    "id": 101,
                    "order": 0
                  },
                  {
                    "id": 102,
                    "order": 1
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/url-to-video/{faceless}/retry": {
      "post": {
        "operationId": "retryUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature.\n\n**This field is omitted when the credit cost could not be estimated.** Its absence does **not** mean the operation was free — the charge still runs asynchronously. When `cost` is missing, reconcile against `GET /credits/history`, which is the authoritative record of what was charged."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 1,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 120,
                      "remaining": 880
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Retry a URL-to-Video render",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRe-attempts rendering for a URL-to-Video video whose embedded video previously failed (`data.video.status` is `failed`). Returns HTTP 202; track it the same way as render. Only failed renders can be retried."
      }
    },
    "/url-to-video/{faceless}/export": {
      "post": {
        "operationId": "exportUrlToVideoVideo",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ExportFacelessRequest"
              },
              "example": {
                "transition": "fade",
                "volume": "medium",
                "captions": {
                  "font_family": "inter",
                  "font_color": "#FFFFFF",
                  "position": "bottom",
                  "effect": "highlight"
                },
                "watermark": {
                  "id": 42,
                  "position": "bottom-right",
                  "opacity": 80
                }
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/FacelessResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "video_id": 10,
                    "voice_id": 12,
                    "music_id": null,
                    "background_id": null,
                    "estimated_duration": 60,
                    "type": "url-based",
                    "genre": {
                      "id": 3,
                      "name": "Cinematic",
                      "slug": "cinematic",
                      "active": true
                    },
                    "script": "Three habits that quietly improve your focus.",
                    "hash": "abc123",
                    "options": {
                      "aspect_ratio": "9:16"
                    },
                    "is_transcribed": false,
                    "watermark_id": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z",
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Focus habits",
                      "type": "faceless",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  },
                  "meta": {
                    "credits": {
                      "cost": 50,
                      "remaining": 830
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Export a URL-to-Video video",
        "description": "💳 Charges credits. The response `meta.credits` shows the cost and your remaining balance.\n\nRebuilds the rendered URL-to-Video video with the supplied styling (captions, watermark, music, transitions) and queues an export. Returns HTTP 202. The video must already be rendered and not currently busy."
      }
    },
    "/url-to-video/{faceless}/assets": {
      "get": {
        "operationId": "listUrlToVideoAssets",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "index",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Zero-based scene position; returns only the asset at that position.",
            "example": 0
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                      },
                      "description": "The URL-to-Video video's ordered media assets."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "user_id": 1,
                      "type": "faceless_background",
                      "status": "success",
                      "order": 0,
                      "media": [
                        {
                          "id": 5,
                          "name": "scene-1",
                          "file_name": "scene-1.png",
                          "mime_type": "image/png",
                          "extension": "png",
                          "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                        }
                      ],
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "List URL-to-Video assets",
        "description": "Lists the media assets (images, clips) that make up the URL-to-Video video, ordered by scene. Assets are produced during rendering — expect an empty list until the video has been rendered at least once."
      }
    },
    "/url-to-video/{faceless}/assets/upload": {
      "post": {
        "operationId": "uploadUrlToVideoAsset",
        "description": "Attaches a media asset to the URL-to-Video. Provide EITHER a multipart `file` upload OR a remote `url` to transload — exactly one. Accepts image and video files, subject to your storage quota.",
        "summary": "Upload a URL-to-Video asset",
        "tags": [
          "URL-to-Video"
        ],
        "parameters": [
          {
            "name": "faceless",
            "in": "path",
            "required": true,
            "description": "The faceless ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadFacelessAssetRequest"
              },
              "example": {
                "url": "https://cdn.example.com/media/clip.mp4"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/UploadFacelessAssetRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.AssetResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "user_id": 1,
                    "type": "faceless_background",
                    "status": "success",
                    "order": 0,
                    "media": [
                      {
                        "id": 5,
                        "name": "scene-1",
                        "file_name": "scene-1.png",
                        "mime_type": "image/png",
                        "extension": "png",
                        "download_url": "https://cdn.syllaby.dev/assets/scene-1.png"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene": {
      "post": {
        "operationId": "createTextToScene",
        "summary": "Create a storyboard",
        "tags": [
          "Text-to-Scene"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTextToSceneRequest"
              },
              "example": {
                "title": "Deep-sea documentary",
                "mode": "wizard"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "uuid": "sb_abc123",
                    "status": "wizard",
                    "prompt": "A documentary about deep-sea creatures.",
                    "settings": {
                      "audio": true,
                      "aspect_ratio": "16:9",
                      "resolution": "1080p"
                    },
                    "duration": [
                      5,
                      6,
                      5
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Deep-sea documentary",
                      "type": "text_to_scene",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    "scenes": [
                      {
                        "id": 12,
                        "uuid": "scn_abc123",
                        "order": 0,
                        "video_prompt": "Wide shot of a glowing coral reef.",
                        "duration": 5,
                        "status": "draft",
                        "error": null,
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Creates a new Text-to-Scene storyboard in draft state. Choose `mode`: `wizard` (guided prompt-to-storyboard generation) or `manual` (build scenes yourself). Keep the returned `id`/`uuid` for follow-up calls.\n\n**Requires an active subscription.**"
      }
    },
    "/text-to-scene/{id}": {
      "get": {
        "operationId": "getTextToScene",
        "summary": "Get a storyboard",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "uuid": "sb_abc123",
                    "status": "ready",
                    "prompt": "A documentary about deep-sea creatures.",
                    "settings": {
                      "audio": true,
                      "aspect_ratio": "16:9",
                      "resolution": "1080p"
                    },
                    "duration": [
                      5,
                      6,
                      5
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Deep-sea documentary",
                      "type": "text_to_scene",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    "scenes": [
                      {
                        "id": 12,
                        "uuid": "scn_abc123",
                        "order": 0,
                        "video_prompt": "Wide shot of a glowing coral reef.",
                        "duration": 5,
                        "status": "draft",
                        "error": null,
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns a single storyboard you own, including its scenes and embedded render state under `data.video`. Responds with `404` when the id does not exist or belongs to another account."
      },
      "patch": {
        "operationId": "updateTextToScene",
        "summary": "Update a storyboard",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateTextToSceneRequest"
              },
              "example": {
                "settings": {
                  "audio": true,
                  "aspect_ratio": "16:9",
                  "resolution": "1080p"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "uuid": "sb_abc123",
                    "status": "ready",
                    "prompt": "A documentary about deep-sea creatures.",
                    "settings": {
                      "audio": true,
                      "aspect_ratio": "16:9",
                      "resolution": "1080p"
                    },
                    "duration": [
                      5,
                      6,
                      5
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Deep-sea documentary",
                      "type": "text_to_scene",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    "scenes": [
                      {
                        "id": 12,
                        "uuid": "scn_abc123",
                        "order": 0,
                        "video_prompt": "Wide shot of a glowing coral reef.",
                        "duration": 5,
                        "status": "draft",
                        "error": null,
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Updates the storyboard's render settings (audio, aspect ratio, resolution). Only the fields you send are changed.\n\n`aspect_ratio` and `resolution` must come from the storyboard's clip engine's supported options — a value outside them returns `422` (e.g. `The selected aspect ratio is not supported by this engine.`)."
      }
    },
    "/text-to-scene/{storyboard}/context": {
      "post": {
        "operationId": "generateTextToSceneContext",
        "description": "Generates dynamic creative-context questions from the supplied video idea to steer storyboard generation. Returns exactly three question sets under `data` — `purpose`, `style`, and `audience`, each with four tailored options. Free — no credits charged.",
        "summary": "Generate context questions",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateContextRequest"
              },
              "example": {
                "prompt": "A gripping documentary about the creatures of the deep ocean."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "string",
                      "description": "The generated narrative context text."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "key": "purpose",
                      "question": "What is the main goal of this documentary?",
                      "options": [
                        "Educate curious viewers",
                        "Raise ocean awareness",
                        "Entertain with wonder",
                        "Inspire conservation"
                      ]
                    },
                    {
                      "key": "style",
                      "question": "What visual and emotional treatment fits best?",
                      "options": [
                        "Moody cinematic slow-burn",
                        "Bright nature-doc clarity",
                        "Tense thriller pacing",
                        "Dreamy ambient drift"
                      ]
                    },
                    {
                      "key": "audience",
                      "question": "Who is this for and where will they watch?",
                      "options": [
                        "Science fans on YouTube",
                        "Students on TikTok",
                        "Educators on LinkedIn",
                        "General viewers on Reels"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene/{storyboard}/prompt": {
      "post": {
        "operationId": "generateTextToScenePrompt",
        "description": "💳 Charges credits. Kicks off asynchronous generation of the storyboard (subjects, hero image, scene prompts) from its source prompt. Returns HTTP 202; poll `GET /text-to-scene/{id}` and read `data.status`. Send the body as `application/json`, or as `multipart/form-data` to attach reference image files.\n\n`clip_engine_id` must be a **text-to-video (clip) engine** — pick an id from `GET /faceless/options` (`clip_engines`); an image-engine or unknown id returns `422`.",
        "summary": "Generate the storyboard from its prompt",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitTextToScenePromptRequest"
              },
              "example": {
                "prompt": "A documentary about deep-sea creatures.",
                "clip_engine_id": 12,
                "duration": {
                  "min": 30,
                  "max": 60
                }
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/SubmitTextToScenePromptRequest"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "uuid": "sb_abc123",
                    "status": "generating:prompts",
                    "prompt": "A documentary about deep-sea creatures.",
                    "settings": {
                      "audio": true,
                      "aspect_ratio": "16:9",
                      "resolution": "1080p"
                    },
                    "duration": [
                      5,
                      6,
                      5
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Deep-sea documentary",
                      "type": "text_to_scene",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    "scenes": [
                      {
                        "id": 12,
                        "uuid": "scn_abc123",
                        "order": 0,
                        "video_prompt": "Wide shot of a glowing coral reef.",
                        "duration": 5,
                        "status": "draft",
                        "error": null,
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 15,
                      "remaining": 885
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene/{storyboard}/scenes": {
      "post": {
        "operationId": "createTextToSceneScene",
        "summary": "Add a scene",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManageTextToSceneSceneRequest"
              },
              "example": {
                "order": 0,
                "raw_video_prompt": "Wide shot of a glowing coral reef.",
                "duration": 5
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 12,
                    "uuid": "scn_abc123",
                    "order": 0,
                    "video_prompt": "Wide shot of a glowing coral reef.",
                    "duration": 5,
                    "status": "draft",
                    "error": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Adds a new scene to the storyboard at the given order with a video prompt and duration."
      }
    },
    "/text-to-scene/{storyboard}/scenes/{scene}": {
      "patch": {
        "operationId": "updateTextToSceneScene",
        "summary": "Update a scene",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManageTextToSceneSceneRequest"
              },
              "example": {
                "raw_video_prompt": "Close-up of a translucent jellyfish pulsing with light.",
                "duration": 6
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 12,
                    "uuid": "scn_abc123",
                    "order": 0,
                    "video_prompt": "Wide shot of a glowing coral reef.",
                    "duration": 5,
                    "status": "draft",
                    "error": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Updates a scene's order, video prompt, or duration. Only the fields you send are changed."
      },
      "delete": {
        "operationId": "deleteTextToSceneScene",
        "summary": "Delete a scene",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "const": "Accepted",
                          "description": "Human-readable status message for the response."
                        }
                      },
                      "required": [
                        "message"
                      ],
                      "description": "Acknowledgement that the deletion was accepted."
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "message": "Accepted"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Deletes a scene from the storyboard. Returns HTTP 202 while related cleanup runs asynchronously."
      }
    },
    "/text-to-scene/{storyboard}/scenes/{scene}/status": {
      "get": {
        "operationId": "getTextToSceneSceneStatus",
        "summary": "Get a scene's status",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "integer",
                          "description": "Unique numeric identifier of the resource."
                        },
                        "status": {
                          "anyOf": [
                            {
                              "$ref": "#/components/schemas/SceneStatus"
                            },
                            {
                              "type": "null"
                            }
                          ],
                          "description": "HTTP status code echoed in the response body."
                        },
                        "error": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Error message describing why processing failed, if any."
                        }
                      },
                      "required": [
                        "id",
                        "status",
                        "error"
                      ],
                      "description": "The scene's id, status, and any error."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 12,
                    "status": "clip:generating",
                    "error": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns the current clip-generation status of a single scene — a lightweight endpoint for polling while a scene's clip is generating."
      }
    },
    "/text-to-scene/{storyboard}/scenes/sort": {
      "put": {
        "operationId": "sortTextToSceneScenes",
        "summary": "Reorder scenes",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SortScenesRequest"
              },
              "example": {
                "scene_id": 12,
                "after_id": 8
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "data": {
                      "type": "object",
                      "properties": {
                        "message": {
                          "type": "string",
                          "const": "Scenes sorted successfully",
                          "description": "Human-readable status message for the response."
                        }
                      },
                      "required": [
                        "message"
                      ],
                      "description": "Confirmation that the scenes were sorted."
                    }
                  },
                  "required": [
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "message": "Scenes sorted successfully"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Moves a scene to follow another scene (or to the start when `after_id` is null), reordering the storyboard."
      }
    },
    "/text-to-scene/{storyboard}/scenes/{scene}/frames": {
      "put": {
        "operationId": "assignTextToSceneFrames",
        "summary": "Assign scene frames",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AssignTextToSceneFrameRequest"
              },
              "example": {
                "first_frame_id": 101,
                "last_frame_id": 102
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 12,
                    "uuid": "scn_abc123",
                    "order": 0,
                    "video_prompt": "Wide shot of a glowing coral reef.",
                    "duration": 5,
                    "status": "draft",
                    "error": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Sets (or clears) the first and/or last frame assets for a scene. Pass null to clear a frame."
      }
    },
    "/text-to-scene/{storyboard}/scenes/{scene}/chain": {
      "put": {
        "operationId": "chainTextToSceneScene",
        "summary": "Chain a scene",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ChainSceneRequest"
              },
              "example": {
                "scene_id": 11
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 12,
                    "uuid": "scn_abc123",
                    "order": 0,
                    "video_prompt": "Wide shot of a glowing coral reef.",
                    "duration": 5,
                    "status": "draft",
                    "error": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Chains this scene to another scene so the referenced scene's last frame seeds this scene's first frame, keeping motion continuous."
      },
      "delete": {
        "operationId": "unchainTextToSceneScene",
        "summary": "Unchain a scene",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "scene",
            "in": "path",
            "required": true,
            "description": "The scene ID",
            "schema": {
              "type": "integer"
            },
            "example": 12
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 12,
                    "uuid": "scn_abc123",
                    "order": 0,
                    "video_prompt": "Wide shot of a glowing coral reef.",
                    "duration": 5,
                    "status": "draft",
                    "error": null,
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Removes the chaining link from a scene so its first frame is no longer seeded by another scene."
      }
    },
    "/text-to-scene/{storyboard}/moodboard/upload": {
      "post": {
        "operationId": "uploadTextToSceneMoodboard",
        "description": "Attaches reference imagery to the storyboard's moodboard to steer its visual style. Send as `multipart/form-data` with one or more `files[]` image parts (jpeg, png, jpg, webp; each 512×512–4096×4096, max 10 MB). Returns the moodboard entries.",
        "summary": "Add moodboard references",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "description": "Reference images to attach to the storyboard moodboard. Send as `multipart/form-data` with one or more `files[]` image parts.",
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "minItems": 1,
                    "description": "One or more reference image files (jpeg, png, jpg, webp; each between 512×512 and 4096×4096 pixels, max 10 MB). Sent as repeated `files[]` multipart parts.",
                    "items": {
                      "type": "string",
                      "format": "binary",
                      "description": "A single reference image file."
                    }
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "files"
                ],
                "properties": {
                  "files": {
                    "type": "array",
                    "minItems": 1,
                    "description": "One or more reference image files (jpeg, png, jpg, webp; each between 512×512 and 4096×4096 pixels, max 10 MB). Sent as repeated `files[]` multipart parts.",
                    "items": {
                      "type": "string",
                      "format": "binary",
                      "description": "A single reference image file."
                    }
                  }
                }
              },
              "example": {
                "files": [
                  "<binary image file>"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TextToSceneMoodboardResource"
                      },
                      "description": "The storyboard's moodboard entries."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": [
                    {
                      "id": 1,
                      "asset_id": 5,
                      "source": "upload",
                      "type": "ai-image",
                      "status": "success",
                      "url": "https://cdn.syllaby.dev/moodboard/1.png",
                      "created_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene/{storyboard}/moodboard/generate": {
      "post": {
        "operationId": "generateTextToSceneMoodboard",
        "description": "💳 Charges credits. Generates a moodboard image from the supplied prompt (optionally enhanced) to steer the storyboard's visual style. Returns HTTP 202.",
        "summary": "Generate a moodboard image",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ManageTextToSceneMoodboardRequest"
              },
              "example": {
                "prompt": "Warm cinematic color palette with deep ocean blues.",
                "enhance": true
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneMoodboardResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "asset_id": 5,
                    "source": "generated",
                    "type": "ai-image",
                    "status": "success",
                    "url": "https://cdn.syllaby.dev/moodboard/1.png",
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 1,
                      "remaining": 899
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene/{storyboard}/clips": {
      "post": {
        "operationId": "generateTextToSceneClips",
        "description": "💳 Charges credits. Queues clip generation for the given scenes (optionally enhancing each scene's prompt first). Returns HTTP 202; poll each scene's status or `GET /text-to-scene/{id}`.",
        "summary": "Generate scene clips",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GenerateTextToSceneClipRequest"
              },
              "example": {
                "scenes": [
                  {
                    "id": 12,
                    "enhance": true
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/TextToSceneSceneResource"
                      },
                      "description": "The scenes queued for clip generation."
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": [
                    {
                      "id": 12,
                      "uuid": "scn_abc123",
                      "order": 0,
                      "video_prompt": "Wide shot of a glowing coral reef.",
                      "duration": 5,
                      "status": "clip:queued",
                      "error": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ],
                  "meta": {
                    "credits": {
                      "cost": 30,
                      "remaining": 870
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/text-to-scene/{storyboard}/estimate": {
      "get": {
        "operationId": "estimateTextToScene",
        "summary": "Estimate storyboard render credits",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "required": {
                          "type": "integer",
                          "description": "The required value for the resource."
                        },
                        "available": {
                          "type": "string",
                          "description": "The available value for the resource."
                        },
                        "sufficient": {
                          "type": "boolean",
                          "description": "The sufficient value for the resource."
                        }
                      },
                      "required": [
                        "required",
                        "available",
                        "sufficient"
                      ],
                      "description": "Estimated required credits, available balance, and whether the balance is sufficient."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "required": 45,
                    "available": 120,
                    "sufficient": true
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Estimates the credits required to render the storyboard and compares them against your available balance."
      }
    },
    "/text-to-scene/{storyboard}/render": {
      "post": {
        "operationId": "renderTextToScene",
        "description": "Assembles the finished storyboard's scene clips into a video asynchronously and returns HTTP 202. Rendering does **not** charge credits — clips are billed when they are generated (`POST /text-to-scene/{storyboard}/clips`). Every scene must have a completed clip first. Track progress by polling `GET /text-to-scene/{id}` and reading `data.video.status`.\n\n**Preconditions (both fail with `422`):**\n- **A scene is missing a completed clip** → `422` `All scenes must have completed clips before rendering.` — generate clips first and poll each scene to `clip:completed`.\n- **Already rendering** → `422` `This storyboard is already rendering.` — wait for `data.video.status` to leave `rendering`.",
        "summary": "Render the storyboard",
        "tags": [
          "Text-to-Scene"
        ],
        "parameters": [
          {
            "name": "storyboard",
            "in": "path",
            "required": true,
            "description": "The storyboard ID",
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "202": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 202,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/TextToSceneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 202,
                  "data": {
                    "id": 1,
                    "uuid": "sb_abc123",
                    "status": "processing",
                    "prompt": "A documentary about deep-sea creatures.",
                    "settings": {
                      "audio": true,
                      "aspect_ratio": "16:9",
                      "resolution": "1080p"
                    },
                    "duration": [
                      5,
                      6,
                      5
                    ],
                    "video": {
                      "id": 10,
                      "user_id": 1,
                      "idea_id": null,
                      "scheduler_id": null,
                      "title": "Deep-sea documentary",
                      "type": "text_to_scene",
                      "url": null,
                      "status": "rendering",
                      "retries": 0,
                      "hash": "abc123",
                      "synced_at": null,
                      "metadata": {
                        "ai_labels": true,
                        "custom_description": null
                      },
                      "failure": null,
                      "created_at": "2026-01-01T12:00:00.000000Z",
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    "scenes": [
                      {
                        "id": 12,
                        "uuid": "scn_abc123",
                        "order": 0,
                        "video_prompt": "Wide shot of a glowing coral reef.",
                        "duration": 5,
                        "status": "draft",
                        "error": null,
                        "created_at": "2026-01-01T12:00:00.000000Z",
                        "updated_at": "2026-01-01T12:00:00.000000Z"
                      }
                    ],
                    "created_at": "2026-01-01T12:00:00.000000Z",
                    "updated_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "description": "Render preconditions not met — a scene is missing a completed clip, or the storyboard is already rendering.",
            "content": {
              "application/json": {
                "example": {
                  "message": "All scenes must have completed clips before rendering.",
                  "error": {
                    "code": "GEN-WRONG-ARGS",
                    "status": 422
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/voice-clones": {
      "post": {
        "operationId": "createVoiceClone",
        "summary": "Create a voice clone",
        "tags": [
          "Voice Clones"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CreateVoiceCloneRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVoiceCloneRequest"
              },
              "example": {
                "terms": true,
                "name": "My Narrator",
                "gender": "female",
                "language": "en",
                "description": "Warm, conversational narrator voice.",
                "samples": [
                  "<binary audio file>"
                ],
                "purchase_addon": true
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/VoiceCloneResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "name": "My Narrator",
                    "gender": "female",
                    "language": "en",
                    "description": "Warm, conversational narrator voice.",
                    "status": "pending",
                    "slot_type": "addon",
                    "preview_url": null,
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 15,
                      "remaining": 885
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Clones a voice from 1–3 audio samples. Send as `multipart/form-data`.\n\nReturns `201` with the clone in a **`pending`** state — cloning runs asynchronously. Poll `GET /voice-clones/{id}` and read `data.status` (`pending` → `reviewing` → `completed`, or `failed`); the sample audio preview appears at `data.preview_url` once `completed`.\n\n**Slots.** Each plan includes a fixed number of voice-clone slots. When your included slots are full you can buy an extra one by sending `purchase_addon: true` — this **💳 charges credits** (the price is `cost` on `GET /voice-clones/slots`) and the response `meta.credits` reports the charge and your remaining balance. Without a free slot and without `purchase_addon`, the request returns `403`; with `purchase_addon` but too few credits, it returns `402`."
      },
      "get": {
        "operationId": "listVoiceClones",
        "summary": "List voice clones",
        "tags": [
          "Voice Clones"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/VoiceCloneResource"
                      },
                      "description": "Your voice clones."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "name": "My Narrator",
                      "gender": "female",
                      "language": "en",
                      "description": "Warm, conversational narrator voice.",
                      "status": "completed",
                      "slot_type": "default",
                      "preview_url": "https://cdn.syllaby.dev/voices/clone-1/preview.mp3",
                      "created_at": "2026-01-01T12:00:00.000000Z"
                    },
                    {
                      "id": 2,
                      "name": "Podcast Host",
                      "gender": "female",
                      "language": "en",
                      "description": "Warm, conversational narrator voice.",
                      "status": "pending",
                      "slot_type": "addon",
                      "preview_url": null,
                      "created_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Lists the voice clones you own, newest first."
      }
    },
    "/voice-clones/slots": {
      "get": {
        "operationId": "getVoiceCloneSlots",
        "tags": [
          "Voice Clones"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "object",
                      "description": "Voice-clone slot capacity and purchase availability.",
                      "properties": {
                        "default_max": {
                          "type": "integer",
                          "description": "Voice-clone slots included with your plan."
                        },
                        "addon_cap": {
                          "type": "integer",
                          "description": "Maximum number of extra (add-on) slots you may purchase."
                        },
                        "current_addons": {
                          "type": "integer",
                          "description": "Extra (add-on) slots you have already purchased."
                        },
                        "lifetime_purchases": {
                          "type": "integer",
                          "description": "Total add-on slots ever purchased on this account."
                        },
                        "filled": {
                          "type": "integer",
                          "description": "Slots currently in use by existing voice clones."
                        },
                        "available": {
                          "type": "integer",
                          "description": "Slots free to use right now."
                        },
                        "can_buy": {
                          "type": "boolean",
                          "description": "Whether buying another add-on slot is currently possible (add-on cap not reached, enough credits, not on a trial)."
                        },
                        "cost": {
                          "type": "integer",
                          "description": "Credits charged to purchase one extra add-on slot."
                        }
                      }
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "default_max": 1,
                    "addon_cap": 5,
                    "current_addons": 2,
                    "lifetime_purchases": 2,
                    "filled": 2,
                    "available": 1,
                    "can_buy": true,
                    "cost": 15
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "summary": "Get voice-clone slot availability",
        "description": "Reports your voice-clone slot capacity and whether you can buy another one. Use this before `POST /voice-clones` to decide whether to send `purchase_addon`.\n\n- `default_max` — slots included with your plan.\n- `addon_cap` — the maximum number of extra slots you may purchase.\n- `current_addons` — extra slots you have already bought.\n- `lifetime_purchases` — total add-on slots ever purchased.\n- `filled` / `available` — slots in use and slots free right now.\n- `can_buy` — whether buying another slot is currently possible (add-on cap not reached, enough credits, not on a trial).\n- `cost` — credits charged to buy one extra slot."
      }
    },
    "/voice-clones/{id}": {
      "get": {
        "operationId": "getVoiceClone",
        "summary": "Get a voice clone",
        "tags": [
          "Voice Clones"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/VoiceCloneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "name": "My Narrator",
                    "gender": "female",
                    "language": "en",
                    "description": "Warm, conversational narrator voice.",
                    "status": "completed",
                    "slot_type": "default",
                    "preview_url": "https://cdn.syllaby.dev/voices/clone-1/preview.mp3",
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns a single voice clone you own — poll this to track cloning status (`pending` → `reviewing` → `completed`/`failed`). Responds with `404` when the id does not exist or belongs to another account."
      },
      "patch": {
        "operationId": "updateVoiceClone",
        "summary": "Update a voice clone",
        "tags": [
          "Voice Clones"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateVoiceCloneRequest"
              },
              "example": {
                "name": "My Narrator",
                "gender": "female",
                "description": "Warm, conversational narrator voice."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/VoiceCloneResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "name": "My Narrator",
                    "gender": "female",
                    "language": "en",
                    "description": "Warm, conversational narrator voice.",
                    "status": "completed",
                    "slot_type": "default",
                    "preview_url": "https://cdn.syllaby.dev/voices/clone-1/preview.mp3",
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Updates a voice clone's `name`, `gender`, and `description`. Only the fields you send are changed. Owner-scoped — a clone belonging to another account responds with `404`."
      },
      "delete": {
        "operationId": "deleteVoiceClone",
        "summary": "Delete a voice clone",
        "tags": [
          "Voice Clones"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "204": {
            "description": "No content"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Deletes a voice clone you own and removes the underlying provider voice. Returns `204 No Content`. Owner-scoped — a clone belonging to another account responds with `404`."
      }
    },
    "/ideas/discover": {
      "post": {
        "operationId": "discoverIdeas",
        "summary": "Discover ideas for a keyword",
        "tags": [
          "Ideas"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DiscoverIdeasRequest"
              },
              "example": {
                "keyword": "cold plunge benefits",
                "network": "youtube"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/KeywordResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "name": "cold plunge benefits",
                    "slug": "cold-plunge-benefits",
                    "network": "youtube",
                    "ideas_count": 42,
                    "searched_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 15,
                      "remaining": 885
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Discovers content ideas for a keyword on a given network. This call is **synchronous** and can be slow — worst case around **2 minutes** while the upstream keyword tool responds. On success it returns the keyword summary (with `ideas_count`); read the discovered ideas themselves with `GET /ideas`.\n\n**💳 Charges 15 credits — and it charges on *every* fruitful call, including a cached re-search of a keyword you have already discovered.** Discovery results are cached globally for three weeks; a repeat discover of the same keyword within that window returns the cached ideas **but still charges the full 15 credits**. A call is charged only when the search actually yields ideas (`ideas_count > 0`); a search that finds nothing is free. The charge and your remaining balance are reported in `meta.credits`.\n\n**Do not blindly retry a timed-out discover.** The synchronous worst case (~2 minutes) exceeds many client and proxy timeouts, so your HTTP layer may give up *after* the server has already completed the discovery and charged you. There is **no idempotency key** on this endpoint: a retry that lands on the now-warm three-week cache is treated as a fresh fruitful discovery and **charges another 15 credits for the same logical search**. If a discover times out, reconcile first with the **free** `GET /ideas` (same `keyword` + `network`): if it now returns ideas, the discovery succeeded — do not retry.\n\nIf your balance is below 15 credits the request is rejected up front with `402` before any search runs."
      }
    },
    "/ideas": {
      "get": {
        "operationId": "listIdeas",
        "summary": "List ideas for a keyword",
        "tags": [
          "Ideas"
        ],
        "parameters": [
          {
            "name": "keyword",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 80
            },
            "description": "The keyword to list ideas for — must be one you have previously discovered (2–80 characters).",
            "example": "cold plunge benefits"
          },
          {
            "name": "network",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "google",
                "google-trends",
                "youtube",
                "instagram",
                "twitter",
                "bing",
                "pinterest",
                "tiktok"
              ]
            },
            "description": "The network the keyword was discovered on: `google`, `google-trends`, `youtube`, `instagram`, `twitter`, `bing`, `pinterest`, or `tiktok`.",
            "example": "youtube"
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": [
                "string",
                "null"
              ],
              "enum": [
                "volume",
                "cpc",
                "competition",
                "trend",
                "-volume",
                "-cpc",
                "-competition",
                "-trend"
              ]
            },
            "description": "Sort field, optionally prefixed with `-` for descending. One of `volume`, `cpc`, `competition`, `trend` (or their `-` variants). Defaults to `-volume` (highest search volume first).",
            "example": "-volume"
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    }
                  },
                  "required": [
                    "status",
                    "message"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "name": "Cold plunge for beginners: a 30-day guide",
                      "volume": 18100,
                      "cpc": 0.42,
                      "competition": 0.35,
                      "competition_label": "LOW",
                      "trend": "up",
                      "trends": [
                        {
                          "month": "2025-11",
                          "value": 14800
                        },
                        {
                          "month": "2025-12",
                          "value": 16200
                        },
                        {
                          "month": "2026-01",
                          "value": 18100
                        }
                      ],
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    },
                    {
                      "name": "Are cold plunges worth it? The science, explained",
                      "volume": 9800,
                      "cpc": 0.42,
                      "competition": 0.52,
                      "competition_label": "MEDIUM",
                      "trend": "flat",
                      "trends": [
                        {
                          "month": "2025-11",
                          "value": 14800
                        },
                        {
                          "month": "2025-12",
                          "value": 16200
                        },
                        {
                          "month": "2026-01",
                          "value": 18100
                        }
                      ],
                      "updated_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns a paginated, sortable list of the ideas discovered for a keyword. **Free — no credits charged.**\n\nYou can only list ideas for a keyword **you have previously discovered** via `POST /ideas/discover`; a `keyword`+`network` pair you never discovered responds with `403`. Sort with `sort` (default `-volume`)."
      }
    },
    "/characters/genres": {
      "get": {
        "operationId": "listCharacterGenres",
        "summary": "List character genres",
        "tags": [
          "Characters"
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.GenreResource"
                      },
                      "description": "The available character genres."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 3,
                      "name": "Realistic",
                      "slug": "realistic",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    },
                    {
                      "id": 4,
                      "name": "Anime",
                      "slug": "anime",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Lists the visual genres a character can be generated in. Use a genre `id` as `genre_id` when generating a preview (`POST /characters/{id}/preview`). Only character-capable genres are returned."
      }
    },
    "/characters": {
      "get": {
        "operationId": "listCharacters",
        "summary": "List characters",
        "tags": [
          "Characters"
        ],
        "parameters": [
          {
            "name": "genre",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Filter by genre slug (see `GET /characters/genres`).",
            "example": "realistic"
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter by ownership: `system` (Syllaby's built-in characters) or `custom` (characters you created). Omit to return both.\n\n`custom` also widens the status filter: it returns **every** character you own, including `draft` ones that are not yet previewed. The unfiltered list excludes `draft` and `preview-failed`.\n\nAny other value returns `422` — an unknown value used to be ignored and returned the full unfiltered list, which looked like a successful filter.",
            "schema": {
              "type": "string",
              "enum": [
                "system",
                "custom"
              ]
            },
            "example": "custom"
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Return only characters in this state. Overrides the default exclusion of `draft` and `preview-failed`, and applies with or without `type`. Any value outside the list returns `422`.",
            "schema": {
              "type": "string",
              "enum": [
                "draft",
                "preview-generating",
                "preview-ready",
                "preview-failed",
                "pose-generating",
                "pose-ready",
                "pose-failed",
                "model-training",
                "model-training-failed",
                "ready"
              ]
            },
            "example": "ready"
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/App.Http.Resources.Api.v2.CharacterResource"
                      },
                      "description": "The characters available to you."
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": [
                    {
                      "id": 1,
                      "name": "Aria",
                      "status": "ready",
                      "genre": {
                        "id": 3,
                        "name": "Realistic",
                        "slug": "realistic",
                        "preview": {
                          "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                          "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                          "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                        }
                      },
                      "gender": "female",
                      "age": "25-34",
                      "traits": [
                        "confident",
                        "friendly"
                      ],
                      "preview_url": "https://cdn.syllaby.dev/characters/1/preview.png",
                      "previews": [
                        {
                          "id": 501,
                          "url": "https://cdn.syllaby.dev/characters/1/sandbox-501.png"
                        },
                        {
                          "id": 502,
                          "url": "https://cdn.syllaby.dev/characters/1/sandbox-502.png"
                        },
                        {
                          "id": 503,
                          "url": "https://cdn.syllaby.dev/characters/1/sandbox-503.png"
                        },
                        {
                          "id": 504,
                          "url": "https://cdn.syllaby.dev/characters/1/sandbox-504.png"
                        }
                      ],
                      "poses": [
                        "https://cdn.syllaby.dev/characters/1/pose-1.png",
                        "https://cdn.syllaby.dev/characters/1/pose-2.png"
                      ],
                      "created_at": "2026-01-01T12:00:00.000000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Lists characters available to you — Syllaby's built-in `system` characters plus the `custom` characters you have created (your own sorted first). Filter with `genre` (a genre slug), `type` (`system` or `custom`), and/or `status`.\n\n**By default the list excludes `draft` and `preview-failed` characters**, so a character you just created with `POST /characters` will not appear until it has been previewed. Pass `type=custom` to see everything you own including drafts, or `status=draft` to see only those.\n\nAn unknown `type` or `status` value returns `422`. A `genre` slug that matches nothing returns `200` with an empty list — a genre is a lookup, not an enum."
      },
      "post": {
        "operationId": "createCharacter",
        "summary": "Create a character",
        "tags": [
          "Characters"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/CreateCharacterRequest"
              }
            },
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCharacterRequest"
              },
              "example": {
                "image": "<binary image file>",
                "name": "Aria",
                "gender": "female",
                "age": "25-34",
                "genre_id": 3
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.CharacterResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "name": "Aria",
                    "status": "draft",
                    "genre": {
                      "id": 3,
                      "name": "Realistic",
                      "slug": "realistic",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    },
                    "gender": "female",
                    "age": "25-34",
                    "traits": [
                      "confident",
                      "friendly"
                    ],
                    "preview_url": "https://cdn.syllaby.dev/characters/1/preview.png",
                    "previews": [],
                    "poses": [],
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Creates a custom character from a reference photo. Send as `multipart/form-data` with an `image` file (plus optional `name`, `gender`, `age`, `traits`, `genre_id`).\n\nReturns `201` with the character in an early state. Next, generate preview candidates with `POST /characters/{id}/preview`, then train the one you like with `POST /characters/{id}/train`."
      }
    },
    "/characters/{id}": {
      "get": {
        "operationId": "getCharacter",
        "summary": "Get a character",
        "tags": [
          "Characters"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.CharacterResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "name": "Aria",
                    "status": "preview-ready",
                    "genre": {
                      "id": 3,
                      "name": "Realistic",
                      "slug": "realistic",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    },
                    "gender": "female",
                    "age": "25-34",
                    "traits": [
                      "confident",
                      "friendly"
                    ],
                    "preview_url": "https://cdn.syllaby.dev/characters/1/preview.png",
                    "previews": [
                      {
                        "id": 501,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-501.png"
                      },
                      {
                        "id": 502,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-502.png"
                      },
                      {
                        "id": 503,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-503.png"
                      },
                      {
                        "id": 504,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-504.png"
                      }
                    ],
                    "poses": [],
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequired"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Returns a single character (a `system` character or one you own). Poll this to track preview and training progress via `data.status`. When previews are ready, `data.previews[]` holds the candidate ids — pass the chosen `previews[].id` as `preview_id` to `POST /characters/{id}/train`. Responds with `404` when the id does not exist or belongs to another account."
      },
      "delete": {
        "operationId": "deleteCharacter",
        "summary": "Delete a character",
        "tags": [
          "Characters"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "responses": {
          "204": {
            "description": "No content"
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Deletes a custom character you own. Returns `204 No Content`, and the character is gone — a follow-up `GET` returns `404`, as does a repeat `DELETE`.\n\n**System characters cannot be deleted** — a built-in character responds with `403`; a character owned by another account responds with `404`. A character that is mid-preview or mid-training also responds with `403`; wait for it to settle.\n\nDeleting a character that a scheduler or an existing video referenced does not delete those — they simply lose the character reference."
      }
    },
    "/characters/{id}/preview": {
      "post": {
        "operationId": "previewCharacter",
        "summary": "Generate character previews",
        "tags": [
          "Characters"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCharacterPreviewRequest"
              },
              "example": {
                "genre_id": 3
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 201,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.CharacterResource"
                    },
                    "meta": {
                      "type": "string",
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 201,
                  "data": {
                    "id": 1,
                    "name": "Aria",
                    "status": "preview-ready",
                    "genre": {
                      "id": 3,
                      "name": "Realistic",
                      "slug": "realistic",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    },
                    "gender": "female",
                    "age": "25-34",
                    "traits": [
                      "confident",
                      "friendly"
                    ],
                    "preview_url": "https://cdn.syllaby.dev/characters/1/preview.png",
                    "previews": [
                      {
                        "id": 501,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-501.png"
                      },
                      {
                        "id": 502,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-502.png"
                      },
                      {
                        "id": 503,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-503.png"
                      },
                      {
                        "id": 504,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-504.png"
                      }
                    ],
                    "poses": [],
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "Generates preview candidates for a character in the chosen genre, using the reference image supplied at creation (you never handle its media id). This call is **synchronous** and can take up to **~90 seconds**; it is throttled to **5 requests per minute**.\n\nReturns `201` with the character; the candidate images appear under `data.previews[]`, each with an `id` you can pass as `preview_id` to `POST /characters/{id}/train`.\n\n**Candidates accumulate.** Every call appends to `previews[]` — earlier candidates are never pruned, and the number produced per call varies. Read the ids from the response you just received rather than assuming a fixed count or that the array holds only the latest batch.\n\n**System characters cannot be previewed** — a built-in character resolves but is rejected with `403`.\n\n**Two distinct `422` shapes can come back, and they mean different things:**\n- **Validation error** — a bad request field (e.g. a `genre_id` that is not a character-capable genre). Standard validation shape: `{ message, errors: { genre_id: [...] } }`. Fix the input and retry.\n- **Generation failure** — the request was valid but preview generation failed downstream. Error-envelope shape: `{ message, error: { code, status } }` with no `errors` bag. Poll `GET /characters/{id}` to check status, then retry."
      }
    },
    "/characters/{id}/train": {
      "post": {
        "operationId": "trainCharacter",
        "summary": "Train a character",
        "tags": [
          "Characters"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "description": "Identifier of the faceless video.",
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartCharacterTrainingRequest"
              },
              "example": {
                "preview_id": 501,
                "name": "Aria",
                "age": "25-34",
                "gender": "female"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "message": {
                      "type": "string",
                      "const": "Success.",
                      "description": "Human-readable status message for the response."
                    },
                    "status": {
                      "type": "integer",
                      "const": 200,
                      "description": "HTTP status code echoed in the response body."
                    },
                    "data": {
                      "$ref": "#/components/schemas/App.Http.Resources.Api.v2.CharacterResource"
                    },
                    "meta": {
                      "type": "object",
                      "properties": {
                        "credits": {
                          "type": "object",
                          "properties": {
                            "cost": {
                              "type": "integer",
                              "description": "Credit cost charged for one use of this engine/feature."
                            },
                            "remaining": {
                              "type": "integer",
                              "description": "Remaining monthly credits available to spend."
                            }
                          },
                          "required": [
                            "cost",
                            "remaining"
                          ],
                          "description": "Credit balance summary for the user."
                        }
                      },
                      "required": [
                        "credits"
                      ],
                      "description": "Pagination and listing metadata."
                    }
                  },
                  "required": [
                    "message",
                    "status",
                    "data",
                    "meta"
                  ]
                },
                "example": {
                  "message": "Success.",
                  "status": 200,
                  "data": {
                    "id": 1,
                    "name": "Aria",
                    "status": "pose-generating",
                    "genre": {
                      "id": 3,
                      "name": "Realistic",
                      "slug": "realistic",
                      "preview": {
                        "16:9": "https://cdn.syllaby.dev/faceless/genres/realistic/16:9.webp",
                        "9:16": "https://cdn.syllaby.dev/faceless/genres/realistic/9:16.webp",
                        "1:1": "https://cdn.syllaby.dev/faceless/genres/realistic/1:1.webp"
                      }
                    },
                    "gender": "female",
                    "age": "25-34",
                    "traits": [
                      "confident",
                      "friendly"
                    ],
                    "preview_url": "https://cdn.syllaby.dev/characters/1/preview.png",
                    "previews": [
                      {
                        "id": 501,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-501.png"
                      },
                      {
                        "id": 502,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-502.png"
                      },
                      {
                        "id": 503,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-503.png"
                      },
                      {
                        "id": 504,
                        "url": "https://cdn.syllaby.dev/characters/1/sandbox-504.png"
                      }
                    ],
                    "poses": [],
                    "created_at": "2026-01-01T12:00:00.000000Z"
                  },
                  "meta": {
                    "credits": {
                      "cost": 10,
                      "remaining": 890
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/AuthenticationException"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "403": {
            "$ref": "#/components/responses/SubscriptionRequiredOrAuthorization"
          },
          "404": {
            "$ref": "#/components/responses/ModelNotFoundException"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "409": {
            "$ref": "#/components/responses/EmailNotVerified"
          },
          "422": {
            "$ref": "#/components/responses/ValidationException"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        },
        "description": "💳 **Charges 10 credits.** The response `meta.credits` reports the charge and your remaining balance.\n\nTrains a consistent character from a chosen preview candidate and kicks off pose generation. Pass `preview_id` (one of the `previews[].id` values from `POST /characters/{id}/preview`) plus `name`, `age`, and `gender`. Training runs asynchronously — poll `GET /characters/{id}` until `data.status` is `ready`, at which point `data.poses[]` holds the generated pose images.\n\n**System characters cannot be trained** — a built-in character responds with `403`."
      }
    }
  },
  "components": {
    "securitySchemes": {
      "http": {
        "type": "http",
        "scheme": "bearer"
      }
    },
    "schemas": {
      "AccountPublicationResource": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "description": "Current lifecycle status of the resource."
          },
          "error": {
            "type": "string",
            "description": "Error message describing why processing failed, if any."
          },
          "metadata": {
            "type": "string",
            "description": "Additional metadata for the resource."
          },
          "post_type": {
            "type": "string",
            "description": "Type of social post (e.g. \"reel\", \"short\", \"post\")."
          },
          "channels": {
            "$ref": "#/components/schemas/SocialChannelResource"
          }
        },
        "required": [
          "status",
          "error",
          "metadata",
          "post_type",
          "channels"
        ],
        "title": "AccountPublicationResource",
        "description": "A account Publication record."
      },
      "App.Http.Resources.Api.v2.AssetResource": {
        "type": "object",
        "description": "A media asset (image or clip) that composes a faceless video scene.",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Identifier of the asset."
          },
          "uuid": {
            "type": "string",
            "description": "Stable UUID of the asset within the video (present when listed against a scene)."
          },
          "type": {
            "type": "string",
            "enum": [
              "audios",
              "faceless-background",
              "ai-image",
              "ai-video",
              "stock-video",
              "stock-image",
              "custom-image",
              "custom-video",
              "scraped",
              "watermark",
              "thumbnail",
              "font"
            ],
            "description": "Kind of media asset (e.g. \"ai-image\", \"ai-video\", \"stock-video\")."
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "success",
              "failed",
              "processing",
              "unknown"
            ],
            "description": "Generation lifecycle state of the asset."
          },
          "url": {
            "type": "string",
            "nullable": true,
            "description": "Downloadable URL of the rendered media file, when available."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based scene position of the asset within the video."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the asset was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the asset was last updated."
          }
        },
        "required": [
          "id",
          "type",
          "status",
          "created_at",
          "updated_at"
        ],
        "title": "App.Http.Resources.Api.v2.AssetResource"
      },
      "App.Http.Resources.FacelessResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "video_id": {
            "type": "integer",
            "description": "Identifier of the parent video."
          },
          "voice_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the narration voice (see faceless options)."
          },
          "music_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background music track (media id)."
          },
          "background_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background asset (see faceless options)."
          },
          "estimated_duration": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Estimated rendered duration in seconds."
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FacelessType"
              },
              {
                "type": "null"
              }
            ],
            "description": "Type/category discriminator for the resource."
          },
          "genre": {
            "$ref": "#/components/schemas/GenreResource"
          },
          "script": {
            "type": [
              "string",
              "null"
            ],
            "description": "Narration script text for the video."
          },
          "hash": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Opaque content hash used for change detection."
          },
          "options": {
            "type": [
              "string",
              "null"
            ],
            "description": "Additional generation options for the faceless video."
          },
          "is_transcribed": {
            "type": "boolean",
            "description": "Whether the video audio has been transcribed."
          },
          "watermark_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the watermark asset (must be owned by the caller)."
          },
          "watermark": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "character_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the consistent character (see faceless options)."
          },
          "character": {
            "$ref": "#/components/schemas/CharacterResource"
          },
          "image_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "clip_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          },
          "engines": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 0,
            "maxItems": 0,
            "additionalItems": false,
            "description": "Available inference engines."
          },
          "video": {
            "$ref": "#/components/schemas/VideoResource"
          },
          "generator": {
            "$ref": "#/components/schemas/GeneratorResource"
          },
          "background": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "music": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "voice": {
            "$ref": "#/components/schemas/VoiceResource"
          },
          "trackers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackerResource"
            },
            "description": "Tracking records for the resource."
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetResource"
            },
            "description": "Ordered list of media assets used to compose the video."
          },
          "captions": {
            "$ref": "#/components/schemas/CaptionResource"
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "video_id",
          "voice_id",
          "music_id",
          "background_id",
          "estimated_duration",
          "type",
          "script",
          "hash",
          "options",
          "is_transcribed",
          "watermark_id",
          "character_id",
          "image_engine_id",
          "clip_engine_id",
          "engines",
          "created_at",
          "updated_at"
        ],
        "title": "App.Http.Resources.FacelessResource",
        "description": "A faceless record."
      },
      "AssetResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "uuid": {
            "type": "string",
            "description": "Globally unique UUID for the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "parent_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the parent record, or null."
          },
          "provider_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider-side identifier for the resource."
          },
          "genre_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the genre/style (see faceless options)."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the resource."
          },
          "type": {
            "$ref": "#/components/schemas/AssetType"
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL-friendly unique identifier for the resource."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable description of the resource."
          },
          "model": {
            "type": [
              "string",
              "null"
            ],
            "description": "Underlying model name used to generate the resource."
          },
          "style": {
            "type": [
              "string",
              "null"
            ],
            "description": "Style label applied to generation."
          },
          "status": {
            "$ref": "#/components/schemas/AssetStatus"
          },
          "is_private": {
            "type": "integer",
            "description": "Whether the record is private to its owner."
          },
          "orientation": {
            "type": [
              "string",
              "null"
            ],
            "description": "Video orientation. One of \"landscape\", \"portrait\", or \"square\"."
          },
          "order": {
            "type": "string",
            "description": "Zero-based ordering position within its collection."
          },
          "active": {
            "type": "string",
            "description": "Whether the record is currently active and selectable."
          },
          "is_bookmarked": {
            "type": "boolean",
            "description": "Whether the caller has bookmarked this record."
          },
          "is_used": {
            "type": "boolean",
            "description": "Whether the asset is currently in use by a video."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "genre": {
            "$ref": "#/components/schemas/Genre"
          },
          "user": {
            "$ref": "#/components/schemas/User"
          },
          "videos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Faceless"
            },
            "description": "Videos associated with the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "parent_id",
          "provider_id",
          "genre_id",
          "name",
          "type",
          "slug",
          "description",
          "model",
          "style",
          "status",
          "is_private",
          "orientation",
          "is_bookmarked",
          "is_used",
          "created_at",
          "updated_at"
        ],
        "title": "AssetResource",
        "description": "A asset record."
      },
      "AssetStatus": {
        "type": "string",
        "enum": [
          "draft",
          "success",
          "failed",
          "processing",
          "unknown"
        ],
        "title": "AssetStatus",
        "description": "A asset Status record."
      },
      "AssetType": {
        "type": "string",
        "enum": [
          "audios",
          "faceless-background",
          "ai-image",
          "ai-video",
          "stock-video",
          "stock-image",
          "custom-image",
          "custom-video",
          "scraped",
          "watermark",
          "thumbnail",
          "font"
        ],
        "title": "AssetType",
        "description": "A asset Type record."
      },
      "CaptionResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "model_id": {
            "type": "integer",
            "description": "Identifier of the related model the media is attached to."
          },
          "model_type": {
            "type": "string",
            "description": "Class/type of the related model the media is attached to."
          },
          "content": {
            "type": "array",
            "items": {},
            "description": "Text content of the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "model_id",
          "model_type",
          "content",
          "created_at",
          "updated_at"
        ],
        "title": "CaptionResource",
        "description": "A caption record."
      },
      "CharacterResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "uuid": {
            "type": "string",
            "description": "Globally unique UUID for the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "genre": {
            "$ref": "#/components/schemas/GenreResource"
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable description of the resource."
          },
          "training_images": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Images used to train the consistent character."
          },
          "gender": {
            "type": "string",
            "description": "Gender label (e.g. \"male\", \"female\", \"neutral\")."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CharacterStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "meta": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Pagination and listing metadata."
          },
          "active": {
            "type": "integer",
            "description": "Whether the record is currently active and selectable."
          },
          "reference": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "thumbnail": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "preview": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "URL of a preview image or clip for the resource."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "uuid",
          "user_id",
          "name",
          "slug",
          "description",
          "training_images",
          "gender",
          "status",
          "meta",
          "active",
          "created_at",
          "updated_at"
        ],
        "title": "CharacterResource",
        "description": "A character record."
      },
      "CharacterStatus": {
        "type": "string",
        "enum": [
          "draft",
          "preview-generating",
          "preview-ready",
          "preview-failed",
          "pose-generating",
          "pose-ready",
          "pose-failed",
          "model-training",
          "model-training-failed",
          "ready"
        ],
        "title": "CharacterStatus",
        "description": "A character Status record."
      },
      "CreateFacelessRequest": {
        "type": "object",
        "description": "v2 public-API input contract for creating a faceless video.\nInherits v1 rules; override here when the public contract must diverge.",
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Title of the resource."
          },
          "type": {
            "type": "string",
            "enum": [
              "b-roll",
              "url-based",
              "ai-visuals",
              "ai-clips"
            ],
            "description": "Faceless video type — controls how the visuals are sourced: `b-roll` (stock footage), `url-based` (images scraped from a web page — requires `POST /faceless/{faceless}/scrape-images` before render), `ai-visuals` (AI-generated images), or `ai-clips` (AI-generated video clips). Defaults to `ai-visuals`. **The type is fixed at creation and cannot be changed later.**"
          },
          "idea_id": {
            "type": "integer",
            "description": "Identifier of a content idea created in the Syllaby app, linking the video to it. Optional — omit it for API-only flows; the v2 API exposes no ideas endpoints, so there is no way to obtain a valid id through the API."
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 timestamp that schedules the video on your Syllaby content calendar — sending it creates a calendar event for the video. It does not delay or schedule the render."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 timestamp marking the end of the scheduled calendar slot. Must be the same as or after `starts_at`; only meaningful together with it."
          }
        },
        "title": "CreateFacelessRequest",
        "required": [
          "title",
          "type"
        ]
      },
      "EngineResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable description of the resource."
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "cost": {
            "type": "array",
            "items": {},
            "description": "Credit cost charged for one use of this engine/feature."
          },
          "modifiers": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Style or generation modifiers applied."
          },
          "features": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Feature flags or entitlements enabled for the plan."
          },
          "flags": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Feature flags applied to the user."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based ordering position within its collection."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "description",
          "type",
          "cost",
          "modifiers",
          "features",
          "flags",
          "order",
          "created_at",
          "updated_at"
        ],
        "title": "EngineResource",
        "description": "A engine record."
      },
      "EventResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "scheduler_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning scheduler."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hex color value (e.g. \"#FFFFFF\")."
          },
          "model_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the related model the media is attached to."
          },
          "model_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Class/type of the related model the media is attached to."
          },
          "starts_at": {
            "type": "string",
            "description": "ISO-8601 timestamp marking the start of the period."
          },
          "ends_at": {
            "type": "string",
            "description": "ISO-8601 timestamp marking the end of the period."
          },
          "completed_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when processing completed, or null."
          },
          "cancelled_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was cancelled, or null."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "scheduler": {
            "$ref": "#/components/schemas/SchedulerResource"
          }
        },
        "required": [
          "id",
          "user_id",
          "scheduler_id",
          "color",
          "model_id",
          "model_type",
          "starts_at",
          "ends_at",
          "completed_at",
          "cancelled_at",
          "created_at",
          "updated_at"
        ],
        "title": "EventResource",
        "description": "A event record."
      },
      "ExportFacelessRequest": {
        "type": "object",
        "properties": {
          "transition": {
            "type": "string",
            "enum": [
              "slide-left",
              "slide-right",
              "slide-up",
              "slide-down",
              "scale-in",
              "scale-out",
              "zoom-in",
              "zoom-out",
              "rotate-left",
              "rotate-right",
              "fade",
              "none",
              "mixed",
              "pop",
              "dreamy",
              "swing",
              "spin-right",
              "spin-left",
              "swoosh-left",
              "swoosh-right",
              "glide-left",
              "glide-right",
              "drop",
              "tumble-left",
              "tumble-right",
              "float",
              "rise-left",
              "rise-right",
              "bounce",
              "flash",
              "crossfade",
              "blur-dissolve",
              "zoom-dissolve"
            ],
            "description": "Transition slug applied between scenes (see faceless options)."
          },
          "overlay": {
            "type": "string",
            "enum": [
              "none",
              "vhs",
              "rain",
              "glitch",
              "dust",
              "sparkling-gold",
              "spark-effect",
              "abstract-particles"
            ],
            "description": "Overlay style slug applied over the video (see faceless options)."
          },
          "sfx": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "none",
              "whoosh"
            ],
            "description": "Sound-effect slug applied to the video (see faceless options)."
          },
          "volume": {
            "type": "string",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Background-music volume level: \"low\", \"medium\", or \"high\"."
          },
          "music_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background music track (media id)."
          },
          "transcriptions": {
            "type": "array",
            "items": {
              "type": "array",
              "items": {
                "type": "string"
              },
              "minItems": 1
            },
            "description": "Per-scene transcription overrides keyed by scene."
          },
          "captions": {
            "type": "object",
            "properties": {
              "font_family": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Caption font family slug (see faceless options)."
              },
              "font_url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri",
                "description": "URL of a custom font file to use for captions."
              },
              "font_color": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
              },
              "position": {
                "type": "string",
                "enum": [
                  "top",
                  "bottom",
                  "center"
                ],
                "description": "On-screen position slug (e.g. \"bottom\", \"center\", \"top\")."
              },
              "effect": {
                "type": "string",
                "enum": [
                  "karaoke",
                  "highlight",
                  "fade",
                  "bounce",
                  "slide",
                  "enlarge"
                ],
                "description": "Caption effect slug applied to on-screen text (see faceless options)."
              }
            },
            "description": "Caption styling options (font, color, position, effect)."
          },
          "watermark": {
            "type": "object",
            "properties": {
              "id": {
                "type": [
                  "integer",
                  "null"
                ],
                "description": "Unique numeric identifier of the resource."
              },
              "position": {
                "type": [
                  "string",
                  "null"
                ],
                "enum": [
                  "top-left",
                  "top-center",
                  "top-right",
                  "middle-left",
                  "middle-center",
                  "middle-right",
                  "bottom-left",
                  "bottom-center",
                  "bottom-right",
                  "none"
                ],
                "description": "On-screen position slug (e.g. \"bottom\", \"center\", \"top\")."
              },
              "opacity": {
                "type": [
                  "integer",
                  "null"
                ],
                "minimum": 0,
                "maximum": 100,
                "description": "Watermark opacity as a percentage (0–100)."
              }
            },
            "description": "Watermark image and placement options."
          }
        },
        "title": "ExportFacelessRequest",
        "description": "A export Faceless Request record."
      },
      "Faceless": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "type": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FacelessType"
              },
              {
                "type": "null"
              }
            ],
            "description": "Type/category discriminator for the resource."
          },
          "video_id": {
            "type": "integer",
            "description": "Identifier of the parent video."
          },
          "voice_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the narration voice (see faceless options)."
          },
          "background_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background asset (see faceless options)."
          },
          "music_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background music track (media id)."
          },
          "watermark_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the watermark asset (must be owned by the caller)."
          },
          "estimated_duration": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Estimated rendered duration in seconds."
          },
          "is_transcribed": {
            "type": "boolean",
            "description": "Whether the video audio has been transcribed."
          },
          "genre_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the genre/style (see faceless options)."
          },
          "character_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the consistent character (see faceless options)."
          },
          "script": {
            "type": [
              "string",
              "null"
            ],
            "description": "Narration script text for the video."
          },
          "hash": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Opaque content hash used for change detection."
          },
          "options": {
            "type": [
              "string",
              "null"
            ],
            "description": "Additional generation options for the faceless video."
          },
          "batch": {
            "type": [
              "string",
              "null"
            ],
            "description": "Identifier grouping records created in the same batch operation."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          },
          "brief": {
            "type": [
              "string",
              "null"
            ],
            "description": "Short brief or summary text for the content."
          },
          "image_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "clip_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          }
        },
        "required": [
          "id",
          "user_id",
          "type",
          "video_id",
          "voice_id",
          "background_id",
          "music_id",
          "watermark_id",
          "estimated_duration",
          "is_transcribed",
          "genre_id",
          "character_id",
          "script",
          "hash",
          "options",
          "batch",
          "created_at",
          "updated_at",
          "brief",
          "image_engine_id",
          "clip_engine_id"
        ],
        "title": "Faceless",
        "description": "A faceless record."
      },
      "FacelessPresetResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "user_id": {
            "type": "string",
            "description": "Identifier of the owning user."
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "music_id": {
            "type": "string",
            "description": "Identifier of the background music track (media id)."
          },
          "music": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "music_category_id": {
            "type": "string",
            "description": "Identifier of the music category tag."
          },
          "music_category": {
            "$ref": "#/components/schemas/TagResource"
          },
          "voice_id": {
            "type": "string",
            "description": "Identifier of the narration voice (see faceless options)."
          },
          "voice": {
            "$ref": "#/components/schemas/VoiceResource"
          },
          "background_id": {
            "type": "string",
            "description": "Identifier of the background asset (see faceless options)."
          },
          "background": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "resource_id": {
            "type": "string",
            "description": "Identifier of the destination resource/folder."
          },
          "resource": {
            "$ref": "#/components/schemas/FolderWithContentResource"
          },
          "genre_id": {
            "type": "string",
            "description": "Identifier of the genre/style (see faceless options)."
          },
          "genre": {
            "$ref": "#/components/schemas/GenreResource"
          },
          "image_engine_id": {
            "type": "string",
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "image_engine": {
            "$ref": "#/components/schemas/EngineResource"
          },
          "clip_engine_id": {
            "type": "string",
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          },
          "clip_engine": {
            "$ref": "#/components/schemas/EngineResource"
          },
          "language": {
            "type": "string",
            "description": "Language of the content (e.g. \"english\")."
          },
          "font_family": {
            "type": "string",
            "description": "Caption font family slug (see faceless options)."
          },
          "font_color": {
            "type": "string",
            "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
          },
          "position": {
            "type": "string",
            "description": "On-screen position slug (e.g. \"bottom\", \"center\", \"top\")."
          },
          "caption_animation": {
            "type": "string",
            "description": "Caption animation/effect slug applied to on-screen captions."
          },
          "duration": {
            "type": "integer",
            "description": "Target video length in seconds."
          },
          "orientation": {
            "type": "string",
            "description": "Video orientation. One of \"landscape\", \"portrait\", or \"square\"."
          },
          "transition": {
            "type": "string",
            "description": "Transition slug applied between scenes (see faceless options)."
          },
          "animation": {
            "type": "string",
            "description": "Per-image motion effect slug (e.g. \"zoom-in\"). See faceless options."
          },
          "volume": {
            "type": "string",
            "description": "Background-music volume level: \"low\", \"medium\", or \"high\"."
          },
          "sfx": {
            "type": "string",
            "description": "Sound-effect slug applied to the video (see faceless options)."
          },
          "overlay": {
            "type": "string",
            "description": "Overlay style slug applied over the video (see faceless options)."
          },
          "watermark_id": {
            "type": "string",
            "description": "Identifier of the watermark asset (must be owned by the caller)."
          },
          "watermark": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "watermark_position": {
            "type": "string",
            "description": "Watermark placement slug (e.g. \"bottom-right\")."
          },
          "watermark_opacity": {
            "type": "string",
            "description": "Watermark opacity as a percentage (0–100)."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "user_id",
          "music_id",
          "music_category_id",
          "voice_id",
          "background_id",
          "resource_id",
          "genre_id",
          "image_engine_id",
          "clip_engine_id",
          "language",
          "font_family",
          "font_color",
          "position",
          "caption_animation",
          "duration",
          "orientation",
          "transition",
          "animation",
          "volume",
          "sfx",
          "overlay",
          "watermark_id",
          "watermark_position",
          "watermark_opacity",
          "created_at",
          "updated_at"
        ],
        "title": "FacelessPresetResource",
        "description": "A faceless Preset record."
      },
      "FacelessResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "string",
            "description": "Identifier of the owning user."
          },
          "video_id": {
            "type": "string",
            "description": "Identifier of the parent video."
          },
          "voice_id": {
            "type": "string",
            "description": "Identifier of the narration voice (see faceless options)."
          },
          "music_id": {
            "type": "string",
            "description": "Identifier of the background music track (media id)."
          },
          "background_id": {
            "type": "string",
            "description": "Identifier of the background asset (see faceless options)."
          },
          "estimated_duration": {
            "type": "string",
            "description": "Estimated rendered duration in seconds."
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "genre_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the selected genre/style (see faceless options). Matches `genre.id` when the genre relation is loaded."
          },
          "genre": {
            "allOf": [
              {
                "$ref": "#/components/schemas/GenreResource"
              }
            ],
            "description": "The selected genre/style, embedded when the `genre` relation is loaded; otherwise omitted."
          },
          "script": {
            "type": "string",
            "description": "Narration script text for the video."
          },
          "hash": {
            "type": "string",
            "description": "Opaque content hash used for change detection."
          },
          "options": {
            "type": "string",
            "description": "Additional generation options for the faceless video."
          },
          "is_transcribed": {
            "type": "string",
            "description": "Whether the video audio has been transcribed."
          },
          "watermark_id": {
            "type": "string",
            "description": "Identifier of the watermark asset (must be owned by the caller)."
          },
          "watermark": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "character_id": {
            "type": "string",
            "description": "Identifier of the consistent character (see faceless options)."
          },
          "character": {
            "$ref": "#/components/schemas/CharacterResource"
          },
          "image_engine_id": {
            "type": "string",
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "clip_engine_id": {
            "type": "string",
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          },
          "engines": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "minItems": 0,
            "maxItems": 0,
            "additionalItems": false,
            "description": "Available inference engines."
          },
          "video": {
            "$ref": "#/components/schemas/VideoResource"
          },
          "generator": {
            "$ref": "#/components/schemas/GeneratorResource"
          },
          "background": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "music": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "voice": {
            "$ref": "#/components/schemas/VoiceResource"
          },
          "trackers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TrackerResource"
            },
            "description": "Tracking records for the resource."
          },
          "assets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetResource"
            },
            "description": "Ordered list of media assets used to compose the video."
          },
          "captions": {
            "$ref": "#/components/schemas/CaptionResource"
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "video_id",
          "voice_id",
          "music_id",
          "background_id",
          "estimated_duration",
          "type",
          "script",
          "hash",
          "options",
          "is_transcribed",
          "watermark_id",
          "character_id",
          "image_engine_id",
          "clip_engine_id",
          "engines",
          "created_at",
          "updated_at"
        ],
        "title": "FacelessResource",
        "description": "A faceless record."
      },
      "FacelessType": {
        "type": "string",
        "enum": [
          "b-roll",
          "url-based",
          "ai-visuals",
          "ai-clips"
        ],
        "title": "FacelessType",
        "description": "A faceless Type record."
      },
      "FolderResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hex color value (e.g. \"#FFFFFF\")."
          },
          "is_bookmarked": {
            "type": "boolean",
            "description": "Whether the caller has bookmarked this record."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "name",
          "color",
          "is_bookmarked",
          "created_at",
          "updated_at"
        ],
        "title": "FolderResource",
        "description": "A folder record."
      },
      "FolderWithContentResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "model_id": {
            "type": "integer",
            "description": "Identifier of the related model the media is attached to."
          },
          "model_type": {
            "type": "string",
            "description": "Class/type of the related model the media is attached to."
          },
          "model": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/FolderResource"
              },
              {
                "$ref": "#/components/schemas/VideoResource"
              },
              {
                "type": "null"
              }
            ],
            "description": "Underlying model name used to generate the resource."
          },
          "is_root": {
            "type": "boolean",
            "description": "Whether the folder is a top-level (root) folder."
          },
          "parent": {
            "$ref": "#/components/schemas/FolderWithContentResource"
          },
          "children": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FolderWithContentResource"
            },
            "description": "Direct child records nested under this one."
          },
          "ancestors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FolderWithContentResource"
            },
            "description": "Parent folders in the hierarchy, ordered from root to direct parent."
          },
          "descendants": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FolderWithContentResource"
            },
            "description": "All nested descendant records beneath this one."
          },
          "children_count": {
            "type": "string",
            "description": "Number of direct child records."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "model_id",
          "model_type",
          "is_root",
          "children_count",
          "created_at",
          "updated_at"
        ],
        "title": "FolderWithContentResource",
        "description": "A folder With Content record."
      },
      "GenerateFacelessScriptRequest": {
        "type": "object",
        "properties": {
          "style": {
            "type": "string",
            "maxLength": 255,
            "description": "Required — narrative style for the generated script (free-form text, max 255 chars). Examples: educational, storytelling, listicle, conversational, motivational."
          },
          "tone": {
            "type": "string",
            "maxLength": 255,
            "description": "Tone of voice for generated content (e.g. \"professional\")."
          },
          "language": {
            "type": "string",
            "maxLength": 255,
            "description": "Language of the content (e.g. \"english\")."
          },
          "topic": {
            "type": "string",
            "maxLength": 500,
            "description": "Topic or subject of the content."
          },
          "duration": {
            "type": "integer",
            "description": "Target length of the generated script in seconds. Must be one of 30, 60, 180, 300, 600, or 900.",
            "enum": [
              30,
              60,
              180,
              300,
              600,
              900
            ]
          }
        },
        "required": [
          "style",
          "tone",
          "language",
          "topic",
          "duration"
        ],
        "title": "GenerateFacelessScriptRequest",
        "description": "A generate Faceless Script Request record."
      },
      "GeneratorResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "model_id": {
            "type": "integer",
            "description": "Identifier of the related model the media is attached to."
          },
          "model_type": {
            "type": "string",
            "description": "Class/type of the related model the media is attached to."
          },
          "topic": {
            "type": [
              "string",
              "null"
            ],
            "description": "Topic or subject of the content."
          },
          "length": {
            "type": [
              "string",
              "null"
            ],
            "description": "Length of the content."
          },
          "tone": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tone of voice for generated content (e.g. \"professional\")."
          },
          "style": {
            "type": [
              "string",
              "null"
            ],
            "description": "Style label applied to generation."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Language of the content (e.g. \"english\")."
          },
          "context": {
            "type": "array",
            "items": {},
            "description": "Additional contextual metadata for the resource."
          },
          "output": {
            "type": [
              "string",
              "null"
            ],
            "description": "Generated output payload."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "model_id",
          "model_type",
          "topic",
          "length",
          "tone",
          "style",
          "language",
          "context",
          "output",
          "created_at",
          "updated_at"
        ],
        "title": "GeneratorResource",
        "description": "A generator record."
      },
      "Genre": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "character_prompt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Prompt describing the consistent character's appearance."
          },
          "meta": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Pagination and listing metadata."
          },
          "active": {
            "type": "integer",
            "description": "Whether the record is currently active and selectable."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based ordering position within its collection."
          },
          "consistent_character": {
            "type": "boolean",
            "description": "Whether the genre supports a consistent character across scenes."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "character_prompt",
          "meta",
          "active",
          "order",
          "consistent_character",
          "created_at",
          "updated_at"
        ],
        "title": "Genre",
        "description": "A genre record."
      },
      "GenreResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "active": {
            "type": "integer",
            "description": "Whether the record is currently active and selectable."
          },
          "consistent_character": {
            "type": "boolean",
            "description": "Whether the genre supports a consistent character across scenes."
          },
          "has_prompt": {
            "type": "boolean",
            "description": "Whether the genre accepts a custom image prompt."
          },
          "preview": {
            "type": "array",
            "items": {},
            "description": "URL of a preview image or clip for the resource."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "active",
          "consistent_character",
          "has_prompt",
          "preview",
          "created_at",
          "updated_at"
        ],
        "title": "GenreResource",
        "description": "A genre record."
      },
      "IdeaResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "keyword_id": {
            "type": "integer",
            "description": "Identifier of the keyword."
          },
          "keyword": {
            "$ref": "#/components/schemas/KeywordResource"
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Title of the resource."
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL-friendly unique identifier for the resource."
          },
          "trend": {
            "type": [
              "number",
              "null"
            ],
            "description": "Trend direction (e.g. \"up\", \"down\", \"flat\")."
          },
          "country": {
            "type": [
              "string",
              "null"
            ],
            "description": "Two-letter country code (ISO 3166-1 alpha-2)."
          },
          "currency": {
            "type": [
              "string",
              "null"
            ],
            "description": "Three-letter currency code (ISO 4217, e.g. \"USD\")."
          },
          "locale": {
            "type": [
              "string",
              "null"
            ],
            "description": "BCP-47 locale code (e.g. \"en-US\")."
          },
          "volume": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Background-music volume level: \"low\", \"medium\", or \"high\"."
          },
          "cpc": {
            "type": [
              "number",
              "null"
            ],
            "description": "Estimated cost-per-click for the keyword, in USD."
          },
          "competition": {
            "type": [
              "number",
              "null"
            ],
            "description": "Keyword competition score (0–1, higher means more competitive)."
          },
          "competition_label": {
            "type": [
              "string",
              "null"
            ],
            "description": "Human-readable competition band (e.g. \"LOW\", \"MEDIUM\", \"HIGH\")."
          },
          "total_results": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Total number of results matching the query."
          },
          "trends": {
            "type": [
              "string",
              "null"
            ],
            "description": "Time-series trend data points."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "keyword_id",
          "title",
          "slug",
          "trend",
          "country",
          "currency",
          "locale",
          "volume",
          "cpc",
          "competition",
          "competition_label",
          "total_results",
          "trends",
          "created_at",
          "updated_at"
        ],
        "title": "IdeaResource",
        "description": "A idea record."
      },
      "KeywordResource": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL-friendly unique identifier for the resource."
          },
          "network": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/Networks"
              },
              {
                "type": "null"
              }
            ],
            "description": "Social network identifier (e.g. \"tiktok\", \"youtube\")."
          },
          "ideas_count": {
            "type": "integer",
            "description": "Number of ideas discovered for this keyword."
          },
          "searched_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when this keyword was last discovered (the search that populated its ideas)."
          }
        },
        "required": [
          "name",
          "slug",
          "network",
          "ideas_count",
          "searched_at"
        ],
        "title": "KeywordResource",
        "description": "A keyword record."
      },
      "ManageFacelessPresetRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the preset. **Required when creating** (`POST /presets/faceless`); **optional when updating** (`PATCH /presets/faceless/{preset}`) — OpenAPI cannot make `required` depend on the HTTP verb, so it is listed in `required` here and the create-only rule is documented in this note and the create operation's description."
          },
          "volume": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "Background-music volume level: \"low\", \"medium\", or \"high\"."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "Language of the content (e.g. \"english\")."
          },
          "font_color": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "Caption font color — either the literal `default` or a hex value (3- or 6-digit, e.g. `#ffffff` or `#fff`).",
            "pattern": "^(default|#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}))$",
            "example": "#ffffff"
          },
          "font_family": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "Caption font family slug (see faceless options)."
          },
          "duration": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Target video length in seconds — a positive number of seconds.",
            "minimum": 1
          },
          "orientation": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "landscape",
              "portrait",
              "square"
            ],
            "maxLength": 26,
            "description": "Video orientation. One of \"landscape\", \"portrait\", or \"square\"."
          },
          "position": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "On-screen position slug (e.g. \"bottom\", \"center\", \"top\")."
          },
          "caption_animation": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 50,
            "description": "Caption animation/effect slug applied to on-screen captions."
          },
          "sfx": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "none",
              "whoosh"
            ],
            "maxLength": 50,
            "description": "Sound-effect slug applied to the video (see faceless options)."
          },
          "music_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background music track (media id)."
          },
          "music_category_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the music category tag."
          },
          "background_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the background asset (see faceless options)."
          },
          "genre_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the genre/style (see faceless options)."
          },
          "voice_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the narration voice (see faceless options)."
          },
          "transition": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "slide-left",
              "slide-right",
              "slide-up",
              "slide-down",
              "scale-in",
              "scale-out",
              "zoom-in",
              "zoom-out",
              "rotate-left",
              "rotate-right",
              "fade",
              "none",
              "mixed",
              "pop",
              "dreamy",
              "swing",
              "spin-right",
              "spin-left",
              "swoosh-left",
              "swoosh-right",
              "glide-left",
              "glide-right",
              "drop",
              "tumble-left",
              "tumble-right",
              "float",
              "rise-left",
              "rise-right",
              "bounce",
              "flash",
              "crossfade",
              "blur-dissolve",
              "zoom-dissolve"
            ],
            "maxLength": 50,
            "description": "Transition slug applied between scenes (see faceless options)."
          },
          "animation": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "pan-in",
              "pan-out",
              "pan-left",
              "pan-right",
              "pan-up",
              "pan-down",
              "rotate-left-in",
              "rotate-right-in",
              "float",
              "none",
              "mixed"
            ],
            "maxLength": 50,
            "description": "Per-image motion effect slug (e.g. \"zoom-in\"). See faceless options."
          },
          "overlay": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "none",
              "vhs",
              "rain",
              "glitch",
              "dust",
              "sparkling-gold",
              "spark-effect",
              "abstract-particles"
            ],
            "maxLength": 50,
            "description": "Overlay style slug applied over the video (see faceless options)."
          },
          "watermark_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the watermark asset (must be owned by the caller)."
          },
          "watermark_position": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "top-left",
              "top-center",
              "top-right",
              "middle-left",
              "middle-center",
              "middle-right",
              "bottom-left",
              "bottom-center",
              "bottom-right",
              "none"
            ],
            "description": "Watermark placement slug (e.g. \"bottom-right\")."
          },
          "watermark_opacity": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0,
            "maximum": 100,
            "description": "Watermark opacity as a percentage (0–100)."
          },
          "resource_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the destination resource/folder."
          },
          "image_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "clip_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          }
        },
        "title": "ManageFacelessPresetRequest",
        "description": "A manage Faceless Preset Request record. `name` is required when creating a preset (`POST /presets/faceless`) and optional when updating one (`PATCH /presets/faceless/{preset}`); all other fields are optional in both cases.",
        "required": [
          "name"
        ]
      },
      "MeResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "email": {
            "type": "string",
            "description": "The user's email address."
          },
          "email_verified": {
            "type": "boolean",
            "description": "Whether the user has verified their email address."
          },
          "credits": {
            "type": "object",
            "properties": {
              "remaining": {
                "type": "integer",
                "description": "Remaining monthly credits available to spend."
              },
              "total": {
                "type": "integer",
                "description": "Total monthly credit allotment."
              },
              "extra": {
                "type": "integer",
                "description": "Extra (top-up) credits available beyond the monthly allotment."
              }
            },
            "required": [
              "remaining",
              "total",
              "extra"
            ],
            "description": "Credit balance summary for the user."
          },
          "subscription": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "exists": {
                    "type": "boolean",
                    "description": "Whether a subscription exists for the user."
                  },
                  "active": {
                    "type": "string",
                    "description": "Whether the record is currently active and selectable."
                  },
                  "trial": {
                    "type": "string",
                    "description": "Whether the subscription is currently in a trial period."
                  },
                  "plan": {
                    "type": "string",
                    "description": "Name of the user's current subscription plan, or null."
                  },
                  "ends_at": {
                    "type": "string",
                    "description": "ISO-8601 timestamp marking the end of the period."
                  }
                },
                "required": [
                  "exists",
                  "active",
                  "trial",
                  "plan",
                  "ends_at"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "exists": {
                    "type": "boolean",
                    "description": "Whether a subscription exists for the user."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "Whether the record is currently active and selectable."
                  },
                  "trial": {
                    "type": "boolean",
                    "description": "Whether the subscription is currently in a trial period."
                  },
                  "plan": {
                    "type": "null",
                    "description": "Name of the user's current subscription plan, or null."
                  },
                  "ends_at": {
                    "type": "null",
                    "description": "ISO-8601 timestamp marking the end of the period."
                  }
                },
                "required": [
                  "exists",
                  "active",
                  "trial",
                  "plan",
                  "ends_at"
                ]
              }
            ],
            "description": "High-level subscription state for the user."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "email_verified",
          "credits",
          "subscription",
          "created_at",
          "updated_at"
        ],
        "title": "MeResource",
        "description": "A me record."
      },
      "MediaResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "file_name": {
            "type": "string",
            "description": "Stored file name of the media asset."
          },
          "uuid": {
            "type": [
              "string",
              "null"
            ],
            "description": "Globally unique UUID for the resource."
          },
          "collection": {
            "type": "string",
            "description": "Media-library collection the file belongs to."
          },
          "model_id": {
            "type": "integer",
            "description": "Identifier of the related model the media is attached to."
          },
          "model_type": {
            "type": "string",
            "description": "Class/type of the related model the media is attached to."
          },
          "original_url": {
            "type": "string",
            "description": "Permanent source URL of the media file."
          },
          "download_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Temporary signed URL to download the media file."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based ordering position within its collection."
          },
          "mime_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "MIME type of the media file (e.g. \"video/mp4\")."
          },
          "extension": {
            "type": "string",
            "description": "File extension (e.g. \"mp4\", \"png\")."
          },
          "size": {
            "type": "integer",
            "description": "File size in bytes."
          },
          "conversions": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": {},
            "description": "Number of tracked conversions."
          },
          "custom_properties": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Arbitrary key/value metadata attached to the media file."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "name",
          "file_name",
          "uuid",
          "collection",
          "model_id",
          "model_type",
          "original_url",
          "download_url",
          "order",
          "mime_type",
          "extension",
          "size",
          "conversions",
          "custom_properties",
          "created_at",
          "updated_at"
        ],
        "title": "MediaResource",
        "description": "A media record."
      },
      "Networks": {
        "type": "string",
        "enum": [
          "google",
          "google-trends",
          "youtube",
          "instagram",
          "twitter",
          "bing",
          "pinterest",
          "tiktok"
        ],
        "title": "Networks",
        "description": "A networks record."
      },
      "PublicationResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the resource."
          },
          "scheduled_at": {
            "type": "string",
            "description": "ISO-8601 timestamp the post is scheduled to publish, or null."
          },
          "draft": {
            "type": "boolean",
            "description": "Whether the record is an unpublished draft."
          },
          "temporary": {
            "type": "boolean",
            "description": "Whether the resource is temporary and may be purged."
          },
          "video_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the parent video."
          },
          "script": {
            "type": [
              "string",
              "null"
            ],
            "description": "Narration script text for the video."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicationResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "accounts": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AccountPublicationResource"
            },
            "description": "Connected social accounts associated with this resource."
          },
          "video": {
            "$ref": "#/components/schemas/VideoResource"
          },
          "event": {
            "$ref": "#/components/schemas/EventResource"
          },
          "aggregate": {
            "type": "object",
            "properties": {
              "views-count": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer",
                    "enum": [
                      0
                    ]
                  }
                ],
                "description": "Number of views on the published post."
              },
              "likes-count": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer",
                    "enum": [
                      0
                    ]
                  }
                ],
                "description": "Number of likes on the published post."
              },
              "comments-count": {
                "anyOf": [
                  {
                    "type": "string"
                  },
                  {
                    "type": "integer",
                    "enum": [
                      0
                    ]
                  }
                ],
                "description": "Number of comments on the published post."
              }
            },
            "required": [
              "views-count",
              "likes-count",
              "comments-count"
            ],
            "description": "Aggregated metric totals for the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "draft",
          "temporary",
          "video_id",
          "script",
          "media",
          "aggregate",
          "created_at",
          "updated_at"
        ],
        "title": "PublicationResource",
        "description": "A publication record."
      },
      "SceneResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "uuid": {
            "type": "string",
            "description": "Globally unique UUID for the resource."
          },
          "video_prompt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Prompt used to generate the video clip."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based ordering position within its collection."
          },
          "role": {
            "type": [
              "string",
              "null"
            ],
            "description": "The user's role within the account."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SceneStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Error message describing why processing failed, if any."
          },
          "first_frame_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the first-frame asset."
          },
          "first_frame": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "last_frame_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the last-frame asset."
          },
          "last_frame": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "clip_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the generated clip."
          },
          "clip": {
            "$ref": "#/components/schemas/AssetResource"
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "uuid",
          "video_prompt",
          "order",
          "role",
          "status",
          "error",
          "first_frame_id",
          "last_frame_id",
          "clip_id",
          "created_at",
          "updated_at"
        ],
        "title": "SceneResource",
        "description": "A scene record."
      },
      "SceneStatus": {
        "type": "string",
        "enum": [
          "draft",
          "clip:queued",
          "clip:generating",
          "clip:completed",
          "clip:failed"
        ],
        "title": "SceneStatus",
        "description": "A scene Status record."
      },
      "SchedulerResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "idea_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the linked content idea."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Title of the resource."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hex color value (e.g. \"#FFFFFF\")."
          },
          "topic": {
            "type": [
              "string",
              "null"
            ],
            "description": "Topic or subject of the content."
          },
          "status": {
            "$ref": "#/components/schemas/SchedulerStatus"
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "source": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SchedulerSource"
              },
              {
                "type": "null"
              }
            ],
            "description": "Source/origin of the resource."
          },
          "options": {
            "type": [
              "string",
              "null"
            ],
            "description": "Additional generation options for the faceless video."
          },
          "details": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "hours": {
                    "type": "array",
                    "items": {},
                    "description": "Number of hours in the period."
                  },
                  "days": {
                    "type": "integer",
                    "description": "Number of days in the period."
                  },
                  "occurrences": {
                    "type": "array",
                    "items": {},
                    "description": "Number of times the event occurred."
                  },
                  "times_per_day": {
                    "type": "integer",
                    "description": "Number of scheduled occurrences per day."
                  },
                  "start_date": {
                    "description": "ISO-8601 start date of the period."
                  },
                  "weekdays": {
                    "description": "Days of the week the schedule runs on."
                  }
                },
                "required": [
                  "hours",
                  "days",
                  "occurrences",
                  "times_per_day",
                  "start_date",
                  "weekdays"
                ]
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                },
                "minItems": 0,
                "maxItems": 0,
                "additionalItems": false
              }
            ],
            "description": "Detailed breakdown for the resource."
          },
          "character_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the consistent character (see faceless options)."
          },
          "metadata": {
            "type": "object",
            "properties": {
              "ai_labels": {
                "description": "Whether AI-content disclosure labels are applied on publish."
              },
              "custom_description": {
                "description": "Custom caption/description applied to published posts."
              }
            },
            "required": [
              "ai_labels",
              "custom_description"
            ],
            "description": "Additional metadata for the resource."
          },
          "paused_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was paused, or null."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          },
          "voice": {
            "$ref": "#/components/schemas/VoiceResource"
          },
          "music": {
            "$ref": "#/components/schemas/MediaResource"
          },
          "character": {
            "$ref": "#/components/schemas/CharacterResource"
          },
          "events": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EventResource"
            },
            "description": "List of related events."
          },
          "videos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VideoResource"
            },
            "description": "Videos associated with the resource."
          },
          "social_channels": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SocialChannelResource"
            },
            "description": "Connected social channels for the account."
          },
          "occurrences": {
            "type": "object",
            "description": "Number of times the event occurred."
          }
        },
        "required": [
          "id",
          "user_id",
          "idea_id",
          "title",
          "color",
          "topic",
          "status",
          "type",
          "source",
          "options",
          "details",
          "character_id",
          "metadata",
          "paused_at",
          "created_at",
          "updated_at"
        ],
        "title": "SchedulerResource",
        "description": "A scheduler record."
      },
      "SchedulerSource": {
        "type": "string",
        "enum": [
          "ai",
          "csv",
          "manual"
        ],
        "title": "SchedulerSource",
        "description": "A scheduler Source record."
      },
      "SchedulerStatus": {
        "type": "string",
        "enum": [
          "draft",
          "failed",
          "paused",
          "writing",
          "deleted",
          "completed",
          "reviewing",
          "scheduled",
          "publishing",
          "generating"
        ],
        "title": "SchedulerStatus",
        "description": "A scheduler Status record."
      },
      "SocialAccountEnum": {
        "type": "integer",
        "enum": [
          0,
          1,
          2,
          3,
          4,
          5,
          6,
          7
        ],
        "title": "SocialAccountEnum",
        "description": "A social Account Enum record."
      },
      "SocialChannelResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "provider": {
            "type": "string",
            "description": "Upstream provider that fulfilled the resource."
          },
          "provider_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider-side identifier for the resource."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the resource."
          },
          "avatar": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL of the user's avatar image, if set."
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "icon": {
            "type": "string",
            "description": "Icon URL or identifier for the resource."
          },
          "needs_reauth": {
            "type": "boolean",
            "description": "Whether the connected account must be re-authenticated."
          },
          "expires_in": {
            "type": "integer",
            "const": 94608000,
            "description": "Seconds until the resource expires."
          },
          "errors": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Map of field name to validation error messages."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "provider",
          "provider_id",
          "name",
          "avatar",
          "type",
          "icon",
          "needs_reauth",
          "expires_in",
          "errors",
          "created_at",
          "updated_at"
        ],
        "title": "SocialChannelResource",
        "description": "A social Channel record."
      },
      "StoryboardResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "uuid": {
            "type": "string",
            "description": "Globally unique UUID for the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/StoryboardStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "is_locked": {
            "type": "boolean",
            "description": "Whether the record is locked from editing."
          },
          "prompt": {
            "type": [
              "string",
              "null"
            ],
            "description": "Generation prompt text."
          },
          "duration": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Target video length in seconds."
          },
          "settings": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Configuration settings for the resource."
          },
          "video_id": {
            "type": "integer",
            "description": "Identifier of the parent video."
          },
          "video": {
            "$ref": "#/components/schemas/VideoResource"
          },
          "clip_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-video (clip) engine (see faceless options)."
          },
          "clip_engine": {
            "$ref": "#/components/schemas/EngineResource"
          },
          "image_engine_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the text-to-image engine (see faceless options)."
          },
          "image_engine": {
            "$ref": "#/components/schemas/EngineResource"
          },
          "scenes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SceneResource"
            },
            "description": "Ordered scenes that compose the video."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "uuid",
          "user_id",
          "status",
          "is_locked",
          "prompt",
          "duration",
          "settings",
          "video_id",
          "clip_engine_id",
          "image_engine_id",
          "created_at",
          "updated_at"
        ],
        "title": "StoryboardResource",
        "description": "A storyboard record."
      },
      "StoryboardStatus": {
        "type": "string",
        "enum": [
          "wizard",
          "processing",
          "generating:prompts",
          "generating:subjects",
          "generating:hero",
          "generating:frames",
          "formatting:prompts",
          "ready",
          "failed"
        ],
        "title": "StoryboardStatus",
        "description": "A storyboard Status record."
      },
      "SubscriptionProvider": {
        "type": "integer",
        "enum": [
          1,
          2,
          3,
          4
        ],
        "title": "SubscriptionProvider",
        "description": "A subscription Provider record."
      },
      "SurveyAnswerResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "answer": {
            "type": [
              "string",
              "null"
            ],
            "description": "The answer text submitted for the survey question."
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "answer",
          "type",
          "created_at",
          "updated_at"
        ],
        "title": "SurveyAnswerResource",
        "description": "A survey Answer record."
      },
      "TagResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "color": {
            "type": [
              "string",
              "null"
            ],
            "description": "Hex color value (e.g. \"#FFFFFF\")."
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "templates": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TemplateResource"
            },
            "description": "Templates associated with the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "name",
          "slug",
          "color",
          "created_at",
          "updated_at"
        ],
        "title": "TagResource",
        "description": "A tag record."
      },
      "TemplateResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "string",
            "description": "Identifier of the owning user."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "description": {
            "type": "string",
            "description": "Human-readable description of the resource."
          },
          "type": {
            "type": "string",
            "description": "Type/category discriminator for the resource."
          },
          "metadata": {
            "type": "string",
            "description": "Additional metadata for the resource."
          },
          "source": {
            "type": "string",
            "description": "Source/origin of the resource."
          },
          "is_active": {
            "type": "string",
            "description": "Whether the record is active."
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TagResource"
            },
            "description": "Tags associated with the resource."
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "name",
          "slug",
          "description",
          "type",
          "metadata",
          "source",
          "is_active",
          "created_at",
          "updated_at"
        ],
        "title": "TemplateResource",
        "description": "A template record."
      },
      "TrackerResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "trackable_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the tracked entity."
          },
          "trackable_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Class/type of the tracked entity."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "count": {
            "type": "integer",
            "description": "Count value for the metric."
          },
          "limit": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Maximum number of items returned."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "trackable_id",
          "trackable_type",
          "name",
          "count",
          "limit",
          "created_at",
          "updated_at"
        ],
        "title": "TrackerResource",
        "description": "A tracker record."
      },
      "UpdateFacelessRequest": {
        "type": "object",
        "description": "v2 public-API input contract for updating a faceless video.\nInherits v1 rules; override here when the public contract must diverge.",
        "properties": {
          "voice_id": {
            "type": "integer",
            "description": "Optional — identifier of the narration voice (see faceless options). Omit voice entirely to render without narration."
          },
          "background_id": {
            "type": "integer",
            "description": "Optional — identifier of the background asset (see faceless options)."
          },
          "music_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Optional — identifier of the background music track (media id), or null to remove music."
          },
          "genre_id": {
            "type": "integer",
            "description": "Optional — identifier of the genre/style (see faceless options). Required at render time for the `ai-visuals` and `ai-clips` types."
          },
          "image_engine_id": {
            "type": "integer",
            "description": "Optional — identifier of the text-to-image engine (see faceless options). Relevant only for the `ai-visuals` and `ai-clips` types."
          },
          "clip_engine_id": {
            "type": "integer",
            "description": "Optional — identifier of the text-to-video (clip) engine (see faceless options). Relevant only for clip-based types."
          },
          "transition": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional — transition slug applied between scenes (see faceless options).",
            "enum": [
              "slide-left",
              "slide-right",
              "slide-up",
              "slide-down",
              "scale-in",
              "scale-out",
              "zoom-in",
              "zoom-out",
              "rotate-left",
              "rotate-right",
              "fade",
              "none",
              "mixed",
              "pop",
              "dreamy",
              "swing",
              "spin-right",
              "spin-left",
              "swoosh-left",
              "swoosh-right",
              "glide-left",
              "glide-right",
              "drop",
              "tumble-left",
              "tumble-right",
              "float",
              "rise-left",
              "rise-right",
              "bounce",
              "flash",
              "crossfade",
              "blur-dissolve",
              "zoom-dissolve"
            ]
          },
          "animation": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "pan-in",
              "pan-out",
              "pan-left",
              "pan-right",
              "pan-up",
              "pan-down",
              "rotate-left-in",
              "rotate-right-in",
              "float",
              "none",
              "mixed"
            ],
            "description": "Optional — per-image motion effect slug (e.g. \"pan-in\"). See faceless options."
          },
          "sfx": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "none",
              "whoosh"
            ],
            "description": "Optional — sound-effect slug applied to the video (see faceless options)."
          },
          "volume": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "description": "Optional — background-music volume level: \"low\", \"medium\", or \"high\"."
          },
          "script": {
            "type": "string",
            "description": "Optional — supply a full custom script to use verbatim instead of generating one. Provide this via PATCH /faceless/{faceless}; the script-generation step is then unnecessary."
          },
          "duration": {
            "type": "integer",
            "description": "Optional — target video length in seconds. Any positive integer; not restricted to the script-generation presets (those fixed values apply only to PUT /faceless/{faceless}/scripts)."
          },
          "aspect_ratio": {
            "type": "string",
            "enum": [
              "16:9",
              "9:16",
              "1:1"
            ],
            "description": "Optional — output aspect ratio: \"16:9\", \"9:16\", or \"1:1\"."
          },
          "captions": {
            "type": "object",
            "properties": {
              "font_family": {
                "type": "string",
                "description": "Caption font family slug (see faceless options)."
              },
              "font_color": {
                "type": "string",
                "description": "Caption font color as a hex value (e.g. \"#FFFFFF\")."
              },
              "font_url": {
                "type": [
                  "string",
                  "null"
                ],
                "format": "uri",
                "description": "URL of a custom font file to use for captions."
              },
              "position": {
                "type": "string",
                "enum": [
                  "top",
                  "bottom",
                  "center"
                ],
                "description": "On-screen position slug (e.g. \"bottom\", \"center\", \"top\")."
              }
            },
            "description": "Optional — caption styling. Only `font_family`, `font_color`, `font_url`, and `position` are honored on update; any other caption keys are ignored."
          }
        },
        "title": "UpdateFacelessRequest"
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "email": {
            "type": "string",
            "description": "The user's email address."
          },
          "provider_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider-side identifier for the resource."
          },
          "provider": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SocialAccountEnum"
              },
              {
                "type": "null"
              }
            ],
            "description": "Upstream provider that fulfilled the resource."
          },
          "active": {
            "type": "boolean",
            "description": "Whether the record is currently active and selectable."
          },
          "is_active": {
            "type": "integer",
            "description": "Whether the record is active."
          },
          "registration_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Code used during account registration, if any."
          },
          "promo_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Promotional code applied to the account."
          },
          "settings": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Configuration settings for the resource."
          },
          "notifications": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Notification preferences for the user."
          },
          "ad_tracking": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Whether ad/conversion tracking is enabled for this user."
          },
          "mailing_list": {
            "type": "integer",
            "description": "Whether the user opted into the marketing mailing list."
          },
          "email_verified_at": {
            "type": [
              "string",
              "null"
            ],
            "description": "ISO-8601 timestamp when the email was verified, or null."
          },
          "user_type": {
            "$ref": "#/components/schemas/UserType"
          },
          "locale": {
            "type": [
              "string",
              "null"
            ],
            "description": "BCP-47 locale code (e.g. \"en-US\")."
          },
          "timezone": {
            "type": [
              "string",
              "null"
            ],
            "description": "IANA timezone name (e.g. \"America/New_York\")."
          },
          "plan_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the subscription plan."
          },
          "subscription_ends_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp the subscription ends/renews, or null."
          },
          "trial_ends_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp the trial ends, or null."
          },
          "pm_last_four": {
            "type": [
              "string",
              "null"
            ],
            "description": "Last four digits of the saved payment method."
          },
          "pm_type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Saved payment-method type (e.g. \"visa\", \"mastercard\")."
          },
          "pm_exemption_code": {
            "type": [
              "string",
              "null"
            ],
            "description": "Tax/payment-method exemption code, if applicable."
          },
          "stripe_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stripe customer identifier (Stripe-billed users only)."
          },
          "apple_account_token": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque Apple App Store account token (Apple IAP users only)."
          },
          "subscription_provider": {
            "$ref": "#/components/schemas/SubscriptionProvider"
          },
          "signup_platform": {
            "type": [
              "string",
              "null"
            ],
            "description": "Platform the user signed up from (e.g. \"web\", \"ios\")."
          },
          "is_lifetime": {
            "type": "boolean",
            "description": "Whether the plan is a lifetime (non-recurring) deal."
          },
          "created_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "ISO-8601 timestamp when the record was last updated."
          },
          "remaining_credit_amount": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Remaining monthly credits available to spend."
          },
          "monthly_credit_amount": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Monthly credit allotment granted by the plan."
          },
          "extra_credits": {
            "type": "integer",
            "description": "Extra (top-up) credits available beyond the monthly allotment."
          }
        },
        "required": [
          "id",
          "name",
          "email",
          "provider_id",
          "provider",
          "active",
          "is_active",
          "registration_code",
          "promo_code",
          "settings",
          "notifications",
          "ad_tracking",
          "mailing_list",
          "email_verified_at",
          "user_type",
          "locale",
          "timezone",
          "plan_id",
          "subscription_ends_at",
          "trial_ends_at",
          "pm_last_four",
          "pm_type",
          "pm_exemption_code",
          "stripe_id",
          "apple_account_token",
          "subscription_provider",
          "signup_platform",
          "is_lifetime",
          "created_at",
          "updated_at",
          "remaining_credit_amount",
          "monthly_credit_amount",
          "extra_credits"
        ],
        "title": "User",
        "description": "A user record."
      },
      "UserResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "stripe_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Stripe customer identifier (Stripe-billed users only)."
          },
          "email": {
            "type": "string",
            "description": "The user's email address."
          },
          "email_verified": {
            "type": "boolean",
            "description": "Whether the user has verified their email address."
          },
          "credits": {
            "type": "object",
            "properties": {
              "remaining": {
                "type": "integer",
                "description": "Remaining monthly credits available to spend."
              },
              "total": {
                "type": "integer",
                "description": "Total monthly credit allotment."
              },
              "extra": {
                "type": "integer",
                "description": "Extra (top-up) credits available beyond the monthly allotment."
              }
            },
            "required": [
              "remaining",
              "total",
              "extra"
            ],
            "description": "Credit balance summary for the user."
          },
          "subscription": {
            "anyOf": [
              {
                "type": "object",
                "properties": {
                  "exists": {
                    "type": "boolean",
                    "description": "Whether a subscription exists for the user."
                  },
                  "trial": {
                    "type": "string",
                    "description": "Whether the subscription is currently in a trial period."
                  },
                  "active": {
                    "type": "string",
                    "description": "Whether the record is currently active and selectable."
                  },
                  "is_lifetime": {
                    "type": "boolean",
                    "description": "Whether the plan is a lifetime (non-recurring) deal."
                  },
                  "plan_id": {
                    "type": [
                      "integer",
                      "null"
                    ],
                    "description": "Identifier of the subscription plan."
                  },
                  "recurring": {
                    "type": "string",
                    "description": "Whether the subscription/charge recurs."
                  },
                  "subscription_status": {
                    "type": "string",
                    "description": "Current subscription status (e.g. \"active\", \"trialing\")."
                  },
                  "ends_at": {
                    "type": "string",
                    "description": "ISO-8601 timestamp marking the end of the period."
                  },
                  "purchase_token": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Google Play purchase token (Play Billing users only)."
                  },
                  "expires_at": {
                    "type": "string",
                    "description": "ISO-8601 timestamp when the resource expires, or null."
                  },
                  "original_transaction_id": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "description": "Original store transaction identifier (IAP users only)."
                  },
                  "auto_renewing": {
                    "type": "string",
                    "description": "Whether the store subscription is set to auto-renew."
                  }
                },
                "required": [
                  "exists",
                  "trial",
                  "active",
                  "is_lifetime",
                  "plan_id",
                  "recurring",
                  "subscription_status",
                  "ends_at",
                  "purchase_token",
                  "expires_at",
                  "original_transaction_id",
                  "auto_renewing"
                ]
              },
              {
                "type": "object",
                "properties": {
                  "exists": {
                    "type": "boolean",
                    "description": "Whether a subscription exists for the user."
                  },
                  "trial": {
                    "type": "boolean",
                    "description": "Whether the subscription is currently in a trial period."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "Whether the record is currently active and selectable."
                  },
                  "is_lifetime": {
                    "type": "boolean",
                    "description": "Whether the plan is a lifetime (non-recurring) deal."
                  }
                },
                "required": [
                  "exists",
                  "trial",
                  "active",
                  "is_lifetime"
                ]
              }
            ],
            "description": "High-level subscription state for the user."
          },
          "settings": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Configuration settings for the resource."
          },
          "notifications": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Notification preferences for the user."
          },
          "features": {
            "type": "array",
            "items": {},
            "description": "Feature flags or entitlements enabled for the plan."
          },
          "source": {
            "type": "string",
            "description": "Source/origin of the resource."
          },
          "apple_account_token": {
            "type": "string",
            "description": "Opaque Apple App Store account token (Apple IAP users only)."
          },
          "hide_real_clone": {
            "type": "boolean",
            "description": "Whether to hide the user's real cloned voice from listings."
          },
          "onboarding": {
            "type": "object",
            "properties": {
              "video_id": {
                "type": "string",
                "description": "Identifier of the parent video."
              },
              "status": {
                "type": "string",
                "description": "Current lifecycle status of the resource."
              },
              "faceless_id": {
                "type": "string",
                "description": "Identifier of the parent faceless video."
              }
            },
            "required": [
              "video_id",
              "status",
              "faceless_id"
            ],
            "description": "Onboarding progress/state for the user."
          },
          "answers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SurveyAnswerResource"
            },
            "description": "Collection of submitted survey answers."
          },
          "show_welcome_modal": {
            "type": "string",
            "description": "Whether the welcome modal should be shown to the user."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "name",
          "stripe_id",
          "email",
          "email_verified",
          "credits",
          "subscription",
          "settings",
          "notifications",
          "features",
          "source",
          "hide_real_clone",
          "show_welcome_modal",
          "created_at",
          "updated_at"
        ],
        "title": "UserResource",
        "description": "A user record."
      },
      "UserType": {
        "type": "integer",
        "enum": [
          1,
          2,
          3,
          4
        ],
        "title": "UserType",
        "description": "A user Type record."
      },
      "VideoResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": "integer",
            "description": "Identifier of the owning user."
          },
          "idea_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the linked content idea."
          },
          "scheduler_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning scheduler."
          },
          "title": {
            "type": [
              "string",
              "null"
            ],
            "description": "Title of the resource."
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type/category discriminator for the resource."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Playable URL of the rendered video (mp4). Populated once the render completes (status `completed`); null while drafting/rendering or if the render failed."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/VideoStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "retries": {
            "type": "integer",
            "description": "Number of times processing has been retried."
          },
          "hash": {
            "type": [
              "string",
              "null"
            ],
            "description": "Opaque content hash used for change detection."
          },
          "synced_at": {
            "type": "string",
            "description": "ISO-8601 timestamp the resource was last synced, or null."
          },
          "metadata": {
            "type": "object",
            "properties": {
              "ai_labels": {
                "description": "Whether AI-content disclosure labels are applied on publish."
              },
              "custom_description": {
                "description": "Custom caption/description applied to published posts."
              }
            },
            "required": [
              "ai_labels",
              "custom_description"
            ],
            "description": "Additional metadata for the resource."
          },
          "failure": {
            "type": [
              "object",
              "null"
            ],
            "nullable": true,
            "description": "Present only when status is \"failed\": the categorized reason the render failed; null otherwise.",
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable failure category the client can branch on.",
                "enum": [
                  "voiceover_failed",
                  "script_processing_failed",
                  "stock_footage_failed",
                  "asset_generation_failed",
                  "image_generation_failed",
                  "composition_failed",
                  "music_failed",
                  "watermark_failed",
                  "background_failed",
                  "source_build_failed",
                  "charge_failed",
                  "render_failed"
                ]
              },
              "message": {
                "type": "string",
                "description": "Human-readable, safe failure message suitable for display to end users."
              }
            }
          },
          "user": {
            "$ref": "#/components/schemas/UserResource"
          },
          "media": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MediaResource"
            },
            "description": "Underlying media files attached to the resource."
          },
          "idea": {
            "$ref": "#/components/schemas/IdeaResource"
          },
          "faceless": {
            "$ref": "#/components/schemas/App.Http.Resources.FacelessResource"
          },
          "storyboard": {
            "$ref": "#/components/schemas/StoryboardResource"
          },
          "resource": {
            "$ref": "#/components/schemas/FolderWithContentResource"
          },
          "publications": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicationResource"
            },
            "description": "Scheduled or published social posts for this video."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "idea_id",
          "scheduler_id",
          "title",
          "type",
          "url",
          "status",
          "retries",
          "hash",
          "synced_at",
          "metadata",
          "created_at",
          "updated_at"
        ],
        "title": "VideoResource",
        "description": "A video record.",
        "example": {
          "id": 10,
          "user_id": 1,
          "idea_id": null,
          "scheduler_id": null,
          "title": "My faceless video",
          "type": "faceless",
          "url": null,
          "status": "failed",
          "retries": 1,
          "hash": "abc123",
          "synced_at": null,
          "metadata": {
            "ai_labels": true,
            "custom_description": null
          },
          "failure": {
            "code": "voiceover_failed",
            "message": "Voiceover generation failed. Please try again shortly or contact support if it persists."
          },
          "created_at": "2026-01-01T12:00:00.000000Z",
          "updated_at": "2026-01-01T12:00:00.000000Z"
        }
      },
      "VideoStatus": {
        "type": "string",
        "enum": [
          "draft",
          "failed",
          "syncing",
          "rendering",
          "completed",
          "sync-failed",
          "timeout",
          "modifying",
          "modified"
        ],
        "title": "VideoStatus",
        "description": "A video Status record."
      },
      "VoiceResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "user_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the owning user."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Display name of the resource."
          },
          "preview": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL of a preview image or clip for the resource."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "description": "Language of the content (e.g. \"english\")."
          },
          "accent": {
            "type": [
              "string",
              "null"
            ],
            "description": "Accent of the voice (e.g. \"american\", \"british\")."
          },
          "gender": {
            "type": [
              "string",
              "null"
            ],
            "description": "Gender label (e.g. \"male\", \"female\", \"neutral\")."
          },
          "provider": {
            "type": [
              "string",
              "null"
            ],
            "description": "Upstream provider that fulfilled the resource."
          },
          "provider_id": {
            "type": [
              "string",
              "null"
            ],
            "description": "Provider-side identifier for the resource."
          },
          "words_per_minute": {
            "type": "integer",
            "description": "The words per minute value for the resource."
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "description": "Type/category discriminator for the resource."
          },
          "is_active": {
            "type": "boolean",
            "description": "Whether the record is active."
          },
          "metadata": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Additional metadata for the resource."
          },
          "order": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Zero-based ordering position within its collection."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was last updated."
          }
        },
        "required": [
          "id",
          "user_id",
          "name",
          "preview",
          "language",
          "accent",
          "gender",
          "provider",
          "provider_id",
          "words_per_minute",
          "type",
          "is_active",
          "metadata",
          "order",
          "created_at",
          "updated_at"
        ],
        "title": "VoiceResource",
        "description": "A voice record."
      },
      "ScrapeImagesRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Publicly reachable web page URL to extract product/page images from. Social-media URLs (YouTube, TikTok, Twitter/X, Instagram, Facebook, etc.) are rejected with `422`."
          }
        },
        "required": [
          "url"
        ],
        "title": "ScrapeImagesRequest",
        "description": "A scrape Images Request record."
      },
      "ScrapeScriptRequest": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Publicly reachable web page URL to extract script content from. Social-media URLs are rejected with `422`."
          },
          "duration": {
            "type": "integer",
            "enum": [
              30,
              60,
              180,
              300,
              600,
              900
            ],
            "description": "Target length of the generated script in seconds. Must be one of 30, 60, 180, 300, 600, or 900."
          },
          "style": {
            "type": "string",
            "description": "Narrative style for the generated script (free-form text, max 255 chars). Examples: educational, storytelling, listicle, conversational, motivational."
          },
          "language": {
            "type": "string",
            "description": "Language for the generated script (e.g. \"english\")."
          },
          "tone": {
            "type": "string",
            "description": "Tone of voice for the generated script. Examples: professional, friendly, casual, authoritative."
          }
        },
        "required": [
          "url",
          "duration",
          "style",
          "language",
          "tone"
        ],
        "title": "ScrapeScriptRequest",
        "description": "A scrape Script Request record."
      },
      "CreateBrollRequest": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the video (max 255 characters)."
          },
          "idea_id": {
            "type": "integer",
            "description": "Optional identifier of a Syllaby content idea to link the video to. The v2 API exposes no ideas endpoints, so omit it for API-only flows."
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 timestamp that schedules the video on your Syllaby content calendar. Does not delay the render."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 end timestamp for the scheduled calendar slot. Must be the same as or after `starts_at`."
          }
        },
        "description": "A create Broll Request record."
      },
      "CreateAiVisualsRequest": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the video (max 255 characters)."
          },
          "idea_id": {
            "type": "integer",
            "description": "Optional identifier of a Syllaby content idea to link the video to. The v2 API exposes no ideas endpoints, so omit it for API-only flows."
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 timestamp that schedules the video on your Syllaby content calendar. Does not delay the render."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 end timestamp for the scheduled calendar slot. Must be the same as or after `starts_at`."
          }
        },
        "description": "A create Ai Visuals Request record."
      },
      "CreateUrlToVideoRequest": {
        "type": "object",
        "required": [
          "title"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the video (max 255 characters)."
          },
          "idea_id": {
            "type": "integer",
            "description": "Optional identifier of a Syllaby content idea to link the video to. The v2 API exposes no ideas endpoints, so omit it for API-only flows."
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 timestamp that schedules the video on your Syllaby content calendar. Does not delay the render."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optional ISO-8601 end timestamp for the scheduled calendar slot. Must be the same as or after `starts_at`."
          }
        },
        "description": "A create Url To Video Request record."
      },
      "RegenerateFacelessAssetRequest": {
        "type": "object",
        "description": "Regenerate a single AI-Visuals scene image. The engine and image-generation tracker come from the stored faceless; only the prompt can be overridden.",
        "properties": {
          "prompt": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 800,
            "description": "Optional replacement prompt for the regenerated image (max 800 characters). Omit to reuse the scene's existing prompt."
          }
        }
      },
      "UploadFacelessAssetRequest": {
        "type": "object",
        "description": "Attach media to a dedicated faceless video. Provide EITHER a multipart `file` upload OR a remote `url` to transload — exactly one, never both. Accepts image and video mimes and is subject to your storage quota.",
        "properties": {
          "file": {
            "type": "string",
            "format": "binary",
            "contentMediaType": "application/octet-stream",
            "description": "The media file to upload (multipart/form-data). Provide this OR `url`, not both."
          },
          "url": {
            "type": "string",
            "format": "uri",
            "description": "Publicly reachable URL of a media file to transload. Provide this OR `file`, not both."
          }
        }
      },
      "SubmitTextToScenePromptRequest": {
        "type": "object",
        "description": "Prompt-driven storyboard generation input. Send as `application/json`, or as `multipart/form-data` when attaching reference image files.",
        "required": [
          "prompt",
          "clip_engine_id",
          "duration"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "The prompt describing the video to generate (max 5000 characters)."
          },
          "clip_engine_id": {
            "type": "integer",
            "description": "Identifier of the text-to-video clip engine to use (see faceless options `clip_engines`)."
          },
          "duration": {
            "type": "object",
            "required": [
              "min",
              "max"
            ],
            "description": "Target duration range for the generated video, in seconds.",
            "properties": {
              "min": {
                "type": "integer",
                "minimum": 0,
                "description": "Minimum total duration in seconds."
              },
              "max": {
                "type": "integer",
                "minimum": 1,
                "description": "Maximum total duration in seconds."
              }
            }
          },
          "settings": {
            "type": "object",
            "description": "Optional render settings for the storyboard.",
            "properties": {
              "audio": {
                "type": "boolean",
                "description": "Whether the rendered video includes generated audio."
              },
              "aspect_ratio": {
                "type": "string",
                "description": "Output aspect ratio (e.g. \"16:9\", \"9:16\"). Must be a value the chosen clip engine supports — see its `modifiers` in `GET /text-to-video/models`."
              },
              "resolution": {
                "type": "string",
                "description": "Output resolution (e.g. \"720p\", \"1080p\"). Must be a value the chosen clip engine supports — see its `modifiers` in `GET /text-to-video/models`."
              }
            }
          },
          "references": {
            "type": "array",
            "maxItems": 5,
            "description": "Optional reference images to steer the visual style — up to 5. Send as file parts via `multipart/form-data`.",
            "items": {
              "type": "string",
              "format": "binary",
              "description": "A reference image file."
            }
          },
          "context": {
            "type": "array",
            "maxItems": 3,
            "description": "Optional guided context Q&A pairs that shape the generation — up to 3.",
            "items": {
              "type": "object",
              "required": [
                "key",
                "question",
                "answer"
              ],
              "properties": {
                "key": {
                  "type": "string",
                  "enum": [
                    "purpose",
                    "style",
                    "audience"
                  ],
                  "description": "The context dimension this answer addresses."
                },
                "question": {
                  "type": "string",
                  "maxLength": 500,
                  "description": "The context question (max 500 characters)."
                },
                "answer": {
                  "type": "string",
                  "maxLength": 500,
                  "description": "The answer to the context question (max 500 characters)."
                }
              }
            }
          }
        }
      },
      "CreateTextToSceneRequest": {
        "type": "object",
        "required": [
          "title",
          "mode"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 255,
            "description": "Display name of the storyboard (max 255 characters)."
          },
          "mode": {
            "type": "string",
            "enum": [
              "wizard",
              "manual"
            ],
            "description": "Authoring mode: `wizard` (guided prompt-to-storyboard generation) or `manual` (you build scenes yourself)."
          }
        },
        "description": "A create Text To Scene Request record."
      },
      "UpdateTextToSceneRequest": {
        "type": "object",
        "properties": {
          "settings": {
            "type": "object",
            "description": "Render settings for the storyboard. Only the fields you send are changed.",
            "properties": {
              "audio": {
                "type": "boolean",
                "description": "Whether the rendered video includes generated audio."
              },
              "aspect_ratio": {
                "type": "string",
                "description": "Output aspect ratio (e.g. \"16:9\", \"9:16\"). Must be a value the chosen clip engine supports — see its `modifiers` in `GET /text-to-video/models`."
              },
              "resolution": {
                "type": "string",
                "description": "Output resolution (e.g. \"720p\", \"1080p\"). Must be a value the chosen clip engine supports — see its `modifiers` in `GET /text-to-video/models`."
              }
            }
          }
        },
        "description": "A update Text To Scene Request record."
      },
      "GenerateTextToSceneClipRequest": {
        "type": "object",
        "required": [
          "scenes"
        ],
        "properties": {
          "scenes": {
            "type": "array",
            "minItems": 1,
            "description": "The scenes to generate clips for (at least one).",
            "items": {
              "type": "object",
              "required": [
                "id",
                "enhance"
              ],
              "properties": {
                "id": {
                  "type": "integer",
                  "description": "Identifier of a scene belonging to this storyboard."
                },
                "enhance": {
                  "type": "boolean",
                  "description": "Whether to enhance the scene's prompt before generating its clip."
                }
              }
            }
          }
        },
        "description": "A generate Text To Scene Clip Request record."
      },
      "SortScenesRequest": {
        "type": "object",
        "required": [
          "scene_id"
        ],
        "properties": {
          "scene_id": {
            "type": "integer",
            "description": "Identifier of the scene to move."
          },
          "after_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the scene it should follow, or null to move it to the start."
          }
        },
        "description": "A sort Scenes Request record."
      },
      "AssignTextToSceneFrameRequest": {
        "type": "object",
        "properties": {
          "first_frame_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Asset id to use as the scene's first frame, or null to clear it."
          },
          "last_frame_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Asset id to use as the scene's last frame, or null to clear it."
          }
        },
        "description": "A assign Text To Scene Frame Request record."
      },
      "ChainSceneRequest": {
        "type": "object",
        "required": [
          "scene_id"
        ],
        "properties": {
          "scene_id": {
            "type": "integer",
            "description": "Identifier of the scene to chain to (its last frame seeds this scene's first frame)."
          }
        },
        "description": "A chain Scene Request record."
      },
      "ManageTextToSceneMoodboardRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "Prompt describing the moodboard imagery to generate (max 5000 characters)."
          },
          "enhance": {
            "type": "boolean",
            "description": "Whether to enhance the prompt before generating."
          },
          "references": {
            "type": "array",
            "description": "Optional asset ids to use as visual references.",
            "items": {
              "type": "integer",
              "description": "Reference asset id."
            }
          }
        },
        "description": "A manage Text To Scene Moodboard Request record."
      },
      "GenerateContextRequest": {
        "type": "object",
        "required": [
          "prompt"
        ],
        "properties": {
          "prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "Prompt to expand into narrative context for the storyboard (max 5000 characters)."
          }
        },
        "description": "A generate Context Request record."
      },
      "ManageTextToSceneSceneRequest": {
        "type": "object",
        "properties": {
          "order": {
            "type": "integer",
            "minimum": 0,
            "description": "Zero-based position of the scene within the storyboard."
          },
          "raw_video_prompt": {
            "type": "string",
            "maxLength": 5000,
            "description": "The scene's video prompt (max 5000 characters)."
          },
          "duration": {
            "type": "integer",
            "minimum": 1,
            "description": "Scene duration in seconds. Validated against the storyboard's clip engine: engines with a fixed duration list accept only those values (e.g. Veo 3.1 accepts 4, 6, or 8), range engines accept any integer between their min and max. Discover each engine's duration modifier via `GET /faceless/options?only=clip_engines` or `GET /text-to-video/models`."
          }
        },
        "description": "A manage Text To Scene Scene Request record."
      },
      "TextToSceneResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Numeric identifier of the storyboard."
          },
          "uuid": {
            "type": "string",
            "description": "Stable UUID of the storyboard."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/StoryboardStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current generation status of the storyboard."
          },
          "prompt": {
            "type": [
              "string",
              "null"
            ],
            "description": "The source prompt the storyboard was generated from, when applicable."
          },
          "settings": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Render settings for the storyboard (audio, aspect ratio, resolution)."
          },
          "duration": {
            "type": [
              "array",
              "null"
            ],
            "items": {},
            "description": "Per-scene duration breakdown for the storyboard."
          },
          "video": {
            "allOf": [
              {
                "$ref": "#/components/schemas/VideoResource"
              }
            ],
            "description": "The embedded render state (shared v2 VideoResource); `url` is null until the render completes."
          },
          "scenes": {
            "type": "array",
            "description": "The storyboard's scenes, in order.",
            "items": {
              "$ref": "#/components/schemas/TextToSceneSceneResource"
            }
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp of when the storyboard was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp of the last update."
          }
        },
        "required": [
          "id",
          "uuid",
          "status",
          "prompt",
          "settings",
          "duration",
          "created_at",
          "updated_at"
        ],
        "description": "A text To Scene record."
      },
      "TextToSceneSceneResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Numeric identifier of the scene."
          },
          "uuid": {
            "type": "string",
            "description": "Stable UUID of the scene."
          },
          "order": {
            "type": "integer",
            "description": "Zero-based position of the scene within the storyboard."
          },
          "video_prompt": {
            "type": [
              "string",
              "null"
            ],
            "description": "The prompt used to generate the scene's clip."
          },
          "duration": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Scene duration in seconds."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/SceneStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current status of the scene's clip generation."
          },
          "error": {
            "type": [
              "string",
              "null"
            ],
            "description": "Failure reason when clip generation failed; otherwise null."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp of when the scene was created."
          },
          "updated_at": {
            "type": "string",
            "description": "ISO-8601 timestamp of the last update."
          }
        },
        "required": [
          "id",
          "uuid",
          "order",
          "video_prompt",
          "duration",
          "status",
          "error",
          "created_at",
          "updated_at"
        ],
        "description": "A text To Scene Scene record."
      },
      "TextToSceneMoodboardResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Numeric identifier of the moodboard entry."
          },
          "asset_id": {
            "type": "integer",
            "description": "Identifier of the underlying media asset."
          },
          "source": {
            "allOf": [
              {
                "$ref": "#/components/schemas/MoodboardSource"
              }
            ],
            "description": "How the moodboard image was produced (uploaded or generated)."
          },
          "type": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AssetType"
              }
            ],
            "description": "Media type of the moodboard asset."
          },
          "status": {
            "allOf": [
              {
                "$ref": "#/components/schemas/AssetStatus"
              }
            ],
            "description": "Processing status of the moodboard asset."
          },
          "url": {
            "type": [
              "string",
              "null"
            ],
            "description": "Playable/downloadable URL of the asset; null until ready."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp of when the entry was created."
          }
        },
        "required": [
          "id",
          "asset_id",
          "source",
          "type",
          "status",
          "url",
          "created_at"
        ],
        "description": "A text To Scene Moodboard record."
      },
      "MoodboardSource": {
        "type": "string",
        "enum": [
          "upload",
          "generated"
        ],
        "title": "MoodboardSource",
        "description": "A moodboard Source record."
      },
      "AutoTopUpResource": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "description": "Whether auto top-up is currently switched on."
          },
          "type": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "extra-credits",
              "dynamic-credits",
              null
            ],
            "description": "Purchase mode when enabled: `extra-credits` buys a fixed one-time credit pack (see `plan_id`), `dynamic-credits` buys a custom amount (see `units`). `null` if auto top-up has never been configured."
          },
          "plan_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Identifier of the one-time credit-pack plan to purchase. Set only when `type` is `extra-credits`."
          },
          "units": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Number of pricing units to purchase — 100 credits per unit. Set only when `type` is `dynamic-credits`."
          },
          "enabled_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "Timestamp the preference was last enabled. `null` if never enabled."
          },
          "consecutive_failures": {
            "type": "integer",
            "description": "Consecutive failed top-up charge attempts. Auto top-up disables itself automatically once this reaches 3, and it resets to 0 on every successful charge or re-enable."
          }
        },
        "required": [
          "enabled",
          "consecutive_failures"
        ],
        "title": "AutoTopUpResource",
        "description": "The authenticated account's auto top-up preference."
      },
      "App.Http.Resources.Api.v2.CharacterResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CharacterStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "genre": {
            "$ref": "#/components/schemas/App.Http.Resources.Api.v2.GenreResource"
          },
          "gender": {
            "type": "string",
            "description": "Gender label (e.g. \"male\", \"female\", \"neutral\")."
          },
          "age": {
            "description": "Age or age-range label for the character (e.g. \"25-34\")."
          },
          "traits": {
            "description": "Descriptive personality/appearance traits for the character."
          },
          "preview_url": {
            "type": [
              "string",
              "null"
            ],
            "description": "URL of a short generated preview (voice sample audio, or character preview image), or null until it is ready."
          },
          "previews": {
            "type": "string",
            "description": "Candidate preview images produced by preview generation. Each entry's `id` is the value you pass as `preview_id` to `POST /characters/{id}/train`."
          },
          "poses": {
            "type": "string",
            "description": "Generated pose image URLs for a trained character; empty until training reaches status `ready`."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          }
        },
        "required": [
          "id",
          "name",
          "status",
          "gender",
          "age",
          "traits",
          "preview_url",
          "previews",
          "poses",
          "created_at"
        ],
        "title": "App.Http.Resources.Api.v2.CharacterResource",
        "description": "A character record."
      },
      "App.Http.Resources.Api.v2.GenreResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "slug": {
            "type": "string",
            "description": "URL-friendly unique identifier for the resource."
          },
          "preview": {
            "type": "array",
            "items": {},
            "description": "URL of a preview image or clip for the resource."
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "preview"
        ],
        "title": "App.Http.Resources.Api.v2.GenreResource",
        "description": "A genre record."
      },
      "CloneStatus": {
        "type": "string",
        "enum": [
          "failed",
          "pending",
          "reviewing",
          "completed"
        ],
        "title": "CloneStatus",
        "description": "A clone Status record."
      },
      "CreateCharacterPreviewRequest": {
        "type": "object",
        "properties": {
          "genre_id": {
            "type": "integer",
            "description": "Required — id of the character-capable genre to render the preview in. Must be one of the genres returned by `GET /characters/genres`; any other id fails validation with `422`."
          }
        },
        "required": [
          "genre_id"
        ],
        "title": "CreateCharacterPreviewRequest",
        "description": "A create Character Preview Request record."
      },
      "CreateCharacterRequest": {
        "type": "object",
        "description": "v2 reuses the v1 rules verbatim. The v1 request has no authorize() override\n(defaults to true) and no route-model binding, so an empty subclass is safe\non v2's raw {id} routes — no hidden 403 trap.",
        "properties": {
          "image": {
            "type": "string",
            "format": "binary",
            "contentMediaType": "application/octet-stream",
            "description": "Required — a reference photo of the character to build (image file, max 10 MB). Send as `multipart/form-data`."
          },
          "genre_id": {
            "type": [
              "integer",
              "null"
            ],
            "description": "Optional — id of a character-capable genre (see `GET /characters/genres`)."
          },
          "name": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional — display name for the character (max 250 characters). Omit it and the name is derived from your account name."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 500,
            "description": "Optional — free-text description of the character (max 500 characters)."
          },
          "gender": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "male",
              "female"
            ],
            "description": "Optional — character gender. Accepted values: `male`, `female`, `neutral`. **Omitting it stores `unknown`**, which is what the character then returns — `unknown` is a response value only and is rejected if you send it."
          },
          "traits": {
            "type": [
              "array",
              "null"
            ],
            "items": {
              "type": "string"
            },
            "description": "Optional — list of descriptive traits for the character."
          },
          "age": {
            "type": [
              "string",
              "null"
            ],
            "description": "Optional — age or age-range label for the character (e.g. \"25-34\")."
          }
        },
        "required": [
          "image"
        ],
        "title": "CreateCharacterRequest"
      },
      "CreateVoiceCloneRequest": {
        "type": "object",
        "properties": {
          "terms": {
            "type": "string",
            "description": "Required — you must accept the voice-cloning terms. Send a truthy value (`true`, `1`, `\"yes\"`, `\"on\"`); consent is a legal boundary and the request is rejected without it."
          },
          "name": {
            "type": "string",
            "maxLength": 20,
            "description": "Required — display name for the voice clone (max 20 characters)."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "Optional — free-text description of the voice (max 200 characters)."
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "neutral"
            ],
            "description": "Required — voice gender: `male`, `female`, or `neutral`."
          },
          "language": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 3,
            "description": "Optional — ISO language code for the voice (max 3 characters, e.g. `en`)."
          },
          "purchase_addon": {
            "type": [
              "boolean",
              "null"
            ],
            "description": "Optional — set `true` to buy an extra voice-clone slot when your included slots are full. Sent over `multipart/form-data`, so the accepted truthy spellings are `true`, `1`, `on` and `yes` (case-insensitive); `false`, `0`, `off`, `no` and an empty value all decline. Any other value returns `422` rather than silently declining the purchase. Charges credits (see `GET /voice-clones/slots` for the price); a `false`/omitted value with no free slot returns `403`. If purchasing and your balance is too low, the request returns `402`."
          },
          "samples": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "binary",
              "contentMediaType": "application/octet-stream"
            },
            "minItems": 1,
            "maxItems": 3,
            "description": "Required — 1 to 3 audio sample files of the voice to clone. Each file may be mp3, wav, m4a, or webm, up to 10 MB. Send as `multipart/form-data` (`samples[]`)."
          }
        },
        "required": [
          "terms",
          "name",
          "gender",
          "samples"
        ],
        "title": "CreateVoiceCloneRequest",
        "description": "A create Voice Clone Request record."
      },
      "DiscoverIdeasRequest": {
        "type": "object",
        "properties": {
          "keyword": {
            "type": "string",
            "minLength": 2,
            "maxLength": 80,
            "description": "Required — the keyword or phrase to discover content ideas for (2–80 characters)."
          },
          "network": {
            "type": "string",
            "enum": [
              "google",
              "google-trends",
              "youtube",
              "instagram",
              "twitter",
              "bing",
              "pinterest",
              "tiktok"
            ],
            "description": "Required — the network the ideas are sourced for: `google`, `google-trends`, `youtube`, `instagram`, `twitter`, `bing`, `pinterest`, or `tiktok`."
          }
        },
        "required": [
          "keyword",
          "network"
        ],
        "title": "DiscoverIdeasRequest",
        "description": "A discover Ideas Request record."
      },
      "StartCharacterTrainingRequest": {
        "type": "object",
        "properties": {
          "preview_id": {
            "type": "integer",
            "description": "Required — id of the chosen preview candidate (an entry from the character's `previews[].id`, produced by `POST /characters/{id}/preview`)."
          },
          "name": {
            "type": "string",
            "description": "Required — display name for the trained character."
          },
          "age": {
            "type": "string",
            "description": "Required — age or age-range label for the character (e.g. \"25-34\")."
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female"
            ],
            "description": "Required — character gender: `male`, `female`, or `neutral`."
          }
        },
        "required": [
          "preview_id",
          "name",
          "age",
          "gender"
        ],
        "title": "StartCharacterTrainingRequest",
        "description": "A start Character Training Request record."
      },
      "UpdateVoiceCloneRequest": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 125,
            "description": "Required — display name for the voice clone (max 125 characters)."
          },
          "description": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 255,
            "description": "Optional — free-text description of the voice (max 255 characters)."
          },
          "gender": {
            "type": "string",
            "enum": [
              "male",
              "female",
              "neutral"
            ],
            "description": "Required — voice gender: `male`, `female`, or `neutral`."
          }
        },
        "required": [
          "name",
          "gender"
        ],
        "title": "UpdateVoiceCloneRequest",
        "description": "A update Voice Clone Request record."
      },
      "VoiceCloneResource": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Unique numeric identifier of the resource."
          },
          "name": {
            "type": "string",
            "description": "Display name of the resource."
          },
          "gender": {
            "type": "string",
            "description": "Gender label (e.g. \"male\", \"female\", \"neutral\")."
          },
          "language": {
            "type": "string",
            "description": "Language of the content (e.g. \"english\")."
          },
          "description": {
            "description": "Human-readable description of the resource."
          },
          "status": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/CloneStatus"
              },
              {
                "type": "null"
              }
            ],
            "description": "Current lifecycle status of the resource."
          },
          "slot_type": {
            "type": "string",
            "enum": [
              "addon",
              "default"
            ],
            "description": "Which slot the voice clone occupies: \"default\" (included with the plan) or \"addon\" (a purchased extra slot)."
          },
          "preview_url": {
            "type": "string",
            "description": "URL of a short generated preview (voice sample audio, or character preview image), or null until it is ready."
          },
          "created_at": {
            "type": "string",
            "description": "ISO-8601 timestamp when the record was created."
          }
        },
        "required": [
          "id",
          "name",
          "gender",
          "language",
          "description",
          "status",
          "slot_type",
          "preview_url",
          "created_at"
        ],
        "title": "VoiceCloneResource",
        "description": "A voice Clone record."
      }
    },
    "responses": {
      "AuthenticationException": {
        "description": "Unauthenticated",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-UNAUTHORIZED"
                    },
                    "status": {
                      "type": "integer",
                      "example": 401
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "Unauthenticated.",
              "error": {
                "code": "GEN-UNAUTHORIZED",
                "status": 401
              }
            }
          }
        }
      },
      "ValidationException": {
        "description": "Validation error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Errors overview."
                },
                "errors": {
                  "type": "object",
                  "description": "A detailed description of each field that failed validation.",
                  "additionalProperties": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-VALIDATION-FAILED"
                    },
                    "status": {
                      "type": "integer",
                      "example": 422
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "errors",
                "error"
              ]
            },
            "example": {
              "message": "The given data was invalid.",
              "errors": {
                "voice_id": [
                  "The selected voice id is invalid."
                ]
              },
              "error": {
                "code": "GEN-VALIDATION-FAILED",
                "status": 422
              }
            }
          }
        }
      },
      "AuthorizationException": {
        "description": "Authorization error",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-FORBIDDEN"
                    },
                    "status": {
                      "type": "integer",
                      "example": 403
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "This action is unauthorized.",
              "error": {
                "code": "GEN-FORBIDDEN",
                "status": 403
              }
            }
          }
        }
      },
      "ModelNotFoundException": {
        "description": "Not found",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-NOT-FOUND"
                    },
                    "status": {
                      "type": "integer",
                      "example": 404
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "Resource Not Found",
              "error": {
                "code": "GEN-NOT-FOUND",
                "status": 404
              }
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Rate limit exceeded — requests are limited per API token (30 per minute by default). The response carries `Retry-After` (seconds to wait) and `X-RateLimit-Reset` (Unix timestamp when the window resets); back off until then and retry. Successful responses include `X-RateLimit-Limit` and `X-RateLimit-Remaining` so you can pace requests proactively.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "RATE-LIMIT-EXCEEDED"
                    },
                    "status": {
                      "type": "integer",
                      "example": 429
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "Too Many Attempts.",
              "error": {
                "code": "RATE-LIMIT-EXCEEDED",
                "status": 429
              }
            }
          }
        }
      },
      "BadRequest": {
        "description": "Bad request — e.g. an `include` value outside the endpoint's allowlist.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                }
              },
              "required": [
                "message"
              ]
            },
            "example": {
              "message": "Requested include(s) `foo` are not allowed. Allowed include(s) are `video, captions, media, music, voice, background, genre, watermark, character, assets`."
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "Insufficient credits. The request is authenticated and valid, but the account balance is too low — top up and retry.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "example": "You do not have enough credits to render this video"
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "INSUFFICIENT-CREDITS"
                    },
                    "status": {
                      "type": "integer",
                      "example": 402
                    },
                    "required": {
                      "type": "integer",
                      "example": 13
                    },
                    "available": {
                      "type": "integer",
                      "example": 4
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SubscriptionRequired": {
        "description": "No active **paid** subscription. The v2 public API is paid-only — every faceless and preset endpoint (reads included) requires an active paid subscription, and trials are not eligible. Two codes distinguish the cause on this `403`: `PAID-SUBSCRIPTION-REQUIRED` (subscribed but on a trial — access unlocks automatically once the subscription becomes paid) and `SUBSCRIPTION-REQUIRED` (never subscribed, expired, or canceled). Rejected before any ownership, credit, or validation check. Only `GET /me`, `GET /credits/costs`, and `GET /credits/history` are reachable without a paid subscription.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Human-readable status message for the response.",
                  "example": "An active subscription is required."
                },
                "error": {
                  "type": "object",
                  "description": "Structured error detail.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code — `PAID-SUBSCRIPTION-REQUIRED` for trial callers, `SUBSCRIPTION-REQUIRED` for unsubscribed, expired, or canceled callers.",
                      "example": "SUBSCRIPTION-REQUIRED"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the error body.",
                      "example": 403
                    }
                  }
                }
              }
            },
            "example": {
              "message": "An active subscription is required.",
              "error": {
                "code": "SUBSCRIPTION-REQUIRED",
                "status": 403
              }
            }
          }
        }
      },
      "SubscriptionRequiredOrAuthorization": {
        "description": "Forbidden — two distinct causes share this status:\n\n1. **No active subscription** (code `SUBSCRIPTION-REQUIRED`, message \"An active subscription is required.\") — checked first by the active-subscription gate, before any ownership or precondition logic. The v2 public API has no free tier.\n2. **Authorization / ownership or precondition failure** — the subscription is active but the action is not allowed: the resource belongs to another account, or a render precondition is unmet (e.g. `A script is required before rendering.`, `Voice was not provided.`, the video is busy, or storage is full).",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Human-readable status message for the response.",
                  "example": "An active subscription is required."
                },
                "error": {
                  "type": "object",
                  "description": "Structured error detail, present on the gate (`SUBSCRIPTION-REQUIRED`) and code-bearing authorization failures.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "description": "Stable machine-readable error code — `SUBSCRIPTION-REQUIRED` for the subscription gate.",
                      "example": "SUBSCRIPTION-REQUIRED"
                    },
                    "status": {
                      "type": "integer",
                      "description": "HTTP status code echoed in the error body.",
                      "example": 403
                    }
                  }
                }
              }
            },
            "example": {
              "message": "An active subscription is required.",
              "error": {
                "code": "SUBSCRIPTION-REQUIRED",
                "status": 403
              }
            }
          }
        }
      },
      "EmailNotVerified": {
        "description": "Email address not verified. The token is valid and the account exists, but the user has not confirmed their email address. This gate fronts every v2 endpoint. Have the user complete verification, then retry.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "EMAIL-NOT-VERIFIED"
                    },
                    "status": {
                      "type": "integer",
                      "example": 409
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "Your email address is not verified.",
              "error": {
                "code": "EMAIL-NOT-VERIFIED",
                "status": 409
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The URL exists but not for this HTTP method — e.g. `GET /presets/faceless/{preset}`, which is only defined for `PATCH` and `DELETE`. Check the verb against the endpoint reference; the `Allow` header lists the methods this path accepts.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-METHOD-NOT-ALLOWED"
                    },
                    "status": {
                      "type": "integer",
                      "example": 405
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "The GET method is not supported for this route.",
              "error": {
                "code": "GEN-METHOD-NOT-ALLOWED",
                "status": 405
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "The request body exceeded the server upload limit. This is checked before validation, so the response names no specific field. Send fewer or smaller files — a single file over the documented per-field limit returns `422` on that key instead.",
        "content": {
          "application/json": {
            "schema": {
              "type": "object",
              "properties": {
                "message": {
                  "type": "string",
                  "description": "Error overview."
                },
                "error": {
                  "type": "object",
                  "description": "Machine-readable error descriptor. Branch on `error.code`.",
                  "properties": {
                    "code": {
                      "type": "string",
                      "example": "GEN-WRONG-ARGS"
                    },
                    "status": {
                      "type": "integer",
                      "example": 413
                    }
                  },
                  "required": [
                    "code",
                    "status"
                  ]
                }
              },
              "required": [
                "message",
                "error"
              ]
            },
            "example": {
              "message": "The POST data is too large.",
              "error": {
                "code": "GEN-WRONG-ARGS",
                "status": 413
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Account",
      "description": "The authenticated user — profile, per-feature credit costs, and the credit ledger."
    },
    {
      "name": "Faceless Videos",
      "description": "Create, configure, render, and retrieve faceless videos, their assets, and reusable presets. The typed product endpoints — **B-roll**, **AI-Visuals**, and **URL-to-Video** — are recommended shortcuts for those specific types; this generic `/faceless` surface is the advanced entry point that supports every type, including `ai-clips` (only reachable here), and lets you switch a draft's `type` before rendering."
    },
    {
      "name": "Text to Video",
      "description": "Generate short AI video clips from a text prompt: list the models your plan allows, estimate the exact charge, create a clip, and poll it to completion."
    },
    {
      "name": "B-roll",
      "description": "Generate stock-footage videos from a narration script."
    },
    {
      "name": "AI-Visuals",
      "description": "Generate videos with AI-generated imagery, with per-scene upload and regeneration."
    },
    {
      "name": "URL-to-Video",
      "description": "Turn a web page into a video: scrape images and script, then render."
    },
    {
      "name": "Text-to-Scene",
      "description": "A storyboard editor: generate, reorder, chain, and render scenes into a video.\n\n## Models, formats & pricing\n\nText-to-Scene renders clips with the same engines as Text-to-Video. Fetch the\nlive list — with the `id` to send as `clip_engine_id` and per-engine credit\npricing — from [`GET /faceless/options?only=clip_engines`](#tag/faceless-videos/GET/faceless/options).\nEach engine's supported aspect ratios, resolutions, and durations are listed in\nthe `modifiers` of [`GET /text-to-video/models`](#tag/text-to-video/GET/text-to-video/models) —\nmatch entries by `slug`.\n\nSnapshot of the current lineup (the endpoints above are the live source of truth;\n`clip_engine_id` values vary per environment, so always take the `id` from\n`/faceless/options`):\n\n| Model | Slug | Aspect ratios | Resolutions | Clip duration (s) | Credits / sec |\n|---|---|---|---|---|---|\n| Veo 3.1 | `veo-3-1` | 16:9, 9:16 | 720p, 1080p | 4, 6, 8 | 6 – 11 |\n| Veo 3.1 Fast | `veo-3-1-fast` | 16:9, 9:16 | 720p, 1080p | 4, 6, 8 | 3 – 4 |\n| Veo 3 | `veo-3` | 16:9, 9:16 | 720p, 1080p | 4, 6, 8 | 6 – 11 |\n| Veo 3 Fast | `veo-3-fast` | 16:9, 9:16 | 720p, 1080p | 4, 6, 8 | 3 – 4 |\n| Seedance 2 | `seedance-2` | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9, auto | 480p, 720p, 1080p | 4 – 15 | 2.28 – 12.16 |\n| Seedance 2 Fast | `seedance-2-fast` | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9, auto | 480p, 720p | 4 – 15 | 1.82 – 3.9 |\n| Seedance 2 Mini | `seedance-2-mini` | 16:9, 9:16, 1:1, 4:3, 3:4, 21:9, auto | 480p, 720p | 4 – 15 | 2 – 3 |\n| Seedance 1.5 Pro | `seedance-1-5-pro` | 16:9, 9:16, auto | 720p, 1080p | 5, 8, 12 | 0.68 – 3.17 |\n| Seedance Pro | `seedance-1-pro` | 16:9, 9:16, auto | 720p, 1080p | 5, 8, 12 | 1.34 – 3.18 |\n| Kling 3.0 Omni | `kling-3-omni` | 16:9, 9:16, 1:1, auto | 720p, 1080p | 3 – 15 | 5 – 8 |\n| Kling O1 | `kling-o1` | 16:9, 9:16, 1:1, auto | 720p, 1080p | 3 – 10 | 3 – 5 |\n| Kling 2.6 Pro | `kling-2-6-pro` | 16:9, 9:16, 1:1, auto | 1080p | 5, 10 | 2 – 4 |\n| Minimax Hailuo | `minimax-hailuo-02` | 16:9, 9:16, 1:1 | 512P, 768P, 1080P | 6, 10 | 1.33 |\n| Minimax Hailuo 2.3 | `minimax-hailuo-2-3` | 16:9, 9:16, 1:1, auto | 768P, 1080P | 6, 10 | 1.33 – 2 |\n| Grok Imagine Video | `grok-imagine-video` | 16:9, 9:16, 3:4, 4:3, 1:1, 3:2, 2:3, auto | 480p, 720p | 1 – 15 | 2 |\n| Happy Horse | `happy-horse-1-0` | 16:9, 9:16, 1:1, 4:3, 3:4, auto | 720p, 1080p | 3 – 15 | 4 – 8 |\n\nWhere a credit range is shown, the exact rate depends on the selected\nresolution and/or audio toggle — each engine's `cost` array in\n`/faceless/options?only=clip_engines` lists the exact rate per combination.\nThe storyboard `settings.aspect_ratio` and `settings.resolution` must be\nvalues the chosen engine supports. For the exact credit total of a storyboard,\ncall `GET /text-to-scene/{storyboard}/estimate` before rendering."
    },
    {
      "name": "Voice Clones",
      "description": "Clone a narration voice from audio samples, manage voice-clone slots, and list, update, or delete your clones."
    },
    {
      "name": "Ideas",
      "description": "Discover and rank content ideas for a keyword on a given network."
    },
    {
      "name": "Characters",
      "description": "Build reusable AI characters: browse genres, create from a reference photo, generate previews, and train a consistent character."
    }
  ]
}
