# Get Agent Node Source: https://docs.mosaic.so/api/agent-nodes/get-agent-node GET /agent_nodes/{agent_node_id} Get a single agent node instance. Returns a single agent node instance from your organization’s workspaces. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent_nodes/[agent_node_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "agent_node": { "agent_node_id": "4e2e1ac5-2ca2-4e5c-9b1d-469b6062e704", "node_type": { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" }, "params_used": { "use_intelligent_analysis": true, "genre": "Cinematic" } } } ``` ## Response Fields | Field | Type | Description | | -------------------------------------- | -------------- | -------------------------------------------------------- | | `agent_node.agent_node_id` | string | Agent node instance ID (UUID). | | `agent_node.node_type.node_type_id` | string | Node type ID for this agent node. | | `agent_node.node_type.node_type_name` | string \| null | Node type display name. | | `agent_node.node_type.docs_url` | string \| null | Canonical docs page URL (from `nodes.docs_path`). | | `agent_node.node_type.params_docs_url` | string \| null | Exact params/API section URL (from `nodes.docs_anchor`). | | `agent_node.params_used` | object | Current params configured on this node instance. | For node type catalog lookups, use [GET /node\_types](/api/agent-nodes/get-agent-nodes) and [GET /node\_type/](/api/node-types/get-node-type). # List Node Types Source: https://docs.mosaic.so/api/agent-nodes/get-agent-nodes GET /node_types List all available node types. Returns all available node types for your organization. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/node_types" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "node_types": [ { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" } ] } ``` ## Returned Fields | Field | Type | Description | | ----------------- | -------------- | -------------------------------------------------------- | | `node_type_id` | string | Node type ID (UUID). | | `node_type_name` | string \| null | Node type display name. | | `docs_url` | string \| null | Canonical docs page URL (from `nodes.docs_path`). | | `params_docs_url` | string \| null | Exact params/API section URL (from `nodes.docs_anchor`). | # Get Agent Run Source: https://docs.mosaic.so/api/agent-runs/get-agent-run GET /agent_run/{run_id} Get status and outputs for a run. Poll this endpoint to check the status of your agent run and retrieve outputs. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent_run/[run_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "agent_id": "123e4567-e89b-12d3-a456-789012345678", "started_at": "2025-01-10T14:30:00Z", "status": "completed", "status_message": null, "needs_credits": false, "errors": [], "node_status_counts": { "completed": 10, "in_progress": 0, "failed": 0 }, "inputs": [ { "video_url": "https://storage.googleapis.com/mosaic-inputs/...", "thumbnail_url": "https://storage.googleapis.com/mosaic-inputs/..." } ], "outputs": [ { "id": "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "video_url": "https://storage.googleapis.com/mosaic-outputs/...", "thumbnail_url": "https://storage.googleapis.com/mosaic-thumbnails/...", "premiere_prproj_url": "https://storage.googleapis.com/mosaic-outputs/.../timeline.zip?...", "sources": [ { "provider": "getty", "source_kind": "licensed_library", "media_type": "image", "provider_asset_id": "1234567890", "render_asset_id": "getty_image_000", "query": "mayor press conference", "title": "Mayor speaks at press conference", "credit": "Photographer / Collection", "source_url": "https://www.gettyimages.com/detail/...", "display_url": "https://media.gettyimages.com/...", "rights_status": "licensed", "start_ms": 1200, "end_ms": 3400, "start_seconds": 1.2, "end_seconds": 3.4, "placement": "partial_screen", "layout": "bottom", "getty_asset_family": "editorial", "source_metadata": {}, "rights_metadata": {} } ], "completed_at": "2025-01-10T14:35:30Z", "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8" } ] } ``` ## Output Fields | Field | Type | Description | | --------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `string` | Unique identifier for this output render | | `video_url` | `string` | Signed URL to download the rendered video (valid for 7 days) | | `thumbnail_url` | `string \| null` | Signed URL to download the video thumbnail | | `premiere_prproj_url` | `string \| null` | Signed URL to download the Premiere Pro timeline zip attached to this render (when available) | | `sources` | `array` | Source citations for licensed or external media used in this output. Getty b-roll citations include timing, query, asset IDs when resolved, placement, and rights metadata. | | `completed_at` | `string` | ISO 8601 timestamp when this output finished rendering | | `original_node_id` | `string \| null` | Template agent\_node\_id this output originated from. Use this to map outputs to specific nodes in your agent. | **Tracking outputs**: Use `original_node_id` to identify which node in your agent template produced each output. This allows you to consistently map outputs to your application logic across multiple runs. ## Source Fields | Field | Type | Description | | ------------------------------------- | ---------------- | -------------------------------------------------------------------------------------- | | `provider` | `string` | Source provider, for example `getty`. | | `media_type` | `string` | `image`, `video`, or another media type. | | `provider_asset_id` | `string \| null` | Provider asset ID, such as the Getty image/video ID, when resolved. | | `render_asset_id` | `string \| null` | Internal render/timeline asset ID. | | `query` | `string \| null` | Search query used to choose the source. | | `start_ms` / `end_ms` | `number \| null` | Usage window in the rendered output. | | `placement` / `layout` | `string \| null` | How the media was placed, such as `full_screen`, `partial_screen`, `top`, or `bottom`. | | `source_metadata` / `rights_metadata` | `object` | Provider-specific metadata and rights details when available. | ## Run Fields | Field | Type | Description | | -------------------- | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `agent_id` | `string` | Agent UUID that started this run. | | `status` | `string` | Overall run status (see Status Values below). | | `status_message` | `string \| null` | Human-readable detail about the run status. | | `needs_credits` | `boolean` | `true` when one or more runtime tasks in this run are marked `needs_credits=true` (insufficient credits). | | `errors` | `array` | Error messages grouped by template node. Each entry has `original_node_id` and `messages[]`. Empty array `[]` when the run has no errors. | | `node_status_counts` | `object` | Counts of nodes in `completed`, `in_progress`, and `failed` states. | For node-level statuses, error details, and credit-blocked details, use [Get Agent Run Nodes](/api/agent-runs/get-agent-run-nodes). If `needs_credits` is `true`, first check `GET /plan`. If no paid plan is active, choose one via `GET /plan/list` and `POST /plan/upgrade` (complete checkout when `requires_checkout: true`). You can then enable auto top-ups with `POST /credits/settings` if your active plan is `creator`, `creator_annual`, `professional`, or `professional_annual`, and finally call [Resume Agent Run](/api/agent-runs/post-agent-run-resume) to re-queue failed/blocked runtime nodes in the same run. ## Status Values | Status | Description | | ------------------ | ----------------------------------------------------- | | `running` | Agent is processing your videos | | `completed` | Processing finished successfully | | `partial_complete` | Some outputs finished successfully, but others failed | | `failed` | The entire run failed, no outputs generated | | `cancelled` | The run was cancelled by the user | # Get Agent Run Nodes Source: https://docs.mosaic.so/api/agent-runs/get-agent-run-nodes GET /agent_run/{run_id}/nodes Get node-level status details for a run. Returns node-level status for a run, including node type metadata and whether a node is currently blocked by credits. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent_run/[run_id]/nodes" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "nodes": [ { "agent_node_id": "11111111-1111-1111-1111-111111111111", "original_node_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "status": "failed", "status_message": "Insufficient credits", "errors": ["Audio transcription timed out after 300s"], "node_type": { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" }, "needs_credits": true } ] } ``` ## Response Fields | Field | Type | Description | | -------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------- | | `run_id` | `string` | Agent run ID. | | `nodes[].agent_node_id` | `string` | Runtime node ID for this run. | | `nodes[].original_node_id` | `string \| null` | Template `agent_node_id` this runtime node was cloned from. | | `nodes[].status` | `string` | Current node status. | | `nodes[].status_message` | `string \| null` | Optional node status detail. | | `nodes[].errors` | `array` | Error messages from failed tasks in this node. Empty array when the node has no errors. | | `nodes[].node_type` | `object` | Node type metadata, including docs links. | | `nodes[].needs_credits` | `boolean` | `true` when any runtime task attached to the node is marked `needs_credits=true` (insufficient credits). | When a failed or blocked node has `needs_credits=true`, top up credits and call [Resume Agent Run](/api/agent-runs/post-agent-run-resume) to continue the run. # List Agent Runs Source: https://docs.mosaic.so/api/agent-runs/get-agent-runs GET /agent/{agent_id}/runs List recent runs for an agent with pagination and optional status/date filters. Lists recent runs for one agent. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent/[agent_id]/runs?limit=25&status=running,completed" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | -------- | ------ | -------- | ------------------------------------------------------------ | | `limit` | number | No | Page size (`1-100`, default `25`). | | `cursor` | string | No | Pagination cursor from `next_cursor`. | | `status` | string | No | Comma-separated statuses (for example: `running,completed`). | | `from` | string | No | ISO timestamp lower bound on `created_at`. | | `to` | string | No | ISO timestamp upper bound on `created_at`. | ## Response ```json theme={null} { "runs": [ { "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "status": "completed", "status_message": null, "started_at": "2026-03-02T09:00:00Z", "updated_at": "2026-03-02T09:06:00Z", "node_status_counts": { "completed": 10, "in_progress": 0, "failed": 0 }, "inputs": [], "outputs": [ { "id": "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "video_url": "https://storage.googleapis.com/mosaic-outputs/...", "thumbnail_url": "https://storage.googleapis.com/mosaic-thumbnails/...", "premiere_prproj_url": "https://storage.googleapis.com/mosaic-outputs/.../timeline.zip?...", "completed_at": "2026-03-02T09:06:00Z", "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8" } ], "triggered_by": null } ], "next_cursor": null } ``` `outputs[]` uses the same shape as [Get Agent Run](/api/agent-runs/get-agent-run), including `premiere_prproj_url` when a Premiere Pro timeline package is attached to the render and `sources[]` when the output contains source citations. This summary response does **not** include `needs_credits`. To check whether a run is credit-blocked, call [Get Agent Run](/api/agent-runs/get-agent-run) (run-level) and/or [Get Agent Run Nodes](/api/agent-runs/get-agent-run-nodes) (node-level). # List All Agent Runs Source: https://docs.mosaic.so/api/agent-runs/get-all-agent-runs GET /agent_runs List runs across all agents in your organization. Returns run summaries across every agent your API key can access. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent_runs?limit=25&status=running,completed" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | ---------- | ------ | -------- | ----------------------------------------------- | | `limit` | number | No | Page size (`1-100`, default `25`). | | `cursor` | string | No | Pagination cursor from `next_cursor`. | | `status` | string | No | Comma-separated statuses (`running,completed`). | | `from` | string | No | ISO timestamp lower bound on `created_at`. | | `to` | string | No | ISO timestamp upper bound on `created_at`. | | `agent_id` | string | No | Filter runs to one agent ID. | ## Response ```json theme={null} { "runs": [ { "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "status": "completed", "status_message": null, "started_at": "2026-03-02T09:00:00Z", "updated_at": "2026-03-02T09:06:00Z", "node_status_counts": { "completed": 10, "in_progress": 0, "failed": 0 }, "inputs": [], "outputs": [], "triggered_by": null } ], "next_cursor": null } ``` `outputs[]` uses the same shape as [Get Agent Run](/api/agent-runs/get-agent-run), including `premiere_prproj_url` when a Premiere Pro timeline package is attached to the render and `sources[]` when the output contains source citations. This summary response does **not** include `needs_credits`. To check whether a run is credit-blocked, call [Get Agent Run](/api/agent-runs/get-agent-run) (run-level) and/or [Get Agent Run Nodes](/api/agent-runs/get-agent-run-nodes) (node-level). # List Trigger Runs Source: https://docs.mosaic.so/api/agent-runs/get-trigger-runs GET /trigger/{trigger_id}/runs List runs started by a specific trigger. Returns run summaries for one trigger ID. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/trigger/[trigger_id]/runs?limit=25" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | -------- | ------ | -------- | ----------------------------------------------- | | `limit` | number | No | Page size (`1-100`, default `25`). | | `cursor` | string | No | Pagination cursor from `next_cursor`. | | `status` | string | No | Comma-separated statuses (`running,completed`). | | `from` | string | No | ISO timestamp lower bound on `created_at`. | | `to` | string | No | ISO timestamp upper bound on `created_at`. | ## Response ```json theme={null} { "runs": [ { "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "status": "completed", "status_message": null, "started_at": "2026-03-02T09:00:00Z", "updated_at": "2026-03-02T09:06:00Z", "node_status_counts": { "completed": 10, "in_progress": 0, "failed": 0 }, "inputs": [], "outputs": [], "triggered_by": { "trigger_id": "9cb911f5-7e2e-473d-8de0-9f5e2b7c95c1" } } ], "next_cursor": null } ``` `outputs[]` uses the same shape as [Get Agent Run](/api/agent-runs/get-agent-run), including `premiere_prproj_url` when a Premiere Pro timeline package is attached to the render and `sources[]` when the output contains source citations. # Run Agent Source: https://docs.mosaic.so/api/agent-runs/post-agent-run POST /agent/{agent_id}/run Execute an agent workflow on videos or run generation-only workflows. Execute an agent workflow. Supports standard video-input workflows and generation-only workflows such as AI Avatar, Video Generation, Audio Generation, and Image Generation. ## Canonical input model Treat `video_inputs` as the canonical run input shape: * `video_inputs[]` entries map assets to a specific `Video Input` tile (`agent_node_id`) * each entry accepts one or more sources: `video_ids`, `node_render_ids`, `video_urls` * optional `input_clip_start_ms` / `input_clip_end_ms` fields can limit the source range used for a run Top-level fields (`video_ids`, `node_render_ids`, `video_urls`) are shorthand for single-input runs. ## Single-input shorthand If your runnable graph has one `Video Input` tile, you can send top-level input arrays without specifying `agent_node_id`. ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "video_urls": [ "https://www.youtube.com/watch?v=dQw4w9WgXcQ" ], "callback_url": "https://your-webhook.com/callback" }' ``` Example using `video_ids` (from the [Uploads API](/api/asset-management/upload-flow)): ```json theme={null} { "video_ids": [ "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" ], "callback_url": "https://your-webhook.com/callback" } ``` Example using `node_render_ids` (from previous run outputs): ```json theme={null} { "node_render_ids": [ "7ba7b810-9dad-11d1-80b4-00c04fd430c8" ], "callback_url": "https://your-webhook.com/callback" } ``` ## Multi-input workflows If your agent has multiple runnable `Video Input` tiles, you must use `video_inputs` and provide an entry for each runnable input tile. In that mode, do not also send top-level input arrays. You can get each `agent_node_id` from `GET /agent/[agent_id]` or from the Mosaic editor's API info panel for that tile. ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "video_inputs": [ { "agent_node_id": "11111111-1111-1111-1111-111111111111", "video_ids": ["aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"] }, { "agent_node_id": "22222222-2222-2222-2222-222222222222", "video_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"] } ], "callback_url": "https://your-webhook.com/callback" }' ``` ## Generation-Only Workflows For workflows starting with generation nodes and no Video Input node, no video inputs should be provided. These agents generate media based on the parameters configured in the agent, or on `update_params` you pass at run time. Generation node type IDs: | Node | Node type ID | Docs | | ---------------- | -------------------------------------- | ---------------------------------------------------- | | AI Avatar | `b3b4c9e2-2a47-4fa9-8ce8-0c1fa1d7b6ef` | [AI Avatar](/tiles/ai-avatar#api-info) | | Video Generation | `a2eb3ec2-da7a-4f97-94d2-a9a537548522` | [Video Generation](/tiles/video-generation#api-info) | | Audio Generation | `14687f30-5fd0-468f-8239-2784d83df95b` | [Audio Generation](/tiles/audio-generation#api-info) | | Image Generation | `18b998a0-2ea7-4676-a5d3-3ae6c8ac0b72` | [Image Generation](/tiles/image-generation#api-info) | To create a generation-only agent, use [Create Agent](/api/agents/post-agent-create), then add one of these nodes with [Update Agent](/api/agents/post-agent-update). Run that agent without `video_inputs`, `video_ids`, `video_urls`, or `node_render_ids`. ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "callback_url": "https://your-webhook.com/callback", "update_params": { "NODE_ID": { "prompt": "A cinematic product teaser with dramatic lighting" } } }' ``` For AI Avatar, create an avatar first with [`POST /avatar-profiles/create`](/api/avatar-profiles/create-avatar-profile), then pass the avatar ID into the avatar node: ```json theme={null} { "callback_url": "https://your-webhook.com/callback", "update_params": { "AI_AVATAR_AGENT_NODE_ID": { "avatar_profile_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "video_model": "seedance-2-fast", "single_take": false, "script": "Here is the exact script the avatar should say." } } } ``` Video Generation example: ```json theme={null} { "callback_url": "https://your-webhook.com/callback", "update_params": { "VIDEO_GENERATION_AGENT_NODE_ID": { "prompt": "A cinematic product teaser with dramatic lighting", "model": "seedance-2", "resolution": "1080p", "duration": "8", "aspect_ratio": "16:9" } } } ``` Use `model: "seedance-2"` and `resolution: "4k"` for 4K output. 4K resolution is billed at 2x normal Seedance. Audio Generation example: ```json theme={null} { "callback_url": "https://your-webhook.com/callback", "update_params": { "AUDIO_GENERATION_AGENT_NODE_ID": { "mode": "music", "music_prompt": "Upbeat electronic background music for a product launch", "music_length_ms": 30000 } } } ``` Image Generation example: ```json theme={null} { "callback_url": "https://your-webhook.com/callback", "update_params": { "IMAGE_GENERATION_AGENT_NODE_ID": { "prompt": "A clean hero image of a modern video editing workspace", "image_size": "landscape_4_3", "quality": "high" } } } ``` ## Parameters | Field | Type | Required | Description | | --------------------- | --------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `video_inputs` | object\[] | Conditional | Canonical per-tile input mapping. Each entry must include `agent_node_id` plus at least one of `video_ids`, `node_render_ids`, `video_urls`, or `mimir_assets`. Required for multi-input runs. | | `video_ids` | string\[] | Conditional | Top-level shorthand for single-input runs. Video UUIDs from the Uploads API (or existing workspace video assets). | | `node_render_ids` | string\[] | Conditional | Top-level shorthand for single-input runs. Render IDs from prior run outputs (`GET /agent_run/{run_id}` -> `outputs[].id`) or run webhooks. | | `video_urls` | string\[] | Conditional | Top-level shorthand for single-input runs. Video URLs to ingest (YouTube and signed URLs). | | `input_clip_start_ms` | integer | | Optional start offset applied to all top-level input arrays. Can be sent by itself (trim from this offset to the end) or with `input_clip_end_ms`. | | `input_clip_end_ms` | integer | | Optional end offset applied to all top-level input arrays. Can be sent by itself (trim from `0` to this offset) or with `input_clip_start_ms`. For URL inputs, Mosaic cuts the downloaded asset before uploading it to the run. | | `video_id_inputs` | object\[] | Conditional | Per-item form for existing uploaded videos. Each object accepts `id`, `input_clip_start_ms`, and `input_clip_end_ms`. | | `node_render_inputs` | object\[] | Conditional | Per-item form for previous render outputs. Each object accepts `id`, `input_clip_start_ms`, and `input_clip_end_ms`. | | `video_url_inputs` | object\[] | Conditional | Per-item form for external/signed URLs. Each object accepts `url`, `input_clip_start_ms`, and `input_clip_end_ms`. | | `youtube_url_inputs` | object\[] | Conditional | Per-item form for YouTube URLs. Each object accepts `url`, `input_clip_start_ms`, and `input_clip_end_ms`. | | `mimir_assets` | object\[] | Conditional | Mimir assets to ingest. Each object has `id` (Mimir item UUID), optional `artifact` (`highres`, `proxy`, or `auto`; defaults to `highres`), and optional `input_clip_start_ms` / `input_clip_end_ms`. Requires a [Mimir connection](#mimir-integration). | | `callback_url` | string | | Optional webhook URL for status updates | | `update_params` | object | | Optional parameters to override node parameters in the agent workflow. Keys must be valid `agent_node_id` values from the runnable graph. | | `ignore_nodes` | string\[] | | Optional list of `agent_node_id` values to bypass for this run. Mosaic removes each ignored node from the runtime graph and rewires incoming edges directly to its downstream nodes. | Input rules: * Use **either** top-level input arrays **or** `video_inputs` (not both in the same request). * If the runnable graph has multiple `Video Input` tiles, provide one `video_inputs` entry for each runnable input tile. * `node_render_ids` are valid video inputs (top-level shorthand for single-input runs, or per-entry in `video_inputs`). * `mimir_assets` can be combined with other input types in the same entry. * If you need different start/end ranges for different inputs, use `video_id_inputs`, `node_render_inputs`, `video_url_inputs`, or `youtube_url_inputs` instead of the plain string arrays. * `input_clip_start_ms` and `input_clip_end_ms` are independent optional fields; if both are provided, `input_clip_end_ms` must be greater than `input_clip_start_ms`. ID source rules: * `video_ids` come from the [Uploads API](/api/asset-management/upload-flow). * `node_render_ids` come from previous run outputs (`GET /agent_run/{run_id}` -> `outputs[].id`) or run webhooks. ## Input Clipping You can run an agent on a segment of a source video by passing millisecond offsets. This is useful when you only want the first part of a long video or when billing should match the portion actually processed. Top-level clipping applies the same range to every top-level input: ```json theme={null} { "youtube_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "input_clip_start_ms": 0, "input_clip_end_ms": 1200000, "callback_url": "https://your-webhook.com/callback" } ``` For URL inputs, Mosaic cuts the downloaded file before it is uploaded as the run input. For existing `video_ids` and `node_render_ids`, Mosaic creates a clipped timeline/render input for the requested range. You can also send only one side of the range: `input_clip_start_ms` only (trim from start offset to end of source): ```json theme={null} { "video_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "input_clip_start_ms": 45000, "callback_url": "https://your-webhook.com/callback" } ``` `input_clip_end_ms` only (trim from `0` to end offset): ```json theme={null} { "video_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"], "input_clip_end_ms": 90000, "callback_url": "https://your-webhook.com/callback" } ``` Use the object input forms when each source needs its own range: ```json theme={null} { "video_inputs": [ { "agent_node_id": "11111111-1111-1111-1111-111111111111", "youtube_url_inputs": [ { "url": "https://www.youtube.com/watch?v=VIDEO_ONE", "input_clip_start_ms": 0, "input_clip_end_ms": 900000 }, { "url": "https://www.youtube.com/watch?v=VIDEO_TWO", "input_clip_start_ms": 30000, "input_clip_end_ms": 630000 } ], "node_render_inputs": [ { "id": "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "input_clip_start_ms": 0, "input_clip_end_ms": 600000 } ], "mimir_assets": [ { "id": "b60d57d2-4b12-a80c-6f14-c5eefaa91460", "artifact": "highres", "input_clip_start_ms": 120000, "input_clip_end_ms": 720000 } ] } ], "callback_url": "https://your-webhook.com/callback" } ``` ## Video URL Requirements & Limits The `video_urls` field supports two types of URLs: **YouTube URLs:** * Supports standard YouTube video URLs (e.g., `https://www.youtube.com/watch?v=VIDEO_ID`) * **Maximum duration**: 5 hours per video * The system automatically validates the video exists and checks duration before processing **Signed URLs (HTTP/HTTPS):** * Must be HTTP or HTTPS URLs pointing to video files * **Maximum file size**: 5 GB per video * **Maximum duration**: 5 hours per video ## Modifying Node Parameters You can override specific parameters for any node in your agent workflow using the `update_params` field. This allows you to dynamically change behavior (like clip duration, prompt text, or number of clips) at runtime. To find the correct parameters: 1. Open your agent in the [Mosaic Dashboard](https://edit.mosaic.so) 2. Click the settings menu on the node you want to modify 3. Scroll down to the **API info** dropdown 4. Open the dropdown to find the `Agent node ID` 5. Click **Copy params** to get the JSON structure The copied JSON will look like this, where the key is the **agent\_node\_id** (UUID) and the value object contains the parameters you can override: ```json theme={null} { "bf750792-a2e9-48c2-9d39-24f892772f6a": { "num_clips": 10, "target_duration": 60 } } ``` Pass this entire object as the `update_params` value in your API request. ### `update_params` validation behavior Mosaic validates `update_params` before creating the run: * Unknown `agent_node_id` keys return `400` * Invalid parameter types/values return `400` * Protected/system nodes (for example Video Input/Destination/trigger nodes) cannot be overridden with `update_params` If validation fails, the run is **not** created. ## Bypassing Nodes at Runtime Use `ignore_nodes` to skip one or more nodes for a single run without editing the saved agent template. For each ignored node: * Incoming connections to the node are rewired to its downstream nodes * The ignored node is removed from the runtime DAG for that run only * The template itself is unchanged ```json theme={null} { "video_urls": ["https://youtube.com/watch?v=..."], "ignore_nodes": [ "8cbfd03e-6e85-4f3d-b4b9-8de0b5bfb6a4" ], "update_params": { "35a12345-6789-abcd-ef01-234567890abc": { "audio_id": "your-uploaded-audio-uuid" } } } ``` ## Uploading Media for Node Parameters Some nodes accept **images**, **audio**, or **videos** as parameters. To set these programmatically, use the [Uploads API](/api/asset-management/upload-flow) to upload your files and get their UUIDs: ```json theme={null} { "video_urls": ["https://youtube.com/watch?v=..."], "update_params": { "35a12345-6789-abcd-ef01-234567890abc": { "audio_id": "your-uploaded-audio-uuid" }, "76b23456-7890-efab-cd12-345678901bcd": { "image_id": "your-uploaded-image-uuid" } } } ``` See the [Upload Flow](/api/asset-management/upload-flow) for the complete upload process. ## Chaining Runs with `node_render_ids` You can feed outputs from a previous run directly into another run by passing render IDs returned in webhooks or from `GET /agent_run/[run_id]` (`outputs[].id`). Single-input shorthand: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "node_render_ids": [ "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "8cbfd03e-6e85-4f3d-b4b9-8de0b5bfb6a4" ], "callback_url": "https://your-webhook.com/callback" }' ``` Canonical `video_inputs` form: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "video_inputs": [ { "agent_node_id": "11111111-1111-1111-1111-111111111111", "node_render_ids": [ "7ba7b810-9dad-11d1-80b4-00c04fd430c8" ] } ], "callback_url": "https://your-webhook.com/callback" }' ``` ## Mimir Integration Mosaic can ingest video directly from [Mimir](https://mimir.mjoll.no) using `mimir_assets`. This downloads the video from your Mimir instance, stores Mimir metadata (item ID, artifact type, connection details) as `source_info` on the video record, and makes it available for Premiere Pro linking in downstream tiles. ### Prerequisites 1. Go to **Settings > Integrations** in the [Mosaic dashboard](https://edit.mosaic.so). 2. Add your Mimir instance URL (e.g. `https://mimir.mjoll.no`) and an API key generated from your Mimir user settings. 3. Mosaic verifies the connection on save. If verification fails, check that the URL and API key are correct. ### Single Mimir asset ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "mimir_assets": [ { "id": "b60d57d2-4b12-a80c-6f14-c5eefaa91460", "artifact": "highres" } ], "callback_url": "https://your-webhook.com/callback" }' ``` ### Multiple Mimir assets with different artifacts ```json theme={null} { "mimir_assets": [ { "id": "b60d57d2-4b12-a80c-6f14-c5eefaa91460", "artifact": "highres" }, { "id": "a1e0b6bd-d3be-4d1b-a529-41dd8927325e", "artifact": "proxy" } ], "callback_url": "https://your-webhook.com/callback" } ``` ### Mimir assets in multi-input workflows ```json theme={null} { "video_inputs": [ { "agent_node_id": "11111111-1111-1111-1111-111111111111", "mimir_assets": [ { "id": "b60d57d2-4b12-a80c-6f14-c5eefaa91460" } ] }, { "agent_node_id": "22222222-2222-2222-2222-222222222222", "video_urls": ["https://www.youtube.com/watch?v=dQw4w9WgXcQ"] } ], "callback_url": "https://your-webhook.com/callback" } ``` ### `mimir_assets` entry schema | Field | Type | Required | Description | | --------------------- | ------------- | -------- | ---------------------------------------------------------------------------- | | `id` | string (UUID) | Yes | Mimir item ID. | | `artifact` | string | No | Which artifact variant to download (see table below). Defaults to `highres`. | | `input_clip_start_ms` | integer | No | Optional start offset for this Mimir asset. | | `input_clip_end_ms` | integer | No | Optional end offset for this Mimir asset. | #### Artifact options | Value | Behavior | | --------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `highres` | Downloads the high-resolution source file. **Default** when `artifact` is omitted. Returns `400` if the item has no highres available. | | `proxy` | Downloads the lower-resolution proxy. Returns `400` if the item has no proxy available. | | `auto` | Prefers highres if available, falls back to proxy. Returns `400` only if neither is available. | Regardless of which artifact is downloaded, the Mimir item ID is always stored in `source_info` so Premiere Pro exports can link back to the original asset in Mimir. `mimir_assets` require an **organization-scoped API key** (`mk_` prefix). The Mimir connection itself is **workspace-scoped** — configure it per workspace in Settings → Integrations. If no Mimir connection is configured for the agent's workspace, the API returns a `400` error explaining how to set one up. ### How Mimir metadata flows When a Mimir asset is ingested: 1. Mosaic fetches the item details from your Mimir instance. 2. The selected artifact URL (highres or proxy) is downloaded. 3. Mimir metadata (item ID, artifact type, connection details) is stored in `videos.source_info`. 4. Downstream tiles (e.g. News UK, Sun) that generate Premiere Pro projects use this metadata to link clips back to Mimir. ## Agent graph best practices * For "shorter/tighter" edits, place `Rough Cut` and/or `Clips` before style-heavy nodes. * Place `Reframe` before `Captions`, `Cinematic Captions`, `Motion Graphics`, and `Watermark` so overlays are composed against final framing. * Keep `update_params` minimal and explicit (only send fields you want to override). ## Publish to social after render After run completion, retrieve `outputs[].video_url` from `GET /agent_run/[run_id]` and send that URL in `media_urls` to [`POST /social/post`](/api/social/post-social-post). ## Response ```json theme={null} { "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d" } ``` The `run_id` is used to track the progress of your agent run. # Cancel Agent Run Source: https://docs.mosaic.so/api/agent-runs/post-agent-run-cancel POST /agent_run/{run_id}/cancel Cancel an in-progress run. Cancels an active run and prevents additional downstream processing. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent_run/[run_id]/cancel" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "success": true, "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "tasks_cancelled": 2, "nodes_reset": 3, "message": "Agent run cancelled successfully" } ``` # Resume Agent Run Source: https://docs.mosaic.so/api/agent-runs/post-agent-run-resume POST /agent_run/{run_id}/resume Resume a failed or cancelled run. Resumes a failed or cancelled run by re-queueing eligible runtime nodes. Trigger/source nodes are excluded from resume. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent_run/[run_id]/resume" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "success": true, "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "agent_state_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "nodes_queued": 4, "nodes_considered": 7, "requeued_nodes": 4, "requeued_node_tasks_detached": 4, "requeued_node_active_tasks_cancelled": 1, "requeued_node_active_tasks_total": 1 } ``` ## Notes * Run status must be `failed` or `cancelled` * Resume only re-queues runtime nodes (`not_started`, `blocked`, `cancelled`, `failed`) * Trigger node types are never resumed * Existing trigger metadata is preserved, and resume metadata is appended If the run cannot be resumed in its current state, Mosaic returns `409` with a `detail` message. ## Credit-blocked runs (`needs_credits`) Use this endpoint to continue runs that failed because of insufficient credits: 1. Detect credit-blocking via `GET /agent_run/{run_id}` (`needs_credits: true`) and/or `GET /agent_run/{run_id}/nodes` (`nodes[].needs_credits: true`). 2. Check the current plan with `GET /plan`. 3. If you are on a free/no paid plan: * List purchasable plans with `GET /plan/list`. * Upgrade with `POST /plan/upgrade`. * If upgrade returns `requires_checkout: true`, complete checkout at `checkout_url`, then re-check `GET /plan`. 4. Optionally enable auto top-ups with `POST /credits/settings` (eligible plans only: `creator`, `creator_annual`, `professional`, `professional_annual`). 5. Call `POST /agent_run/{run_id}/resume` to re-queue eligible failed/blocked runtime nodes. # Creating Agents Source: https://docs.mosaic.so/api/agents/creating-agents Create, update, duplicate, and delete agent templates through the API. You can now create and maintain agents directly from the public API. ## Endpoints * [POST /agent/create](/api/agents/post-agent-create) creates a new agent. * [POST /agent//update](/api/agents/post-agent-update) updates metadata and mutates graph structure. * [POST /agent//duplicate](/api/agents/post-agent-duplicate) duplicates an agent and returns its copied graph payload. * [POST /agent//delete](/api/agents/post-agent-delete) soft-deletes an agent. ## Generation Agents For AI Avatar, Video Generation, Audio Generation, and Image Generation, create a metadata-only agent with `POST /agent/create`, then add the generation node with `POST /agent/{agent_id}/update`. Generation-only agents do not need Video Input nodes. Run them with `POST /agent/{agent_id}/run` and no video inputs. See [Run Agent](/api/agent-runs/post-agent-run#generation-only-workflows) for generation-only run examples. ## Agent Graph Model Graph mutations happen via `POST /agent/{agent_id}/update` using ordered `operations` with create/update/delete node/connection steps. In this contract: * Node params are validated server-side using tile metadata and node schemas. * Position is backend-managed (auto-layout), not client-managed. * Agent node responses are represented as `agent_node_id`, `node_type`, and `params_used` (`node_type` contains `node_type_id` and docs metadata). * New nodes in `create_node` operations can only use request-scoped `temp_ref_id`; persisted `agent_node_id` values are backend-generated and returned in the response. * `temp_ref_id` values are never persisted and only work within the single update request where they are created. ## Optional Dashboard Flow You can still create agents in [edit.mosaic.so](https://edit.mosaic.so) and use the API to run them. ## Next Steps * Use [GET /agent/\[agent\_id\]](/api/agents/get-agent) to inspect your template * Use [POST /agent/\[agent\_id\]/duplicate](/api/agents/post-agent-duplicate) to clone an existing template graph * Use [POST /agent/\[agent\_id\]/update](/api/agents/post-agent-update) for both metadata and graph mutations * Use [POST /agent/\[agent\_id\]/run](/api/agent-runs/post-agent-run) to execute it * Use [GET /node\_types](/api/agent-nodes/get-agent-nodes) to discover available node types # Get Agent Source: https://docs.mosaic.so/api/agents/get-agent GET /agent/{agent_id} Retrieve an agent template, agent nodes, and graph connections. Returns the saved agent template with agent node instances (including embedded `node_type`) and connections. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent/[agent_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "agent": { "id": "123e4567-e89b-12d3-a456-789012345678", "name": "My Agent", "description": "", "visibility": "private", "created_at": "2026-03-01T12:00:00Z", "updated_at": "2026-03-02T08:00:00Z" }, "agent_nodes": [ { "agent_node_id": "bf750792-a2e9-48c2-9d39-24f892772f6a", "node_type": { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" }, "params_used": { "use_intelligent_analysis": true, "genre": "Cinematic" } }, { "agent_node_id": "a1c2d3e4-5678-90ab-cdef-1234567890ab", "node_type": { "node_type_id": "ea1b2c3d-4e5f-6789-0abc-def123456789", "node_type_name": "Captions", "docs_url": "https://docs.mosaic.so/tiles/captions", "params_docs_url": "https://docs.mosaic.so/tiles/captions#api-info" }, "params_used": { "caption_font": "Montserrat" } } ], "connections": [ { "source_agent_node_id": "bf750792-a2e9-48c2-9d39-24f892772f6a", "target_agent_node_id": "a1c2d3e4-5678-90ab-cdef-1234567890ab" } ] } ``` ## Response Fields | Field | Type | Description | | ----------------------------------------- | -------------- | ----------------------------------------------------------------------------------------------------- | | `agent.id` | string | Agent ID. | | `agent.name` | string | Agent display name. | | `agent.description` | string | Agent description. | | `agent.visibility` | string \| null | Visibility setting (`public` or `private`). | | `agent.created_at` | string | ISO timestamp. | | `agent.updated_at` | string | ISO timestamp. | | `agent_nodes[].agent_node_id` | string | Agent node instance ID. Use this in `operations[].agent_node_id` for `update_node` and `delete_node`. | | `agent_nodes[].node_type.node_type_id` | string | Node type ID for this agent node. | | `agent_nodes[].node_type.node_type_name` | string \| null | Node type display name for this agent node. | | `agent_nodes[].node_type.docs_url` | string \| null | Canonical docs page URL (from `nodes.docs_path`). | | `agent_nodes[].node_type.params_docs_url` | string \| null | Exact params/API section URL (from `nodes.docs_anchor`). | | `agent_nodes[].params_used` | object | Current parameter configuration for this node instance. | | `connections[]` | array | Directed edges between `agent_node_id` values in this agent graph. | # List Agents Source: https://docs.mosaic.so/api/agents/get-agents GET /agents List all agents available to the API key organization. Returns all agents scoped to your API key's organization. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agents?limit=25" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | -------- | ------ | -------- | ------------------------------------- | | `limit` | number | No | Page size (`1-100`, default `25`). | | `cursor` | string | No | Pagination cursor from `next_cursor`. | ## Response ```json theme={null} { "agents": [ { "id": "123e4567-e89b-12d3-a456-789012345678", "name": "My Agent", "description": "Weekly YouTube clip automation", "created_at": "2026-03-01T12:00:00Z", "updated_at": "2026-03-02T08:00:00Z" } ], "next_cursor": null } ``` # Create Agent Source: https://docs.mosaic.so/api/agents/post-agent-create POST /agent/create Create an agent template (metadata only). Creates a new agent template with metadata only. Graph structure is mutated later via [POST /agent//update](/api/agents/post-agent-update). `POST /agent/create` does **not** accept graph fields (`graph`, `nodes`, `connections`, `create_video_input_node`). Sending them returns a validation error. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "UGC Variants", "description": "Generate and caption UGC clips", "visibility": "private" }' ``` ## Body Parameters | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------------------------------ | | `name` | string | No | Agent name (`1-120` chars). | | `description` | string | No | Agent description (`<=5000` chars). | | `visibility` | string | No | `public` or `private`. | | `workspace_id` | string | No | Target workspace UUID. Defaults to organization primary workspace. | ## Response ```json theme={null} { "success": true, "agent_id": "a7ac4cc6-2302-4b14-8fd1-a3287bfc7606", "operations_applied": 0, "created_nodes": [] } ``` # Delete Agent Source: https://docs.mosaic.so/api/agents/post-agent-delete POST /agent/{agent_id}/delete Soft-delete an agent and detach template graph rows. Soft-deletes an agent by removing workspace scope and detaching template nodes/connections. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/123e4567-e89b-12d3-a456-789012345678/delete" \ -H "Authorization: Bearer mk_your_api_key" ``` You can also call the same operation with `DELETE /agent/{agent_id}/delete`. ## Response ```json theme={null} { "success": true, "agent_id": "123e4567-e89b-12d3-a456-789012345678", "message": "Agent deleted successfully" } ``` # Duplicate Agent Source: https://docs.mosaic.so/api/agents/post-agent-duplicate POST /agent/{agent_id}/duplicate Duplicate an agent template and return the duplicated graph. Creates a new agent by copying the source template's metadata, nodes, and connections. Response shape matches [Get Agent](/api/agents/get-agent): `agent`, `agent_nodes`, and `connections`. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/123e4567-e89b-12d3-a456-789012345678/duplicate" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Copy of My Agent", "description": "Optional override description", "visibility": "private" }' ``` All body fields are optional. ## Body Parameters | Field | Type | Required | Description | | ------------- | ------ | -------- | ----------------------------------------------------------------------------------- | | `name` | string | No | Name for the duplicated agent (`1-120` chars). Defaults to `Copy of `. | | `description` | string | No | Description override (`<=5000` chars). Defaults to source description. | | `visibility` | string | No | `public` or `private`. Defaults to source visibility. | ## Response ```json theme={null} { "agent": { "id": "9c2d2aef-58c6-4af2-845f-d7f2d4d0a9c5", "name": "Copy of My Agent", "description": "Optional override description", "visibility": "private", "created_at": "2026-03-20T20:17:00Z", "updated_at": "2026-03-20T20:17:00Z" }, "agent_nodes": [ { "agent_node_id": "bf750792-a2e9-48c2-9d39-24f892772f6a", "node_type": { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" }, "params_used": { "use_intelligent_analysis": true } } ], "connections": [ { "source_agent_node_id": "bf750792-a2e9-48c2-9d39-24f892772f6a", "target_agent_node_id": "a1c2d3e4-5678-90ab-cdef-1234567890ab" } ] } ``` # Update Agent Source: https://docs.mosaic.so/api/agents/post-agent-update POST /agent/{agent_id}/update Update agent metadata and/or mutate graph structure. Updates an existing agent. Graph mutation is action-based: send ordered `operations` (`create_node`, `update_node`, `delete_node`, `create_connection`, `delete_connection`). Node positions are always backend-managed (auto-layout). ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/123e4567-e89b-12d3-a456-789012345678/update" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "create_node", "temp_ref_id": "video_input_1", "node_type_id": "9451e6ff-ac7f-4317-9055-a2f35f641b29" }, { "op": "create_node", "temp_ref_id": "captions_1", "node_type_id": "cdccb204-168e-4aec-aa72-480b11e74324", "params_used": { "caption_style": "colored" } }, { "op": "create_connection", "source_temp_ref_id": "video_input_1", "target_temp_ref_id": "captions_1" } ] }' ``` You can also call the same operation with `PATCH /agent/{agent_id}/update`. ## Body Parameters | Field | Type | Required | Description | | -------------- | ------ | -------- | ------------------------------------------------------- | | `name` | string | No | Agent name (`1-120` chars). | | `description` | string | No | Agent description (`<=5000` chars). | | `visibility` | string | No | `public` or `private`. | | `operations[]` | array | No | Ordered graph operations for node/connection mutations. | At least one of `name`, `description`, `visibility`, or `operations` is required. ## Operation Types (Detailed) ### `create_node` | Field | Type | Required | Description | | -------------- | ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | | `op` | string | Yes | Must be `"create_node"`. | | `node_type_id` | string (UUID) | Yes | Node type to instantiate. | | `temp_ref_id` | string | No | Request-scoped temporary reference for this newly created node. Use this in later operations in the same request. Not persisted. | | `params_used` | object | No | Initial node parameters. | Backend behavior: creates a new node, assigns a persisted `agent_node_id`, and returns mapping details in `created_nodes`. You cannot supply `agent_node_id` in `create_node`; use returned IDs for later operations. `temp_ref_id` is only valid within the current update request. It is never saved and cannot be reused in future update calls. ### `update_node` | Field | Type | Required | Description | | --------------- | ------------- | -------- | ------------------------------------------------------- | | `op` | string | Yes | Must be `"update_node"`. | | `agent_node_id` | string (UUID) | Yes | Existing persisted node to update. | | `params_used` | object | Yes | Parameter patch object merged into current node params. | ### `delete_node` | Field | Type | Required | Description | | --------------- | ------------- | -------- | ---------------------------------- | | `op` | string | Yes | Must be `"delete_node"`. | | `agent_node_id` | string (UUID) | Yes | Existing persisted node to delete. | Backend behavior: also removes connections where this node is source or target. ### `create_connection` | Field | Type | Required | Description | | ---------------------- | ------------- | ----------- | --------------------------------------------------------------------------------------------------------------------- | | `op` | string | Yes | Must be `"create_connection"`. | | `source_agent_node_id` | string (UUID) | Conditional | Source existing node ID. Provide this **or** `source_temp_ref_id`. | | `source_temp_ref_id` | string | Conditional | Source temp ref from earlier `create_node` operation in the same request. Provide this **or** `source_agent_node_id`. | | `target_agent_node_id` | string (UUID) | Conditional | Target existing node ID. Provide this **or** `target_temp_ref_id`. | | `target_temp_ref_id` | string | Conditional | Target temp ref from earlier `create_node` operation in the same request. Provide this **or** `target_agent_node_id`. | Rules: * Provide exactly one source reference (`source_agent_node_id` or `source_temp_ref_id`). * Provide exactly one target reference (`target_agent_node_id` or `target_temp_ref_id`). * `source_temp_ref_id` and `target_temp_ref_id` must reference a `temp_ref_id` created by an **earlier** `create_node` operation in the same request. Mutation execution is atomic: if any operation fails validation or persistence, no graph changes are saved. Error messages include the operation step (for example, `Operation 3: ...`) to make retries deterministic. ### `delete_connection` | Field | Type | Required | Description | | ---------------------- | ------------- | ----------- | --------------------------------------------------------------------------------------------------------------------- | | `op` | string | Yes | Must be `"delete_connection"`. | | `source_agent_node_id` | string (UUID) | Conditional | Source existing node ID. Provide this **or** `source_temp_ref_id`. | | `source_temp_ref_id` | string | Conditional | Source temp ref from earlier `create_node` operation in the same request. Provide this **or** `source_agent_node_id`. | | `target_agent_node_id` | string (UUID) | Conditional | Target existing node ID. Provide this **or** `target_temp_ref_id`. | | `target_temp_ref_id` | string | Conditional | Target temp ref from earlier `create_node` operation in the same request. Provide this **or** `target_agent_node_id`. | To **rewire** a connection, send `delete_connection` then `create_connection` in the same `operations` array; execution order is preserved and applied atomically. ## Response ```json theme={null} { "success": true, "agent_id": "123e4567-e89b-12d3-a456-789012345678", "operations_applied": 3, "created_nodes": [ { "temp_ref_id": "video_input_1", "agent_node_id": "11111111-1111-1111-1111-111111111111" }, { "temp_ref_id": "captions_1", "agent_node_id": "22222222-2222-2222-2222-222222222222" } ] } ``` ## Validation Error Response When parameter validation fails, the API returns all detected issues in one response: ```json theme={null} { "detail": "Invalid node parameters: Node 11111111-1111-1111-1111-111111111111: unknown parameter 'bad_key'; Node 22222222-2222-2222-2222-222222222222: Required parameter 'prompt' is missing", "issues": [ { "code": "unknown_parameter", "message": "unknown parameter 'bad_key'", "node_id": "11111111-1111-1111-1111-111111111111", "node_type_id": "9451e6ff-ac7f-4317-9055-a2f35f641b29", "param_name": "bad_key", "operation_step": 1 }, { "code": "invalid_parameter", "message": "Required parameter 'prompt' is missing", "node_id": "22222222-2222-2222-2222-222222222222", "node_type_id": "cdccb204-168e-4aec-aa72-480b11e74324", "param_name": "prompt", "operation_step": 2 } ] } ``` # Finalize Audio Upload Source: https://docs.mosaic.so/api/asset-management/post-uploads-audio-finalize-upload POST /uploads/audio/finalize_upload Finalize a previously uploaded audio asset. Call after uploading the file bytes to the signed URL from [Create Audio Upload URL](/api/asset-management/post-uploads-audio-get-upload-url). ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/audio/finalize_upload" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{"audio_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"}' ``` ## Response ```json theme={null} { "audio_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" } ``` Use `audio_id` in `update_params` when calling [Run Agent](/api/agent-runs/post-agent-run). # Create Audio Upload URL Source: https://docs.mosaic.so/api/asset-management/post-uploads-audio-get-upload-url POST /uploads/audio/get_upload_url Create a signed upload URL for an audio asset. **Limits:** 500 MB, 5 hour duration ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/audio/get_upload_url" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "audio_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "upload_url": "https://storage.googleapis.com/...", "upload_fields": { "key": "...", "policy": "...", "x-goog-signature": "..." }, "max_file_size_bytes": 524288000 } ``` Use `audio_id` in `update_params` after [finalizing the upload](/api/asset-management/post-uploads-audio-finalize-upload). # Get Asset View URL Source: https://docs.mosaic.so/api/asset-management/post-uploads-get-view-url POST /uploads/get_view_url Get a short-lived signed viewing URL for an uploaded asset. Returns a short-lived signed URL for viewing an uploaded asset (inline, not forced download). ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/get_view_url" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "asset_type": "video", "asset_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d" }' ``` ## Response ```json theme={null} { "asset_type": "video", "asset_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "signed_url": "https://storage.googleapis.com/...", "thumbnail_url": "https://storage.googleapis.com/..." } ``` ## Notes * `asset_type` must be one of: `video`, `audio`, `image` * Asset must belong to your organization workspace scope # Finalize Image Upload Source: https://docs.mosaic.so/api/asset-management/post-uploads-image-finalize-upload POST /uploads/image/finalize_upload Finalize a previously uploaded image asset. Call after uploading the file bytes to the signed URL from [Create Image Upload URL](/api/asset-management/post-uploads-image-get-upload-url). ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/image/finalize_upload" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{"image_id": "img-1234-5678-90ab-cdef"}' ``` ## Response ```json theme={null} { "image_id": "img-1234-5678-90ab-cdef" } ``` Use `image_id` in `update_params` when calling [Run Agent](/api/agent-runs/post-agent-run). # Create Image Upload URL Source: https://docs.mosaic.so/api/asset-management/post-uploads-image-get-upload-url POST /uploads/image/get_upload_url Create a signed upload URL for an image asset. **Limits:** 50 MB ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/image/get_upload_url" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "image_id": "img-1234-5678-90ab-cdef", "upload_url": "https://storage.googleapis.com/...", "upload_fields": { "key": "...", "policy": "...", "x-goog-signature": "..." }, "max_file_size_bytes": 52428800 } ``` Use `image_id` in `update_params` after [finalizing the upload](/api/asset-management/post-uploads-image-finalize-upload). # Finalize Video Upload Source: https://docs.mosaic.so/api/asset-management/post-uploads-video-finalize-upload POST /uploads/video/finalize_upload Finalize a previously uploaded video asset. Call after uploading the file bytes to the signed URL from [Create Video Upload URL](/api/asset-management/post-uploads-video-get-upload-url). **Limits:** 5 GB, plan-based duration: 2 hours on Standard, 5 hours on Professional/Enterprise. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/video/finalize_upload" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{"video_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d"}' ``` ## Response ```json theme={null} { "video_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d" } ``` Use `video_id` in `update_params` when calling [Run Agent](/api/agent-runs/post-agent-run). # Create Video Upload URL Source: https://docs.mosaic.so/api/asset-management/post-uploads-video-get-upload-url POST /uploads/video/get_upload_url Create a signed upload URL for a video asset. **Limits:** 5 GB, plan-based duration: 2 hours on Standard, 5 hours on Professional/Enterprise ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/uploads/video/get_upload_url" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "video_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "upload_url": "https://storage.googleapis.com/...", "upload_fields": { "key": "...", "policy": "...", "x-goog-signature": "..." }, "max_file_size_bytes": 5368709120 } ``` ## Upload File POST as form-data. **Fields first, then file:** ```python Python theme={null} import requests resp = requests.post( "https://api.mosaic.so/uploads/video/get_upload_url", headers={"Authorization": "Bearer mk_your_api_key"} ) data = resp.json() with open("video.mp4", "rb") as f: requests.post(data["upload_url"], data=data["upload_fields"], files={"file": f}) ``` ```javascript JavaScript theme={null} const { video_id, upload_url, upload_fields } = await fetch( "https://api.mosaic.so/uploads/video/get_upload_url", { method: "POST", headers: { "Authorization": "Bearer mk_your_api_key" } } ).then(r => r.json()); const formData = new FormData(); Object.entries(upload_fields).forEach(([k, v]) => formData.append(k, v)); formData.append("file", file); await fetch(upload_url, { method: "POST", body: formData }); ``` Use `video_id` in `update_params` after [finalizing the upload](/api/asset-management/post-uploads-video-finalize-upload). # Upload Flow Source: https://docs.mosaic.so/api/asset-management/upload-flow How asset uploads work for video, audio, and image inputs. Some agent nodes accept images, audio, or videos as parameters. Use these endpoints to upload files and get UUIDs that you can pass to `update_params` when running agents. ## Flow ```text theme={null} POST /uploads/{type}/get_upload_url → POST file to upload_url → POST /uploads/{type}/finalize_upload ``` 1. Call `get_upload_url` to get a signed URL and the asset UUID 2. POST your file to that URL (include `upload_fields` as form data) 3. Call `finalize_upload` to confirm the upload Use the returned UUID in `update_params`: ```json theme={null} { "update_params": { "NODE_ID": { "audio_id": "your-uploaded-uuid" } } } ``` ## Full Example Upload audio and use it in `update_params`: ```python Python theme={null} import requests API_KEY = "mk_your_api_key" BASE = "https://api.mosaic.so" # 1. Get upload URL data = requests.post(f"{BASE}/uploads/audio/get_upload_url", headers={"Authorization": f"Bearer {API_KEY}"}).json() # 2. Upload file with open("music.mp3", "rb") as f: requests.post(data["upload_url"], data=data["upload_fields"], files={"file": f}) # 3. Finalize result = requests.post(f"{BASE}/uploads/audio/finalize_upload", headers={"Authorization": f"Bearer {API_KEY}"}, json={"audio_id": data["audio_id"]}).json() # 4. Use in update_params run = requests.post(f"{BASE}/agent/YOUR_AGENT_ID/run", headers={"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}, json={ "video_urls": ["https://youtube.com/watch?v=dQw4w9WgXcQ"], "update_params": { "AUDIO_NODE_ID": {"audio_id": result["audio_id"]} } }).json() print(f"Run ID: {run['run_id']}") ``` ```javascript JavaScript theme={null} const API_KEY = "mk_your_api_key"; const BASE = "https://api.mosaic.so"; // 1. Get upload URL const data = await fetch(`${BASE}/uploads/audio/get_upload_url`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}` } }).then(r => r.json()); // 2. Upload file const formData = new FormData(); Object.entries(data.upload_fields).forEach(([k, v]) => formData.append(k, v)); formData.append("file", audioFile); await fetch(data.upload_url, { method: "POST", body: formData }); // 3. Finalize const result = await fetch(`${BASE}/uploads/audio/finalize_upload`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ audio_id: data.audio_id }) }).then(r => r.json()); // 4. Use in update_params const run = await fetch(`${BASE}/agent/YOUR_AGENT_ID/run`, { method: "POST", headers: { "Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json" }, body: JSON.stringify({ video_urls: ["https://youtube.com/watch?v=dQw4w9WgXcQ"], update_params: { "AUDIO_NODE_ID": { audio_id: result.audio_id } } }) }).then(r => r.json()); console.log(`Run ID: ${run.run_id}`); ``` ## Supported Formats | Type | Formats | Max Size | Max Duration | | ----- | ----------------------------------- | -------- | ------------------------------------------------------------------- | | Video | MP4, MOV, AVI, WebM, MKV, M4V | 5 GB | Plan-based: 2 hours on Standard, 5 hours on Professional/Enterprise | | Audio | MP3, WAV, M4A, FLAC, OGG, AAC, Opus | 500 MB | 5 hours | | Image | PNG, JPEG, GIF, WebP, SVG | 50 MB | - | ## Errors | Error | Cause | | ----- | --------------------------------- | | 404 | Upload ID not found or expired | | 400 | File not uploaded before finalize | | 413 | File exceeds size limit | # Create Avatar Source: https://docs.mosaic.so/api/avatar-profiles/create-avatar-profile POST /avatar-profiles/create Create a reusable AI Avatar from source media. Creates an avatar in your organization's primary workspace so it can be used by AI Avatar tiles across your workspaces. Processing starts automatically after creation. Provide either a source video URL, or an image URL plus an audio URL. You may include all three if you want separate visual and voice references. Source videos and audio voice references must be between 4 and 15 seconds. Avatar sources should represent one person only. For best results, use direct-to-camera footage with one visible speaker, clear mouth movement, and clean audio from that same person. Avoid background speakers, music, dubbing, heavy noise, overlays, cuts, or other people in frame. If you provide an image plus audio, the image should show the same single person and the audio should be clean single-speaker speech from that person. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/avatar-profiles/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Founder Avatar", "sources": { "video_url": "https://example.com/founder-reference.mp4" } }' ``` Image plus voice-reference audio: ```json theme={null} { "name": "Founder Avatar", "sources": { "image_url": "https://example.com/founder.jpg", "audio_url": "https://example.com/founder-voice.wav" } } ``` ## Parameters | Field | Type | Required | Description | | ------------------- | ----------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `name` | string | Yes | Avatar display name. | | `sources.video_url` | string URL | Conditional | Source video reference. Required unless both `sources.image_url` and `sources.audio_url` are supplied. Must be 4-15 seconds, show one person, and contain clear single-speaker audio from that person. | | `sources.image_url` | string URL | Conditional | Character image reference. Required when no `sources.video_url` is supplied. Should show one person only. | | `sources.audio_url` | string URL | Conditional | Voice reference audio. Required when no `sources.video_url` is supplied. Must be 4-15 seconds of clean single-speaker speech from the same person shown in the image. | | `sources.video_id` | string UUID | Conditional | Existing uploaded video asset ID. Alternative to `sources.video_url`; should follow the same one-person, clear-audio guidance. | | `sources.image_id` | string UUID | Conditional | Existing uploaded image asset ID. Alternative to `sources.image_url`; should show one person only. | | `sources.audio_id` | string UUID | Conditional | Existing uploaded audio asset ID. Alternative to `sources.audio_url`; should contain clean single-speaker speech. | URL sources are downloaded and stored as Mosaic asset IDs when the avatar is created, so expiring signed URLs are not reused later. ## Response Returns the created avatar profile. The response shape is: | Field | Type | Description | | ------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string UUID | Avatar profile ID. Pass this as `avatar_profile_id` in an AI Avatar tile. | | `video_preview_url` | string URL \| null | Signed video preview URL. This is `null` until a preview/reference video is available. | | `name` | string | Avatar display name. | | `status` | `"pending" \| "processing" \| "ready" \| "failed"` | Avatar processing state. `ready` means the avatar is fully prepared. `pending` or `processing` can still be used in an AI Avatar tile; the run waits. `failed` means the avatar cannot be used. | | `status_message` | string \| null | Error message when `status` is `failed`; otherwise `null`. | ```json theme={null} { "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "video_preview_url": null, "name": "Founder Avatar", "status": "processing", "status_message": null } ``` Use the returned `id` as `avatar_profile_id` in an AI Avatar tile immediately. If processing is still running when the agent starts, the run waits for the avatar to become ready. # Get Avatar Source: https://docs.mosaic.so/api/avatar-profiles/get-avatar-profile GET /avatar-profiles/{id} Get one reusable AI Avatar and its processing state. Returns one avatar from your organization's primary workspace. The response includes processing status, so this endpoint replaces a separate status check. You can pass an avatar ID to an AI Avatar tile as soon as it is created. If it is still processing, the run waits for processing to finish. If `processing_status` is `failed`, the avatar cannot be used until you create a new one. ## Request ```bash theme={null} curl "https://api.mosaic.so/avatar-profiles/bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Parameters | Field | Location | Type | Required | Description | | ----- | -------- | ----------- | -------- | ----------- | | `id` | path | string UUID | Yes | Avatar ID. | ## Response Returns the avatar profile. The response shape is: | Field | Type | Description | | ------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | string UUID | Avatar profile ID. Pass this as `avatar_profile_id` in an AI Avatar tile. | | `video_preview_url` | string URL \| null | Signed video preview URL. This is `null` until a preview/reference video is available. | | `name` | string | Avatar display name. | | `status` | `"pending" \| "processing" \| "ready" \| "failed"` | Avatar processing state. `ready` means the avatar is fully prepared. `pending` or `processing` can still be used in an AI Avatar tile; the run waits. `failed` means the avatar cannot be used. | | `status_message` | string \| null | Error message when `status` is `failed`; otherwise `null`. | ```json theme={null} { "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "video_preview_url": "https://...", "name": "Founder Avatar", "status": "processing", "status_message": null } ``` # Get Avatars Source: https://docs.mosaic.so/api/avatar-profiles/get-avatar-profiles GET /avatar-profiles List reusable AI Avatars available to your organization. Returns avatars from your organization's primary workspace. Avatars created through the API are stored there so AI Avatar tiles in any workspace can use them. Each avatar includes `status`. You can use avatars with `pending` or `processing` status immediately; the AI Avatar run waits for processing to finish. Avatars with `failed` status cannot be used. ## Request ```bash theme={null} curl "https://api.mosaic.so/avatar-profiles" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response Returns an object with `avatar_profiles`, an array of avatar profile objects: | Field | Type | Description | | ------------------------------------- | -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `avatar_profiles` | array | List of avatar profiles available to your organization. | | `avatar_profiles[].id` | string UUID | Avatar profile ID. Pass this as `avatar_profile_id` in an AI Avatar tile. | | `avatar_profiles[].video_preview_url` | string URL \| null | Signed video preview URL. This is `null` until a preview/reference video is available. | | `avatar_profiles[].name` | string | Avatar display name. | | `avatar_profiles[].status` | `"pending" \| "processing" \| "ready" \| "failed"` | Avatar processing state. `ready` means the avatar is fully prepared. `pending` or `processing` can still be used in an AI Avatar tile; the run waits. `failed` means the avatar cannot be used. | | `avatar_profiles[].status_message` | string \| null | Error message when `status` is `failed`; otherwise `null`. | ```json theme={null} { "avatar_profiles": [ { "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "video_preview_url": "https://...", "name": "Founder Avatar", "status": "ready", "status_message": null } ] } ``` Use `id` as `avatar_profile_id` in an AI Avatar node. # Changelog Source: https://docs.mosaic.so/api/changelog Notable changes to the Mosaic API. ## 2026-06-28 ### Added: output source citations Agent run outputs now include a `sources[]` array when a render uses licensed or external media. Getty b-roll citations include the usage window, query, provider asset ID when resolved, internal render asset ID, placement/layout, and rights metadata. Affected surfaces: | Surface | Field | | -------------------------------- | ----------------------------------- | | `GET /agent_run/{run_id}` | `outputs[].sources` | | `GET /agent/{agent_id}/runs` | `runs[].outputs[].sources` | | `GET /agent_runs` | `runs[].outputs[].sources` | | `GET /trigger/{trigger_id}/runs` | `runs[].outputs[].sources` | | `RUN_PROGRESS` webhook | `updated_nodes[].outputs[].sources` | | `RUN_FINISHED` webhook | `outputs[].sources` | ## 2026-05-21 ### Added: avatar profile API and generation tile docs The Avatar Profiles API now exposes the public avatar workflow: | Endpoint | Description | | ------------------------------ | -------------------------------------------------------------------------------------------------------- | | `POST /avatar-profiles/create` | Create an avatar from a source video, or an image plus voice reference. Processing starts automatically. | | `GET /avatar-profiles/{id}` | Get one avatar, including signed `video_preview_url`, `status`, and `status_message`. | | `GET /avatar-profiles` | List avatars available to your organization. | Avatar profile responses use a flat object shape: ```json theme={null} { "id": "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb", "video_preview_url": "https://...", "name": "Founder Avatar", "status": "processing", "status_message": null } ``` Avatars can be used in AI Avatar tiles immediately after creation. If processing is still running, the agent run waits for the avatar to become ready; failed avatars return an error through `status_message`. New generation tile documentation is also available for: * [Video Generation](/tiles/video-generation) * [Audio Generation](/tiles/audio-generation) * [Image Generation](/tiles/image-generation) The [Run Agent](/api/agent-runs/post-agent-run#generation-only-workflows) docs now include node IDs and setup guidance for AI Avatar, Video Generation, Audio Generation, and Image Generation workflows. ## 2026-04-04 ### Added: `errors` field on agent runs and webhooks Agent run responses and webhook payloads now include an `errors` field that surfaces error messages from failed tasks, grouped by the template node that produced them. **Run-level** (`GET /agent_run/{run_id}` and `RUN_FINISHED` webhook): ```json theme={null} "errors": [ { "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8", "messages": ["FFmpeg render failed: output format not supported"] }, { "original_node_id": "3ca7b810-9dad-11d1-80b4-00c04fd430c8", "messages": [ "Audio transcription timed out after 300s", "Retry failed: service unavailable" ] } ] ``` Each entry links errors to the `original_node_id` (template node) so you can map failures back to specific nodes in your agent. **Node-level** (`GET /agent_run/{run_id}/nodes` and `RUN_PROGRESS` webhook `updated_nodes[]`): ```json theme={null} "errors": ["Audio transcription timed out after 300s"] ``` Per-node `errors` is a flat string array since the node context is already provided by the parent object. **Affected endpoints:** | Surface | Field | Type | | ------------------------------- | ------------------------ | --------------------------------------------- | | `GET /agent_run/{run_id}` | `errors` | `array` of `{ original_node_id, messages[] }` | | `GET /agent_run/{run_id}/nodes` | `nodes[].errors` | `string[]` | | `RUN_FINISHED` webhook | `errors` | `array` of `{ original_node_id, messages[] }` | | `RUN_PROGRESS` webhook | `updated_nodes[].errors` | `string[]` | Previously, error details from processing tasks were only available internally. The `status_message` field on runs and nodes continues to work as before and is unaffected by this change. # Get Credits Source: https://docs.mosaic.so/api/credits/get-credits GET /credits Get your organization's credit balance, plan, billing cycle, and auto top-up settings. Returns everything about your organization's credit state in a single call: current balance, active plan, billing cycle dates, and auto top-up configuration. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/credits" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "organization_id": "d808af70-fc57-4f90-95ca-186a9cbf2ef7", "balance": 1840, "plan": "creator", "plan_id": "creator_annual", "billing_cycle": { "current_period_start": "2026-03-01T00:00:00.000Z", "current_period_end": "2026-04-01T00:00:00.000Z" }, "auto_topup": { "eligible": true, "enabled": true, "threshold": 1000, "quantity": 5000 } } ``` ## Response Fields | Field | Type | Description | | ------------------------------------ | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `organization_id` | string | Organization identifier. | | `balance` | number | Current remaining credits. | | `plan` | string \| null | Normalized plan family (`creator` or `professional`). | | `plan_id` | string \| null | Concrete active plan ID (`creator`, `creator_annual`, `professional`, etc.). | | `billing_cycle.current_period_start` | string \| null | Current subscription cycle start in ISO format. | | `billing_cycle.current_period_end` | string \| null | Current subscription cycle end in ISO format. | | `auto_topup.eligible` | boolean | Whether the current plan can use auto top-ups. Eligible plans are `creator`, `creator_annual`, `professional`, and `professional_annual`. | | `auto_topup.enabled` | boolean | Whether auto top-up is active. | | `auto_topup.threshold` | number | When the credit balance drops below this number, an auto top-up is triggered. | | `auto_topup.quantity` | number | Number of credits purchased each time an auto top-up fires. | When `auto_topup.eligible` is `false`, auto top-ups are unavailable for the current plan and the returned auto top-up config will be disabled (`enabled: false`, `threshold: 0`, `quantity: 0`). # Get Credit Usage Source: https://docs.mosaic.so/api/credits/get-credits-usage GET /credits/usage Get credit usage breakdown by tile and date. Returns aggregated credit usage over a date range. The response includes: * totals across the range * grouped usage by tile * grouped usage by date * grouped usage by both date and tile Tile names (for example `YouTube Download`, `Rough Cut`, `Clips`) are resolved from node metadata associated with each credit log. ## Query Parameters | Parameter | Type | Required | Description | | ------------ | ------ | -------- | --------------------------------------------------------------------- | | `start_date` | string | No | ISO date/datetime start bound. Defaults to 30 days before `end_date`. | | `end_date` | string | No | ISO date/datetime end bound. Defaults to now. | | `limit` | number | No | Max raw usage events scanned (1 - 10,000). Default: `5,000`. | ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/credits/usage?start_date=2026-03-01T00:00:00.000Z&end_date=2026-03-31T23:59:59.999Z&limit=5000" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "organization_id": "d808af70-fc57-4f90-95ca-186a9cbf2ef7", "date_range": { "start_date": "2026-03-01T00:00:00.000Z", "end_date": "2026-03-31T23:59:59.999Z" }, "summary": { "total_credits_used": 14220, "total_events": 298, "matching_events": 298, "returned_events": 298, "truncated": false }, "breakdown": { "by_tile": [ { "tile_id": "a4c6ee9a-4ff2-43f8-9a9a-d4ad6dd20f3a", "tile_name": "Rough Cut", "credits_used": 7210, "events": 142 }, { "tile_id": "3cfd7bcb-f4cb-4bd3-8f81-a3de9af16f14", "tile_name": "Clips", "credits_used": 5030, "events": 101 } ], "by_date": [ { "date": "2026-03-01", "credits_used": 420, "events": 11 }, { "date": "2026-03-02", "credits_used": 388, "events": 9 } ], "by_date_and_tile": [ { "date": "2026-03-01", "tile_id": "a4c6ee9a-4ff2-43f8-9a9a-d4ad6dd20f3a", "tile_name": "Rough Cut", "credits_used": 420, "events": 11 } ] } } ``` ## Response Fields | Field | Type | Description | | ------------------------------------------- | -------------- | --------------------------------------------------- | | `organization_id` | string | Organization identifier. | | `date_range.start_date` | string | Start of the queried range (ISO). | | `date_range.end_date` | string | End of the queried range (ISO). | | `summary.total_credits_used` | number | Total credits consumed in the returned range. | | `summary.total_events` | number | Number of charge events included in aggregation. | | `summary.matching_events` | number | Total matching events before `limit` truncation. | | `summary.returned_events` | number | Number of events processed in this response window. | | `summary.truncated` | boolean | `true` when `matching_events > returned_events`. | | `breakdown.by_tile[].tile_id` | string | Tile/node type identifier. | | `breakdown.by_tile[].tile_name` | string \| null | Human-readable tile name. | | `breakdown.by_tile[].credits_used` | number | Credits used by this tile. | | `breakdown.by_tile[].events` | number | Number of usage events for this tile. | | `breakdown.by_date[].date` | string | UTC date (`YYYY-MM-DD`). | | `breakdown.by_date[].credits_used` | number | Credits used on this date. | | `breakdown.by_date[].events` | number | Number of usage events on this date. | | `breakdown.by_date_and_tile[].date` | string | UTC date (`YYYY-MM-DD`). | | `breakdown.by_date_and_tile[].tile_id` | string | Tile/node type identifier. | | `breakdown.by_date_and_tile[].tile_name` | string \| null | Human-readable tile name. | | `breakdown.by_date_and_tile[].credits_used` | number | Credits used by this tile on this date. | | `breakdown.by_date_and_tile[].events` | number | Number of usage events for this tile on this date. | # Update Credit Settings Source: https://docs.mosaic.so/api/credits/post-credits-settings POST /credits/settings Configure auto top-ups for your organization's credits. Enable, disable, or update auto top-up settings for your organization. When enabled, credits are automatically purchased at your plan's top-up rate whenever your balance drops below the threshold. Requires one of these active plans: `creator`, `creator_annual`, `professional`, or `professional_annual`. Returns `403` if no eligible plan is active. To read current credit and auto top-up state, use `GET /credits`. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/credits/settings" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "auto_topup": { "enabled": true, "threshold": 1000, "quantity": 5000 } }' ``` ## Body Parameters | Field | Type | Required | Description | | ---------------------- | ------- | -------- | -------------------------------------------------------------------------- | | `auto_topup.enabled` | boolean | Yes | Enable or disable auto top-ups. | | `auto_topup.threshold` | number | Yes | Credit balance threshold that triggers an auto top-up (`0` – `1,000,000`). | | `auto_topup.quantity` | number | Yes | Number of credits to purchase per auto top-up (`0` – `1,000,000`). | ## Response Returns the updated settings. ```json theme={null} { "auto_topup": { "enabled": true, "threshold": 1000, "quantity": 5000 } } ``` ## Errors | Status | Reason | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------- | | `403` | No active paid plan, or plan is not eligible for auto top-ups (must be `creator`, `creator_annual`, `professional`, or `professional_annual`). | ## Examples ### Enable auto top-up ```bash theme={null} curl -X POST "https://api.mosaic.so/credits/settings" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "auto_topup": { "enabled": true, "threshold": 500, "quantity": 2000 } }' ``` ### Disable auto top-up ```bash theme={null} curl -X POST "https://api.mosaic.so/credits/settings" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "auto_topup": { "enabled": false, "threshold": 0, "quantity": 0 } }' ``` # API Overview Source: https://docs.mosaic.so/api/introduction Everything you need to get started with the Mosaic API. ## What is the Mosaic API? The Mosaic API lets you run video editing workflows entirely from code. A workflow is called an **Agent** — a graph of processing steps (called **Tiles**) that can do anything from adding captions to generating clips to full multi-step pipelines. You supply a video, Mosaic does the work and returns the result. ## Getting Started ### 1. Get your API key Create an API key in your [Mosaic dashboard](https://edit.mosaic.so). All keys are prefixed with `mk_` and authenticate via the `Authorization: Bearer` header. ```bash theme={null} curl -H "Authorization: Bearer mk_your_key" \ -H "Content-Type: application/json" \ https://api.mosaic.so/whoami ``` ### 2. Verify with Who Am I Call `/whoami` to confirm your key is valid and see which organization it belongs to: ```json theme={null} { "organization_id": "123e4567-e89b-12d3-a456-789012345678", "organization_name": "Acme Productions", "organization_slug": "acme-productions", "created_at": "2024-01-15T08:00:00Z", "last_used_at": "2024-01-15T14:30:00Z" } ``` Always test your API key with `/whoami` first when setting up a new integration. This catches authentication issues before you start building. ### 3. Run your first agent The typical flow is three steps: 1. **Run an agent** — `POST /agent/{agent_id}/run` with your video URLs and optional parameters. 2. **Track progress** — Poll `GET /agent_run/{run_id}` or subscribe to a [webhook](/api/webhooks/events) via `callback_url`. 3. **Download outputs** — Outputs (signed video URLs, thumbnails, Premiere timelines) are included in the run response. *** ## Core Concepts | Concept | What it is | Key endpoints | | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | [**Agents**](/api/agents/creating-agents) | Reusable video editing workflows you create and configure. Each agent is a graph of tiles. | [Create](/api/agents/post-agent-create), [Update](/api/agents/post-agent-update), [List](/api/agents/get-agents) | | [**Agent Runs**](/api/agent-runs/post-agent-run) | An execution of an agent against one or more input videos. | [Run](/api/agent-runs/post-agent-run), [Get Status](/api/agent-runs/get-agent-run), [Get Nodes](/api/agent-runs/get-agent-run-nodes) | | [**Avatar Profiles**](/api/avatar-profiles/create-avatar-profile) | Reusable AI Avatar identities created from a one-person source video, or an image plus clean single-speaker voice reference from the same person. | [Create](/api/avatar-profiles/create-avatar-profile), [Get](/api/avatar-profiles/get-avatar-profile), [List](/api/avatar-profiles/get-avatar-profiles) | | [**Node Types**](/api/agent-nodes/get-agent-nodes) | The catalog of available tiles (Captions, Reframe, Clips, etc.) and their parameters. | [List Types](/api/agent-nodes/get-agent-nodes), [Get Type](/api/node-types/get-node-type) | | [**Triggers**](/api/triggers/get-agent-triggers) | Automatic run triggers — YouTube channel monitors, schedules, or storage watchers. | [List](/api/triggers/get-agent-triggers), [Add YouTube](/api/triggers/post-add-youtube-channels) | | [**Webhooks**](/api/webhooks/events) | Real-time POST notifications for run lifecycle events (`RUN_STARTED`, `RUN_PROGRESS`, `RUN_FINISHED`). | [Events](/api/webhooks/events) | | [**Asset Management**](/api/asset-management/upload-flow) | Upload your own video, audio, and image files for use in agent runs. | [Upload Flow](/api/asset-management/upload-flow) | | [**Credits**](/api/credits/get-credits) | Check balance, view usage history, and configure auto top-up. | [Balance](/api/credits/get-credits), [Usage](/api/credits/get-credits-usage) | | [**Plans**](/api/plan/get-plan) | View your current plan and upgrade. | [Get Plan](/api/plan/get-plan), [Upgrade](/api/plan/post-plan-upgrade) | | [**Social**](/api/social/post-social-post) | Publish outputs directly to connected social accounts and read post analytics. | [Connections](/api/social/get-social-connections), [Post](/api/social/post-social-post), [Get Post](/api/social/get-social-post), [Analytics](/api/social/get-social-post-analytics) | *** ## Authentication Use your API key with the `Authorization: Bearer` header on every request. ```bash theme={null} curl -H "Authorization: Bearer mk_your_key" \ -H "Content-Type: application/json" \ https://api.mosaic.so/agent/[agent_id]/run ``` API keys can be created and managed in your [Mosaic dashboard](https://edit.mosaic.so). ### Webhook Authentication When a webhook secret is configured for your account, Mosaic includes an `X-Mosaic-Signature` header for verification. Always validate this signature before processing webhook payloads. See the [Webhook Events](/api/webhooks/events) documentation for details. ## Error Handling Responses use conventional HTTP status codes. On errors the body contains a `detail` field with a human-readable message. ```json theme={null} { "detail": "Invalid request body: video_urls: Required" } ``` | Status | Meaning | Typical Cause | | ------ | --------------------- | -------------------------------------------------------------------- | | 400 | Bad Request | Malformed JSON, missing required field, or invalid value | | 401 | Unauthorized | API key is missing, revoked, or invalid | | 403 | Forbidden | API key does not have access to the requested resource | | 404 | Not Found | Agent, run, or `agent_node_id` does not exist | | 413 | Payload Too Large | Uploaded file exceeds the size limit or video exceeds duration limit | | 500 | Internal Server Error | Unexpected server-side exception | ## Base URL ```text theme={null} https://api.mosaic.so ``` # Get Node Type Source: https://docs.mosaic.so/api/node-types/get-node-type GET /node_type/{node_type_id} Get a single node type. Returns one node type from the public node type catalog. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/node_type/[node_type_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "node_type": { "node_type_id": "3b281fb9-9eb2-40f6-b05b-4b6f909a3da9", "node_type_name": "AI Music", "docs_url": "https://docs.mosaic.so/tiles/ai-music", "params_docs_url": "https://docs.mosaic.so/tiles/ai-music#api-info" } } ``` ## Response Fields | Field | Type | Description | | --------------------------- | -------------- | -------------------------------------------------------- | | `node_type.node_type_id` | string | Node type ID (UUID). | | `node_type.node_type_name` | string \| null | Node type display name. | | `node_type.docs_url` | string \| null | Canonical docs page URL (from `nodes.docs_path`). | | `node_type.params_docs_url` | string \| null | Exact params/API section URL (from `nodes.docs_anchor`). | # Get Plan Source: https://docs.mosaic.so/api/plan/get-plan GET /plan Get current and scheduled plan details for your organization. Returns the current paid plan, any scheduled plan change, and current credit usage context. `plan.id` and `scheduled_plan.id` return the concrete plan ID (for example: `creator`, `creator_annual`, `professional`, `professional_annual`, or `pro`). ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/plan" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "organization_id": "d808af70-fc57-4f90-95ca-186a9cbf2ef7", "plan": { "id": "creator_annual", "family": "creator", "status": "active", "started_at": "2026-02-01T00:00:00.000Z", "current_period_start": "2026-03-01T00:00:00.000Z", "current_period_end": "2026-04-01T00:00:00.000Z", "canceled_at": null }, "scheduled_plan": null, "credits": { "balance": 1840, "usage": 660, "included_usage": 2500, "unlimited": false } } ``` # List Plans Source: https://docs.mosaic.so/api/plan/get-plan-list GET /plan/list List available plans, included credits, and top-up rates. Returns Mosaic plan metadata used for pricing and upgrade UX. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/plan/list" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "plans": [ { "id": "creator", "billing": "monthly", "price_usd": 50, "credits_per_month": 2500, "top_up_rate_per_100_credits_usd": 2, "notes": "Best for individuals getting started" }, { "id": "creator_annual", "billing": "annual", "price_usd": 480, "credits_per_month": 2500, "top_up_rate_per_100_credits_usd": 2, "notes": "Best for individuals getting started (annual)" }, { "id": "professional", "billing": "monthly", "price_usd": 150, "credits_per_month": 10000, "top_up_rate_per_100_credits_usd": 1.6, "notes": "Best for growing teams and automations" }, { "id": "professional_annual", "billing": "annual", "price_usd": 1500, "credits_per_month": 10000, "top_up_rate_per_100_credits_usd": 1.6, "notes": "Best for growing teams and automations (annual)" } ] } ``` # Upgrade Plan Source: https://docs.mosaic.so/api/plan/post-plan-upgrade POST /plan/upgrade Upgrade or change your current organization plan. Changes the current organization plan. Depending on billing state, Mosaic may return a checkout URL to complete the change. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/plan/upgrade" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "plan_id": "professional_annual" }' ``` ## Body Parameters | Field | Type | Required | Description | | ------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------- | | `plan_id` | string | Yes | Target purchasable plan ID (`creator`, `creator_annual`, `professional`, `professional_annual`, or `pro`). | | `success_url` | string | No | Override checkout success redirect URL. | | `cancel_url` | string | No | Override checkout cancel redirect URL. | ## Response (Immediate Change) ```json theme={null} { "success": true, "requires_checkout": false, "plan_id": "professional_annual", "plan_family": "professional" } ``` ## Response (Checkout Required) ```json theme={null} { "success": false, "requires_checkout": true, "checkout_url": "https://billing.autumn.com/checkout/...", "plan_id": "professional_annual" } ``` # Delete Social Connection Source: https://docs.mosaic.so/api/social/delete-social-connection DELETE /social/connections/{social_connection_id} Disconnect one social account. Disconnects one social account. Use the `social_connection_id` returned by `GET /social/connections`. ## Request ```bash theme={null} curl -X DELETE "https://api.mosaic.so/social/connections/7f9388af-26e8-4e68-a52b-6b9a0ef3a017" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Path Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | ------------------------- | | `social_connection_id` | string (uuid) | Yes | The connected account ID. | ## Response ```json theme={null} { "success": true, "platform": "linkedin", "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017" } ``` # Delete Social Post Source: https://docs.mosaic.so/api/social/delete-social-post DELETE /social/post/{post_id} Delete a social post. Deletes a social post. Use the `post_id` returned by `POST /social/post`. ## Request ```bash theme={null} curl -X DELETE "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Body Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------- | | `social_connection_id` | string (uuid) | No | Delete using one specific connected account. Useful when a post targets multiple accounts on the same platform. | ## Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "rejected" } ``` # Get Social Connection Source: https://docs.mosaic.so/api/social/get-social-connection GET /social/connections/{social_connection_id} Get status and account metadata for one social connection. Returns status and account metadata for one connected social account. Use the `social_connection_id` returned by `GET /social/connections`. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/connections/7f9388af-26e8-4e68-a52b-6b9a0ef3a017" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Path Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | ------------------------- | | `social_connection_id` | string (uuid) | Yes | The connected account ID. | ## Response ```json theme={null} { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "connected": true, "account_name": "Mosaic", "account_username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so", "username": "mosaic-so", "display_name": "Mosaic", "user_image": "https://media.licdn.com/..." } ``` # List Social Connections Source: https://docs.mosaic.so/api/social/get-social-connections GET /social/connections List connected social accounts that can be used as post destinations. Returns connected social accounts for the API key's organization. Use `social_connection_id` values in `POST /social/post` when you need to target specific accounts, including multiple accounts on the same platform. Use `POST /social/connections` to create a new social connection setup flow. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/connections" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "connected_accounts": [ { "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01", "platform": "x", "account_name": "Mosaic", "account_username": "mosaic_so", "profile_url": "https://x.com/mosaic_so" }, { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "account_name": "Mosaic", "account_username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so" }, { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "account_name": "Motion", "account_username": "motion_so", "profile_url": "https://x.com/motion_so" }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "account_name": "Motion", "account_username": "motion-so", "profile_url": "https://www.linkedin.com/company/motion-so/" } ] } ``` ## Response Details * `social_connection_id` identifies one connected account on one platform. * Organizations can have multiple connections for the same `platform`; use explicit `destinations` when posting to avoid ambiguity. # Get Social Post Source: https://docs.mosaic.so/api/social/get-social-post GET /social/post/{post_id} Get social post status, destination results, links, and available analytics. Returns the current state for a social post. Use the `post_id` returned by `POST /social/post`. For scheduled posts, this endpoint returns `scheduled` while the post is waiting or still processing. After publishing succeeds, the same `post_id` returns `posted` with native destination IDs and URLs when available. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | ----------------------------------------------------------------------------------------------------------------------- | | `social_connection_id` | string (uuid) | No | Return details using one specific connected account. Useful when a post targets multiple accounts on the same platform. | ## Scheduled Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "scheduled", "description": "Launch day recap from the Mosaic team.", "thumbnail_url": "https://cdn.yourdomain.com/media/launch-thumbnail.jpg", "scheduled_at": "2026-03-10T16:00:00Z", "platforms": ["linkedin"], "destinations": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "account_name": "Mosaic", "account_username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so" } ], "links": [], "results": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null } ], "destination_results": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null } ], "analytics": null, "stats": null, "error": null, "created_at": "2026-03-10T15:00:00.000Z", "updated_at": "2026-03-10T15:00:01.000Z" } ``` ## Posted Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "posted", "description": "Launch day recap from the Mosaic team.", "thumbnail_url": "https://cdn.yourdomain.com/media/launch-thumbnail.jpg", "scheduled_at": "2026-03-10T16:00:00Z", "platforms": ["linkedin"], "destinations": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "account_name": "Mosaic", "account_username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so" } ], "links": [ { "platform": "linkedin", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017" } ], "results": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "success", "platform_post_id": "7351291821454032896", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "message": null } ], "destination_results": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "success", "platform_post_id": "7351291821454032896", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "message": null } ], "analytics": { "status": "success", "totals": { "likes": 12, "comments": 3, "shares": null, "impressions": 820, "views": null, "video_views": null, "video_viewers": null, "video_watch_time_ms": null, "engagement": null, "clicks": null, "saves": null, "bookmarks": null, "quotes": null }, "platforms": [ { "platform": "linkedin", "platform_post_id": "7351291821454032896", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "metrics": { "likes": 12, "comments": 3, "shares": null, "impressions": 820, "views": null, "video_views": null, "video_viewers": null, "video_watch_time_ms": null, "engagement": null, "clicks": null, "saves": null, "bookmarks": null, "quotes": null }, "raw_metrics": { "likeCount": 12, "commentCount": 3, "impressionCount": 820 } } ], "metadata": {} }, "stats": { "status": "success" }, "error": null, "created_at": "2026-03-10T16:00:00.000Z", "updated_at": "2026-03-10T16:00:09.000Z" } ``` ## Response Details * `status` is the aggregate post status across destinations. * `description` and `thumbnail_url` are `null` when unavailable. * `analytics` can be `null` when analytics is unavailable. `stats` is retained for backward compatibility. * `destination_results` is the canonical per-destination result list. Use it when a post targets multiple connected accounts on the same platform. * `platform_post_id` is the native post ID from the destination platform. It can be `null` before a scheduled post publishes. * For analytics-only reads, use `GET /social/post/{post_id}/analytics`. # Get Social Post Analytics Source: https://docs.mosaic.so/api/social/get-social-post-analytics GET /social/post/{post_id}/analytics Get normalized analytics for a social post. Returns analytics for a social post with a fixed normalized shape. Use the `post_id` returned by `POST /social/post`. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/post/2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e/analytics" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | ---------------------------------------------------------------------------------------------------------------------- | | `social_connection_id` | string (uuid) | No | Get analytics using one specific connected account. Useful when a post targets multiple accounts on the same platform. | ## Response Fields | Field | Type | Description | | ---------------------------------------- | -------------- | -------------------------------------------------------------------------------------------------------------- | | `analytics.status` | string or null | Analytics status. `null` if the source response does not include it. | | `analytics.totals` | object | Fixed normalized totals object. Every metric key is always present; the value is a number or `null`. | | `analytics.platforms` | array | Per-platform analytics entries. | | `analytics.platforms[].platform` | string | One of `x`, `linkedin`, `instagram`, `facebook`, `tiktok`, `youtube`. | | `analytics.platforms[].platform_post_id` | string or null | Native post ID from the destination platform. `null` if the source response does not include it. | | `analytics.platforms[].post_url` | string or null | Public post URL. `null` if the source response does not include it. | | `analytics.platforms[].metrics` | object | Fixed normalized metric object. Every metric key is always present; the value is a number or `null`. | | `analytics.platforms[].raw_metrics` | object | Unnormalized platform-specific analytics payload for clients that need fields outside the normalized contract. | | `analytics.metadata` | object | Response-level metadata with platform entries removed. | | `stats` | object | Backward-compatible analytics payload. Prefer `analytics` for new integrations. | ## Metric Object Every `analytics.totals` and `analytics.platforms[].metrics` object has exactly these keys: | Field | Type | | --------------------- | -------------- | | `likes` | number or null | | `comments` | number or null | | `shares` | number or null | | `impressions` | number or null | | `views` | number or null | | `video_views` | number or null | | `video_viewers` | number or null | | `video_watch_time_ms` | number or null | | `engagement` | number or null | | `clicks` | number or null | | `saves` | number or null | | `bookmarks` | number or null | | `quotes` | number or null | ## Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "platform": "x", "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01", "analytics": { "status": "success", "totals": { "likes": 42, "comments": 7, "shares": 5, "impressions": 18420, "views": 9120, "video_views": null, "video_viewers": null, "video_watch_time_ms": null, "engagement": null, "clicks": null, "saves": null, "bookmarks": 18, "quotes": 3 }, "platforms": [ { "platform": "x", "platform_post_id": "1901625213503277588", "post_url": "https://x.com/mosaic_so/status/1901625213503277588", "metrics": { "likes": 42, "comments": 7, "shares": 5, "impressions": 18420, "views": 9120, "video_views": null, "video_viewers": null, "video_watch_time_ms": null, "engagement": null, "clicks": null, "saves": null, "bookmarks": 18, "quotes": 3 }, "raw_metrics": { "likeCount": 42, "replyCount": 7, "repostCount": 5, "impressionCount": 18420, "viewCount": 9120, "bookmarkCount": 18, "quoteCount": 3 } } ], "metadata": {} }, "stats": { "status": "success", "x": { "id": "1901625213503277588", "analytics": { "likeCount": 42, "replyCount": 7, "repostCount": 5, "impressionCount": 18420, "viewCount": 9120, "bookmarkCount": 18, "quoteCount": 3 } } } } ``` ## Behavior * Metrics vary by platform and account permissions. Missing normalized metrics are returned as `null`, not omitted and not converted to fake zeroes. * For posts with multiple destinations, pass `social_connection_id` when you need analytics for one connected account. * `analytics.totals` only sums metrics returned in this response. # Get Social Post Comments Source: https://docs.mosaic.so/api/social/get-social-post-comments GET /social/post/{post_id}/comments Get comments for a social post. Returns comments for a published social post with a fixed normalized shape. Responses are bounded so they are safe to consume from agents and automation jobs. Use the `post_id` returned by `POST /social/post`. Comments and nested replies are sorted by `created_at` descending. Comments without `created_at` are returned after comments with timestamps. Ties are ordered by `platform`, then `comment_id`, then `platform_comment_id`. Top-level comments are sorted before pagination. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/post/2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e/comments" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------- | | `social_connection_id` | string (uuid) | No | Get comments using one specific connected account. Useful when a post targets multiple accounts on the same platform. | | `limit` | integer | No | Maximum comments to return. Defaults to `100`; maximum is `1000`. | | `cursor` | string | No | Cursor returned by the previous response. | ## Platform Support Comments are supported for `x`, `linkedin`, `instagram`, `facebook`, `tiktok`, and `youtube`. ## Comment Object Every item in `comments` and every item in `comments[].replies` has exactly these normalized fields: | Field | Type | Description | | ---------------------- | -------------- | ------------------------------------------------------------------------------------------------------------- | | `comment_id` | string or null | Mosaic-normalized comment ID. | | `platform_comment_id` | string or null | Native comment ID from the destination platform. | | `platform` | string or null | One of `x`, `linkedin`, `instagram`, `facebook`, `tiktok`, `youtube`. | | `social_connection_id` | string or null | Connected account used for the lookup. | | `text` | string or null | Comment text. | | `created_at` | string or null | Creation timestamp. `null` if the source response does not include it. | | `comment_url` | string or null | Direct comment URL. `null` if the source response does not include it. | | `like_count` | number or null | Like count. `null` if the source response does not include it. | | `reply_count` | number or null | Reply count. `null` if the source response does not include it. | | `parent_comment_id` | string or null | Parent comment ID for replies. `null` for top-level comments or when the source response does not include it. | | `author` | object or null | Fixed author object. `null` if the source response does not include author metadata. | | `media` | array | Media attachments on the comment. Always an array. | | `replies` | array | Nested comments. Always an array. | | `raw` | object or null | Unnormalized platform-specific comment payload. | When `author` is not `null`, it has exactly these fields: `id`, `name`, `username`, `profile_url`, and `profile_image_url`. Each value is a string or `null`. Every item in `media` has exactly these fields: `type`, `url`, `thumbnail_url`, `mime_type`, `alt_text`, and `raw`. `type` is one of `image`, `video`, `gif`, `audio`, `document`, or `unknown`. ## Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "platform": "linkedin", "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "comments": [ { "comment_id": "comment_123", "platform_comment_id": "urn:li:comment:123", "platform": "linkedin", "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "text": "Looks great.", "created_at": "2026-03-10T17:12:00Z", "comment_url": "https://www.linkedin.com/feed/update/urn:li:activity:7351291821454032896?commentUrn=...", "like_count": 12, "reply_count": 2, "parent_comment_id": null, "author": { "id": null, "name": "Mosaic", "username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so", "profile_image_url": null }, "media": [ { "type": "image", "url": "https://media.example.com/comment-image.jpg", "thumbnail_url": null, "mime_type": null, "alt_text": null, "raw": { "type": "image", "url": "https://media.example.com/comment-image.jpg" } } ], "replies": [ { "comment_id": "comment_reply_456", "platform_comment_id": "urn:li:comment:456", "platform": "linkedin", "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "text": "Thanks!", "created_at": "2026-03-10T17:20:00Z", "comment_url": null, "like_count": null, "reply_count": null, "parent_comment_id": "comment_123", "author": null, "media": [], "replies": [], "raw": { "comment": "Thanks!", "created": "2026-03-10T17:20:00Z" } } ], "raw": { "comment": "Looks great.", "commentUrn": "urn:li:comment:123", "created": "2026-03-10T17:12:00Z", "likeCount": 12 } } ], "pagination": { "limit": 100, "returned": 1, "total_available": 1, "has_more": false, "next_cursor": null, "sort": "created_at_desc" }, "metadata": { "status": "success" } } ``` ## Pagination * Comments are available after the post is published. * Normalized comment fields are fixed. Platform-specific fields are only returned inside `raw`. * Image, video, and other comment attachments are normalized into `media`; the original attachment payload remains in `media[].raw`. * Pagination cursors are based on the sorted response window. * This endpoint paginates the comments available in the current response window. It is not a guaranteed complete historical archive for posts with very high comment volume. * Some platforms return only a recent comments window, and comment data can update asynchronously. * This endpoint reads comments. It does not create, reply to, hide, or delete comments. # List Social Posts Source: https://docs.mosaic.so/api/social/get-social-posts GET /social/posts List social posts with cursor pagination. Returns social posts for the API key's organization, sorted by `created_at` descending. Use this endpoint for dashboards, sync jobs, and agents that need to page through posts. Use `GET /social/post/{post_id}` when you need the freshest status for one specific post. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/posts?limit=20" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Query Parameters | Field | Type | Required | Description | | ---------------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `limit` | integer | No | Maximum posts to return. Defaults to `20`; maximum is `100`. | | `cursor` | string | No | Cursor returned by the previous response. | | `status` | string | No | Filter by post status. Supported values are `scheduled`, `pending_approval`, `processing`, `posted`, `partial_failure`, `failed`, and `rejected`. | | `platform` | string | No | Filter by platform: `x`, `linkedin`, `instagram`, `facebook`, `tiktok`, or `youtube`. | | `social_connection_id` | string (uuid) | No | Filter to posts that target one connected account. | ## Filtered Request ```bash theme={null} curl -X GET "https://api.mosaic.so/social/posts?platform=x&social_connection_id=4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01&limit=10" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} { "posts": [ { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "posted", "description": "Launch day recap from the Mosaic team.", "thumbnail_url": "https://cdn.yourdomain.com/media/launch-thumbnail.jpg", "scheduled_at": "2026-03-10T16:00:00Z", "platforms": ["x", "linkedin"], "destinations": [ { "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01", "platform": "x", "account_name": "Mosaic", "account_username": "mosaic_so", "profile_url": "https://x.com/mosaic_so" }, { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "account_name": "Mosaic", "account_username": "mosaic-so", "profile_url": "https://www.linkedin.com/company/mosaic-so" } ], "links": [ { "platform": "x", "post_url": "https://x.com/mosaic_so/status/1901625213503277588", "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01" } ], "results": [ { "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01", "platform": "x", "status": "success", "platform_post_id": "1901625213503277588", "post_url": "https://x.com/mosaic_so/status/1901625213503277588", "message": null }, { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "success", "platform_post_id": "7351291821454032896", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "message": null } ], "destination_results": [ { "social_connection_id": "4df2f2b9-4c5f-4b3a-9581-1bcb8b4f7d01", "platform": "x", "status": "success", "platform_post_id": "1901625213503277588", "post_url": "https://x.com/mosaic_so/status/1901625213503277588", "message": null }, { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "success", "platform_post_id": "7351291821454032896", "post_url": "https://www.linkedin.com/company/mosaic-so/posts/...", "message": null } ], "error": null, "created_at": "2026-03-10T16:00:00.000Z", "updated_at": "2026-03-10T16:00:09.000Z" }, { "post_id": "4ce8de72-7d67-48dc-bd11-0362d5cebb51", "status": "scheduled", "description": "Motion product update", "thumbnail_url": "https://cdn.yourdomain.com/media/motion-launch.jpg", "scheduled_at": "2026-03-11T18:00:00Z", "platforms": ["x", "linkedin"], "destinations": [ { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "account_name": "Motion", "account_username": "motion_so", "profile_url": "https://x.com/motion_so" }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "account_name": "Motion", "account_username": "motion-so", "profile_url": "https://www.linkedin.com/company/motion-so/" } ], "links": [], "results": [ { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null } ], "destination_results": [ { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null } ], "error": null, "created_at": "2026-03-10T15:30:00.000Z", "updated_at": "2026-03-10T15:30:01.000Z" } ], "pagination": { "limit": 20, "returned": 2, "has_more": true, "next_cursor": "eyJ2ZXJzaW9uIjoidjEiLCJjcmVhdGVkX2F0IjoiMjAyNi0wMy0xMFQxNTozMDowMC4wMDBaIiwiaWQiOiI0Y2U4ZGU3Mi03ZDY3LTQ4ZGMtYmQxMS0wMzYyZDVjZWJiNTEifQ", "sort": "created_at_desc" } } ``` ## Pagination * Results are sorted by `created_at` descending. * `next_cursor` is opaque. Pass it back as `cursor` to get the next page. * `has_more` is `false` and `next_cursor` is `null` when there are no more posts. * List responses do not refresh destination status from the social platforms. Use `GET /social/post/{post_id}` for a fresh read of one post. # Update Social Post Source: https://docs.mosaic.so/api/social/patch-social-post PATCH /social/post/{post_id} Update supported fields on a social post. Updates the supported lifecycle, moderation, and platform-specific metadata fields on a social post. Use the `post_id` returned by `POST /social/post`. This endpoint cannot change post text, attached media, or destination platforms after the post has been created. Create a new post when those need to change. For posts with multiple destinations, schedule and approval updates are applied to every destination when `social_connection_id` is omitted. Moderation and platform-specific metadata fields require `social_connection_id` when the target destination cannot be inferred. ## Platform Support | Platform | Text / media edits | Reschedule | Approval | `disable_comments` | `platform_options` | | ----------- | ------------------ | -------------------- | --------------------- | ------------------ | ---------------------------- | | `x` | No | Scheduled posts only | Pending approval only | No | No | | `linkedin` | No | Scheduled posts only | Pending approval only | Yes | `linkedin.disable_comments` | | `instagram` | No | Scheduled posts only | Pending approval only | Yes | `instagram.disable_comments` | | `facebook` | No | Scheduled posts only | Pending approval only | No | No | | `tiktok` | No | Scheduled posts only | Pending approval only | No | No | | `youtube` | No | Scheduled posts only | Pending approval only | No | `youtube` | `platform_options` supports comment moderation for Instagram and LinkedIn, plus metadata updates for YouTube. Other platform-specific update objects are not supported for existing posts. ## Reschedule Request ```bash theme={null} curl -X PATCH "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "schedule_date": "2026-03-10T18:30:00Z" }' ``` ## Approval Request ```bash theme={null} curl -X PATCH "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "approved": true }' ``` `approved` is only for posts that were created with an approval requirement and are still waiting for approval. ## Comment Settings Request ```bash theme={null} curl -X PATCH "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform_options": { "linkedin": { "disable_comments": true } } }' ``` `disable_comments` can be updated for Instagram and LinkedIn destinations. The top-level `disable_comments` field is also accepted for backward compatibility. ## YouTube Metadata Request ```bash theme={null} curl -X PATCH "https://api.mosaic.so/social/post/[post_id]" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "social_connection_id": "540273be-42e4-41ac-86ad-6d72ebf7d7af", "platform_options": { "youtube": { "visibility": "public", "title": "Mosaic launch recap", "description": "A quick recap from launch week.", "category_id": 24 } } }' ``` ## Body Parameters | Field | Type | Required | Description | | --------------------------------------------- | ------------- | -------- | --------------------------------------------------------------------------------------------------------------------------- | | `schedule_date` | string | No | New scheduled publish timestamp as an ISO string. Only valid before a queued scheduled post publishes. | | `approved` | boolean | No | Set to `true` to approve a post that is waiting for approval. | | `disable_comments` | boolean | No | Disable or re-enable comments for Instagram or LinkedIn destinations. Prefer the platform-scoped form for new integrations. | | `platform_options` | object | No | Platform-specific update options for supported existing-post updates. | | `platform_options.instagram.disable_comments` | boolean | No | Disable or re-enable comments for an Instagram destination. | | `platform_options.linkedin.disable_comments` | boolean | No | Disable or re-enable comments for a LinkedIn destination. | | `platform_options.youtube.visibility` | string | No | One of `unlisted`, `private`, or `public`. | | `platform_options.youtube.title` | string | No | Updated YouTube title. | | `platform_options.youtube.description` | string | No | Updated YouTube description. | | `platform_options.youtube.category_id` | number | No | Updated YouTube category ID. | | `social_connection_id` | string (uuid) | No | Update using one specific connected account. Useful when a post targets multiple accounts on the same platform. | ## Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "scheduled", "scheduled_at": "2026-03-10T18:30:00Z", "updated_destinations": [ { "social_connection_id": "7f9388af-26e8-4e68-a52b-6b9a0ef3a017", "platform": "linkedin", "status": "scheduled" } ] } ``` ## Behavior * `schedule_date` changes Mosaic's queued publish time for scheduled posts that have not published yet. * `approved` does not create a new approval workflow. It only approves a post already waiting for approval. * `platform_options.instagram.disable_comments`, `platform_options.linkedin.disable_comments`, and top-level `disable_comments` all map to the same comment setting update. * Comment settings can be used on scheduled or published Instagram and LinkedIn posts. For queued scheduled posts, the setting is stored and applied when the post publishes. Existing platform behavior for previously created comments is platform-specific. * Comment settings cannot target only one destination if the original post grouped multiple comment-configurable platforms under one publishing operation. Create separate posts when you need independent comment settings. * `platform_options.youtube` can update supported YouTube metadata on YouTube posts. * `youtube_options` is still accepted as a backward-compatible alias for `platform_options.youtube`, but new integrations should use `platform_options.youtube`. # Create Social Connection Source: https://docs.mosaic.so/api/social/post-social-connections POST /social/connections Create a social account linking URL. Creates a new social connection setup flow and returns it as `connect_url`. After the user completes the setup flow, call `GET /social/connections` to find the new `social_connection_id`. Each setup flow creates one connected account slot. To connect another account on the same platform, create another social connection. If the organization cannot create another connection, the request returns an error and no setup URL is created. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/social/connections" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "platform": "linkedin", "connection_name": "Mosaic LinkedIn" }' ``` ## Body Parameters | Field | Type | Required | Description | | ----------------- | ------------ | -------- | ---------------------------------------------------------------------- | | `platform` | string | Yes | One of: `x`, `linkedin`, `instagram`, `facebook`, `tiktok`, `youtube`. | | `connection_name` | string | No | Friendly label for the connection during setup. | | `redirect_url` | string (url) | No | Override the post-connect redirect URL. | ## Response ```json theme={null} { "platform": "linkedin", "connect_url": "https://api.mosaic.so/social/connect/v1.x6WRGq...c2fJ3A" } ``` # Create Social Post Source: https://docs.mosaic.so/api/social/post-social-post POST /social/post Publish or schedule a social post. Publishes immediately or schedules a social post. The returned `post_id` is the ID to use with `GET /social/post/{post_id}`, `GET /social/post/{post_id}/analytics`, `GET /social/post/{post_id}/comments`, `PATCH /social/post/{post_id}`, and `DELETE /social/post/{post_id}`. Use `GET /social/posts` to list posts. Use `destinations` with `social_connection_id` values from `GET /social/connections` to post to specific accounts, including multiple accounts on the same platform. ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/social/post" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "post": "Motion product update", "destinations": [ { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628" }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d" } ], "media_urls": ["https://cdn.yourdomain.com/media/launch.mp4"], "schedule_date": "2026-03-10T16:00:00Z" }' ``` ## Body Parameters | Field | Type | Required | Description | | --------------- | ------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `post` | string | No | Post text. Defaults to an empty string. | | `platforms` | array | Conditional | One or more target platforms (`x`, `linkedin`, `instagram`, `facebook`, `tiktok`, `youtube`). Uses the first active account for each platform. Required when `destinations` is omitted. | | `destinations` | array | Conditional | Explicit target accounts. Each item may be a `social_connection_id` string or an object with `social_connection_id`. Required when `platforms` is omitted. | | `media_urls` | array | No | Public media URLs to attach. | | `schedule_date` | string | No | ISO timestamp to schedule instead of posting immediately. | | `workspace_id` | string (uuid) | No | Workspace to associate with the post. Defaults to the organization's primary workspace. | Additional social publishing fields are accepted when supported. ## Scheduling When `schedule_date` is in the future, Mosaic queues the post and returns a `post_id` you can use right away. The post's aggregate `status` is `scheduled` until the scheduled publish time is reached and publishing completes. Native `platform_post_id` and `post_url` values are `null` while the post is still waiting to publish. Call `GET /social/post/{post_id}` to check whether the post is still scheduled or has published. ## Scheduled Response ```json theme={null} { "post_id": "2d8ca860-f8e0-4f3f-9f2c-337ead6ed91e", "status": "scheduled", "publishing_status": null, "scheduled_at": "2026-03-10T16:00:00Z", "platforms": ["x", "linkedin"], "links": [], "results": [ { "platform": "x", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null, "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628" }, { "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null, "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d" } ], "destination_results": { "62c07212-eeb5-40e2-9902-e478027b8628": { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null }, "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d": { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "status": "scheduled", "platform_post_id": null, "post_url": null, "message": null } }, "destinations": [ { "social_connection_id": "62c07212-eeb5-40e2-9902-e478027b8628", "platform": "x", "account_name": "Motion", "account_username": "motion_so" }, { "social_connection_id": "8b59f2d7-53fa-4f47-9850-cb4b78b19a8d", "platform": "linkedin", "account_name": "Motion", "account_username": "motion-so" } ], "error": null, "publishing_errors": [] } ``` ## Response Details * `post_id` is the Mosaic social post ID. Use it for all post status, analytics, update, and delete calls. * `status` is Mosaic's aggregate status for the requested destinations. * `results` contains per-destination publishing outcomes when available. * `destination_results` is keyed by `social_connection_id` and preserves multiple accounts on the same platform. * `platform_post_id` is the native post ID from the destination platform. It can be `null` while a scheduled post is still waiting to publish. # List Agent Triggers Source: https://docs.mosaic.so/api/triggers/get-agent-triggers GET /agent/{agent_id}/triggers Retrieve all YouTube triggers configured for an agent. Returns all configured YouTube trigger nodes for an agent. Each agent can have multiple YouTube trigger nodes, and each trigger node can monitor multiple channels. The GET endpoint returns all triggers configured for the agent. ## Request ```bash theme={null} curl -X GET "https://api.mosaic.so/agent/[agent_id]/triggers" \ -H "Authorization: Bearer mk_your_api_key" ``` ## Response ```json theme={null} [ { "id": "8f7d6c5b-4a3e-2b1f-9d8c-1a2b3c4d5e6f", "type": "youtube", "youtube_channels": [ "UCxxxxxxxxxxxxxx", "UCyyyyyyyyyyyyyy" ], "youtube_channel_details": [ { "channel_id": "UCxxxxxxxxxxxxxx", "channel_name": "Marques Brownlee", "channel_handle": "@mkbhd", "thumbnail_url": "https://yt3.googleusercontent.com/...", "subscriber_count": 19200000 }, { "channel_id": "UCyyyyyyyyyyyyyy", "channel_name": "Cinematic Clips", "channel_handle": "@cinematicclips", "thumbnail_url": null, "subscriber_count": null } ], "callback_url": "https://your-app.com/webhooks/trigger", "filter_options": { "duration": { "min_seconds": 120, "max_seconds": 2700 } } } ] ``` Returns an empty array `[]` if no triggers are configured. Each trigger represents a trigger node with its associated YouTube channels. `youtube_channel_details` includes `channel_name`, `channel_handle`, `thumbnail_url`, and `subscriber_count`. Some fields may be `null` if Mosaic has not yet refreshed metadata for a channel. Always fall back to `youtube_channels` when details are unavailable. `filter_options.duration` is optional. When present, only videos within the configured duration bounds (in seconds) trigger runs for that specific trigger node. If only `min_seconds` is set, videos shorter than that are ignored; if only `max_seconds` is set, videos longer than that are ignored. When channels are added through `POST /agent/{agent_id}/triggers/add_youtube_channels`, a channel is moved to the selected trigger signature if it already exists on another YouTube trigger node for the same agent. Execution is deduplicated per video input target: if multiple YouTube trigger nodes match the same new video and point to the same Video Input node, Mosaic starts a single run for that target. # Add YouTube Channels Source: https://docs.mosaic.so/api/triggers/post-add-youtube-channels POST /agent/{agent_id}/triggers/add_youtube_channels Add YouTube channels to an agent trigger. Adds channel IDs/URLs into the selected YouTube trigger set (matched by `filter_options`). You do not need to resend previously added channels. **Behavior:** * Creates a new trigger if none exists * Merges new channels into an existing trigger **with matching `filter_options`** if one exists * Creates a new YouTube trigger node when no existing trigger has matching `filter_options` * If a channel already exists on a different YouTube trigger node for this agent, it is moved to the selected trigger node * Deletes emptied YouTube trigger nodes after channel moves * Updates the webhook URL if `trigger_callback_url` is provided * Clears the webhook URL when `trigger_callback_url` is explicitly `null` ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/triggers/add_youtube_channels" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "youtube_channels": [ "UCxxxxxxxxxxxxxx", "https://www.youtube.com/@mkbhd" ], "trigger_callback_url": "https://your-app.com/webhooks/youtube-trigger", "filter_options": { "duration": { "min_seconds": 120, "max_seconds": 2700 } } }' ``` ## Parameters | Field | Type | Required | Description | | ---------------------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `youtube_channels` | string\[] | Yes | List of **new** YouTube channel IDs or URLs to add | | `trigger_callback_url` | string \| null | No | Optional webhook URL. If provided as a string, it **replaces** the existing webhook URL for the selected trigger node. If provided as `null`, the existing webhook URL is removed. Omit this field to keep the existing callback URL unchanged. | | `filter_options` | object | No | Optional trigger filters. Currently supports `filter_options.duration.min_seconds` and `filter_options.duration.max_seconds` (inclusive bounds in seconds). | ## Response ```json theme={null} { "message": "YouTube channels added successfully", "channel_ids": [ "UCxxxxxxxxxxxxxx", "UCyyyyyyyyyyyyyy" ], "channels": [ { "input": "UCxxxxxxxxxxxxxx", "channel_id": "UCxxxxxxxxxxxxxx" }, { "input": "https://www.youtube.com/@mkbhd", "channel_id": "UCyyyyyyyyyyyyyy" } ], "filter_options": { "duration": { "min_seconds": 120, "max_seconds": 2700 } }, "youtube_channel_details": [ { "channel_id": "UCxxxxxxxxxxxxxx", "channel_name": "Channel Name", "channel_handle": null, "thumbnail_url": null, "subscriber_count": null }, { "channel_id": "UCyyyyyyyyyyyyyy", "channel_name": "Marques Brownlee", "channel_handle": "@mkbhd", "thumbnail_url": "https://yt3.googleusercontent.com/...", "subscriber_count": 19200000 } ] } ``` **Duplicate Handling**: If you add a channel that is already monitored on the selected trigger (same filter signature), it is ignored. If that channel exists on another trigger with a different filter signature, it is removed from the other trigger and moved to the selected one. **Run Deduplication**: At execution time, if multiple YouTube trigger nodes still match the same new video and target the same Video Input node, Mosaic starts one run for that target (not one run per trigger tile). # Remove YouTube Channels Source: https://docs.mosaic.so/api/triggers/post-remove-youtube-channels POST /agent/{agent_id}/triggers/remove_youtube_channels Remove monitored YouTube channels from an agent trigger. Subtractively removes only the listed channels, leaving all other monitored channels intact. **Behavior:** * Removes specified channels from **all** YouTube trigger nodes for the agent (duplicate-safe removal) * If a trigger node has no channels left after removal, that trigger node is deleted * Does not affect channels that are not specified ## Request ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/[agent_id]/triggers/remove_youtube_channels" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "youtube_channels": ["UCxxxxxxxxxxxxxx"] }' ``` ## Parameters | Field | Type | Required | Description | | ------------------ | --------- | -------- | ----------------------------------------------- | | `youtube_channels` | string\[] | Yes | YouTube channel IDs or URLs to stop monitoring. | # Webhook Events Source: https://docs.mosaic.so/api/webhooks/events Receive real-time notifications for agent run lifecycle. Provide a `callback_url` when calling [Run Agent](/api/agent-runs/post-agent-run) to receive webhook POSTs for run lifecycle events. ## Authentication If you have a webhook secret configured, every webhook includes an `X-Mosaic-Signature` header containing the secret as a plaintext string. Validate with a direct comparison: ```python theme={null} if request.headers.get('X-Mosaic-Signature') != os.environ['MOSAIC_WEBHOOK_SECRET']: return {"error": "Unauthorized"}, 401 ``` *** ## Common Fields Every webhook payload contains these fields: | Field | Type | Description | | -------------------- | ---------------- | ------------------------------------------------------ | | `flag` | `string` | `"RUN_STARTED"`, `"RUN_PROGRESS"`, or `"RUN_FINISHED"` | | `agent_id` | `string` | Agent UUID | | `run_id` | `string` | Run UUID | | `status` | `string` | Current run status | | `node_status_counts` | `object` | `{ completed, in_progress, failed }` | | `triggered_by` | `object \| null` | What initiated the run (see below) | `needs_credits` and `errors` are included on `RUN_FINISHED` payloads when available. *** ## RUN\_STARTED Sent when the run begins. ```json theme={null} { "flag": "RUN_STARTED", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "status": "running", "inputs": [ { "video_url": "https://storage.googleapis.com/.../input.mp4", "thumbnail_url": "https://storage.googleapis.com/.../thumb.jpg" } ], "node_status_counts": { "completed": 1, "in_progress": 5, "failed": 0 }, "triggered_by": null } ``` **Additional fields:** `inputs` — array of `{ video_url, thumbnail_url }` for the input videos. *** ## RUN\_PROGRESS Sent when one or more nodes change status. Useful for progress tracking without polling. ```json theme={null} { "flag": "RUN_PROGRESS", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "status": "running", "node_status_counts": { "completed": 4, "in_progress": 3, "failed": 0 }, "updated_nodes": [ { "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8", "status": "completed", "status_message": null, "errors": [], "outputs": [ { "id": "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "video_url": "https://storage.googleapis.com/...", "thumbnail_url": "https://storage.googleapis.com/...", "premiere_prproj_url": "https://storage.googleapis.com/.../timeline.zip?...", "sources": [ { "provider": "getty", "source_kind": "licensed_library", "media_type": "image", "provider_asset_id": "1234567890", "render_asset_id": "getty_image_000", "query": "mayor press conference", "start_ms": 1200, "end_ms": 3400, "placement": "partial_screen", "layout": "bottom", "getty_asset_family": "editorial" } ], "completed_at": "2024-01-15T10:35:00Z", "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8" } ] } ], "triggered_by": null } ``` **Additional fields:** | Field | Type | Description | | ---------------------------------- | ---------------- | --------------------------------------------------------------------------------------- | | `updated_nodes[].original_node_id` | `string \| null` | Template `agent_node_id` — use to map back to your agent | | `updated_nodes[].status` | `string` | `completed`, `running`, `queued`, `failed`, `blocked`, `partial_complete` | | `updated_nodes[].status_message` | `string \| null` | Human-readable message | | `updated_nodes[].errors` | `array` | Error messages from failed tasks in this node. Empty array when the node has no errors. | | `updated_nodes[].outputs` | `array` | Outputs produced by this node (if any) | *** ## RUN\_FINISHED Sent when the run reaches a terminal state. Contains all final outputs. ```json theme={null} { "flag": "RUN_FINISHED", "agent_id": "123e4567-e89b-12d3-a456-789012345678", "run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d", "status": "completed", "status_message": null, "needs_credits": false, "errors": [], "inputs": [ { "video_url": "https://storage.googleapis.com/.../input.mp4", "thumbnail_url": "https://storage.googleapis.com/.../thumb.jpg" } ], "outputs": [ { "id": "7ba7b810-9dad-11d1-80b4-00c04fd430c8", "video_url": "https://storage.googleapis.com/.../output.mp4", "thumbnail_url": "https://storage.googleapis.com/.../thumb.jpg", "premiere_prproj_url": "https://storage.googleapis.com/.../timeline.zip?...", "sources": [ { "provider": "getty", "source_kind": "licensed_library", "media_type": "image", "provider_asset_id": "1234567890", "render_asset_id": "getty_image_000", "query": "mayor press conference", "start_ms": 1200, "end_ms": 3400, "placement": "partial_screen", "layout": "bottom", "getty_asset_family": "editorial" } ], "completed_at": "2024-01-15T10:35:00Z", "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8" } ], "node_status_counts": { "completed": 10, "in_progress": 0, "failed": 0 }, "triggered_by": null } ``` When a run fails, `errors` contains error details grouped by template node: ```json theme={null} { "flag": "RUN_FINISHED", "status": "failed", "status_message": "Processing failed for one or more tiles.", "errors": [ { "original_node_id": "2ba7b810-9dad-11d1-80b4-00c04fd430c8", "messages": ["FFmpeg render failed: output format not supported"] }, { "original_node_id": "3ca7b810-9dad-11d1-80b4-00c04fd430c8", "messages": [ "Audio transcription timed out after 300s", "Retry failed: service unavailable" ] } ], "node_status_counts": { "completed": 3, "in_progress": 0, "failed": 2 }, "..." } ``` **Additional fields:** | Field | Type | Description | | --------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------- | | `status` | `string` | `completed`, `partial_complete`, or `failed` | | `status_message` | `string \| null` | Human-readable detail on failure | | `needs_credits` | `boolean` | `true` when one or more runtime tasks in the run are marked `needs_credits=true` (insufficient credits). | | `errors` | `array` | Error messages grouped by template node. Empty array `[]` when the run has no errors. | | `errors[].original_node_id` | `string \| null` | Template `agent_node_id` the errors originated from | | `errors[].messages` | `array` | List of error messages from failed tasks in this node | | `inputs` | `array` | `{ video_url, thumbnail_url }` for each input | | `outputs` | `array` | Final rendered outputs (see below) | When `needs_credits` is `true`, check `GET /plan` first. If no paid plan is active, list plans with `GET /plan/list`, upgrade with `POST /plan/upgrade`, and complete checkout if `requires_checkout: true`. After plan activation, optionally enable auto top-ups via `POST /credits/settings` if your active plan is `creator`, `creator_annual`, `professional`, or `professional_annual`, then call `POST /agent_run/{run_id}/resume` to continue the run. **Output fields:** | Field | Type | Description | | --------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | `string` | Render ID — use for chaining runs via `node_render_ids` | | `video_url` | `string` | Signed download URL (valid 7 days) | | `thumbnail_url` | `string \| null` | Signed thumbnail URL | | `premiere_prproj_url` | `string \| null` | Signed URL for the Premiere Pro timeline zip attached to this render (when available) | | `sources` | `array` | Source citations for licensed or external media used in this output. Getty b-roll citations include timing, query, asset IDs when resolved, placement, and rights metadata. | | `completed_at` | `string` | ISO 8601 timestamp | | `original_node_id` | `string \| null` | Template node that produced this output | *** ## `triggered_by` Present when the run was started by a trigger or YouTube URL. `null` for standard API runs. ```json theme={null} { "type": "youtube", "channel_id": "UCxxxxxxxxxxxxxx", "video_id": "dQw4w9WgXcQ", "video_title": "Never Gonna Give You Up", "video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "triggered_at": "2024-01-15T10:30:00Z", "trigger_id": "8f7d6c5b-4a3e-2b1f-9d8c-1a2b3c4d5e6f" } ``` `type` is one of `"youtube"`, `"schedule"`, or `"manual"`. *** ## Run Status Values | Status | Meaning | | ------------------ | ------------------------------------- | | `running` | Processing in progress | | `completed` | All outputs generated successfully | | `partial_complete` | Some outputs succeeded, others failed | | `failed` | No outputs generated | | `cancelled` | Cancelled by user | # 5.5 Credits (Bottom Left) Source: https://docs.mosaic.so/canvas/credits Track your remaining credits and purchase more The number in the **bottom left** of your canvas shows how many credits you have remaining. Credits are consumed when you run AI-powered tiles and workflows. *** ## Purchase More Credits Click on the credits counter to purchase additional credits anytime. | | Details | | -------------------- | ------------------------------------ | | **Price** | $0.01/credit ($10 for 1,000 credits) | | **Minimum purchase** | 100 credits | | **Maximum purchase** | 1,000,000 credits | *** ## View Your Usage Want to see where your credits are going? Head to **Settings > Usage** for a full breakdown of your credit consumption across tiles and models. Check your credit balance and usage breakdown # 5.3 Give Feedback (Top Left) Source: https://docs.mosaic.so/canvas/feedback Report bugs or suggest improvements If something isn't working right — or if you have an idea that would make Mosaic better — click the **Feedback** button in the top left of your canvas. ## What You Can Report * **Bugs** — something broke, an export failed, or a tile isn't behaving as expected * **Suggestions** — a feature you'd love to see, a workflow improvement, or a UX tweak * **Questions** — stuck on something? Let us know and we'll help you out We actively review every piece of feedback. If your export is slow or something feels off, this is the fastest way to get it resolved. # 5.4 Rename Your Mosaic (Top Center) Source: https://docs.mosaic.so/canvas/rename Organize your projects by renaming them Click the name at the **top center** of your canvas to rename your Mosaic and add a description. *** ## Why Renaming Matters As your workflow grows — more tiles, more branches, more outputs — it gets harder to keep track of what each Mosaic does. A clear name and description help you: * **Find the right Mosaic instantly** when you have dozens of projects * **Remember what a workflow does** weeks or months after you built it * **Stay organized across clients, projects, and platforms** without second-guessing **Good naming habit:** Use a format like `[Client] - [Project] - [Platform]` to keep things clean. For example: `Acme Corp - Product Demo - YouTube`. *** ## What You Can Edit | Field | What it does | | --------------- | ------------------------------------------------------------------- | | **Name** | The main title shown on your canvas and in your Mosaic list | | **Description** | A short note to remind you (or your team) what this workflow is for | The earlier you start naming and describing your Mosaics, the easier it is to manage everything as your library grows. # 5.2 Share (Top Right) Source: https://docs.mosaic.so/canvas/share Share your Mosaic with others Control who can see your Mosaic using the **Share** button in the top right of your canvas. There are two sharing modes: *** ## Private Share **Only the author can view** Your Mosaic is locked to your account. No one else can access it — this is the default for every new Mosaic. Best for: * Work in progress * Internal drafts * Anything not ready for external eyes *** ## Public Share **Anyone with the link can view** Generate a shareable link that lets anyone view your Mosaic — including the full workflow, tiles, and outputs. Best for: * **Publicly sharing your Mosaics** with your audience or community * **Sharing workflows and templates** so others can learn from or remix your setup * **Showcasing your work** on social media, portfolios, or blogs **Affiliate tip:** Sharing your Mosaics publicly can also benefit you if you're a [Mosaic Affiliate](/how-to/affiliate-program). When people discover Mosaic through your shared workflows, you earn **20% of revenue** from every purchase they make. # 5.1 Toolbar (Mid Left) Source: https://docs.mosaic.so/canvas/toolbar Tools for working with your Mosaic workflow The toolbar lives on the left side of your canvas. Here's what each tool does: | Icon | Tool | What it does | | :------------------------------------: | ---------------------- | -------------------------------------------------------------------- | | | **Select** | Click and select tiles on your canvas to move, edit, or connect them | | | **Pan** | Grab and drag to move around the canvas freely — no tiles affected | | | **Zoom In** | Get a closer look at a specific part of your canvas | | | **Zoom Out** | Pull back to see more of your workflow at once | | | **Fit** | Instantly auto-center and fit your entire workflow into view | | | **Keyboard Shortcuts** | View all available shortcuts to speed up your editing | **Pro tip:** Use **Fit** when you lose track of your tiles — it snaps everything back into view instantly. # 7.2 Affiliate Program Source: https://docs.mosaic.so/how-to/affiliate-program Share Mosaic and earn 20% of every purchase Share Mosaic with others and earn **20% of revenue** from every purchase made through your link. Generate your unique code and start earning today **Creators are already earning \$1,000+ with the Mosaic Affiliate Program.** All it takes is a link and a network that cares about great video. *** ## How It Works Head to the affiliate dashboard and create your unique referral code. This takes seconds. Send your link to friends, followers, or your community. Share it anywhere — social media, newsletters, DMs, videos. Anyone who signs up through your link gets **20% off their first paid plan** — an easy sell. You earn **20% of revenue** from every purchase they make. It's that simple. *** ## At a Glance | | Details | | ------------------- | ------------------------------------------------ | | **Your commission** | 20% of revenue from every purchase | | **Their benefit** | 20% off their first paid plan | | **Setup time** | Less than a minute | | **Payout** | Ongoing — you earn as long as they're subscribed | *** ## Ready to Start? Some affiliates have already crossed **\$1,000 in earnings** — and they started with just a single link. The earlier you start, the more you earn. Create your code, grab your link, and start sharing Mosaic # 7.3 FAQs Source: https://docs.mosaic.so/how-to/faqs Common questions answered Answers to the most common questions about using Mosaic. Sometimes exports may take longer due to larger or more complex workflows — this is normal for multi-tile pipelines with heavy AI processing. If it persists, just click the **Feedback** button on your canvas and we'll help you resolve it as soon as possible. Credits are consumed based on the AI models and tiles you use in your workflows. Different tiles and models have different credit costs depending on the processing involved. You can view your current usage anytime by going to **Settings > Usage** in the Mosaic editor. Check your credit balance and usage breakdown We support most video formats. Feel free to import those long podcasts — Mosaic can handle it. | Limit | Value | | ----------------- | --------------------------------------- | | **Max file size** | 20 GB | | **Max duration** | 300 minutes | | **Formats** | MP4, MOV, and most common video formats | Double-click on the canvas to open the tile picker. Start with a **Video Input** tile, then connect **Creation** or **Action** tiles to build your workflow. For a full walkthrough, check out [How Tiles Work](/tiles/how-tiles-work). # 7.1 Manage Subscription Source: https://docs.mosaic.so/how-to/manage-subscription Change plans, update billing, and view usage All subscription and billing management happens in one place — **Settings > Plans & Billing** inside the Mosaic editor. Go to Settings > Plans & Billing in the Mosaic editor *** ## What You Can Do See which plan you're on, what's included, and when your next billing cycle is. Head to **Settings > Plans & Billing** to view your plan details at any time. Ready for more? Click **Manage Billing** inside Plans & Billing to upgrade to a higher tier or switch between monthly and annual billing. Need to swap your card or update billing details? Click **Manage Billing** to securely update your payment information. You can cancel anytime from **Manage Billing**. Your access continues until the end of your current billing period. *** ## Quick Steps Click the settings icon in the Mosaic editor, or use the link above. Select the **Plans & Billing** tab to see your current plan and usage. To change your plan, update payment methods, or cancel — click **Manage Billing** to open the billing portal. *** Manage your subscription, billing, and payment methods # 7.4 Templates Source: https://docs.mosaic.so/how-to/templates Pre-built workflows to get started fast Templates are pre-built Mosaic workflows you can open and start using immediately. Pick one that matches your use case, customize it, and hit run.
🎬
Clips: Long Form to Short Form
Best for Podcasters

Extract the best moments from long-form content and turn them into viral short-form clips.

🎙️
Talking Head to Motion Graphics
Best for Founders

Transform talking head videos into polished content with animated motion graphics and captions.

🧹
Clean Up Raw Footage
Best for Founders

Remove silences, enhance audio, and polish raw footage into clean, share-ready video.

🎨
Motion Graphics A/B Test
Best for Creators

Generate multiple motion graphic variations from the same footage and test what performs best.

🎵
Music Paced Montage
Best for Creators

Build dynamic montages with cuts that sync perfectly to the beat of AI-generated music.

📱
Social Cutdowns
Best for Podcasters

Automatically reframe and cut long-form content into platform-ready social clips.

🤖
AI Avatar Showcase
Best for Agencies

Create professional AI avatar videos for demos, presentations, and brand content.

🏭
AI Avatar Farm
Best for Agencies

Generate avatar videos at scale — multiple scripts, voices, and styles in one workflow.

🔥
Sizzle Reels
Best for Agencies

Build high-energy sizzle reels with pacing cues, impact moments, and cinematic flair.

# 6. Models Source: https://docs.mosaic.so/models AI models available across Mosaic features, billed by generation seconds. Mosaic uses a range of AI models across its creation tiles. Each model is billed by **generation seconds** — the duration of the content it produces. One subscription gives you access to all models. *** ## AI Avatar Generate realistic AI presenters that speak your script with natural lip sync. [Learn more](/tiles/ai-avatar) | Model | Unit | | --------------- | ------------------ | | Seedance 2 Fast | Generation Seconds | | Seedance 2 | Generation Seconds | | Kling 2.6 Pro | Generation Seconds | | Kling 3 | Generation Seconds | | Kling 3 Pro | Generation Seconds | *** ## AI Avatar (Single Take) Create single-take avatar videos with a continuous, natural delivery style. [Learn more](/tiles/ai-avatar) | Model | Unit | | --------- | ------------------ | | Fabric 1 | Generation Seconds | | Longcat 1 | Generation Seconds | *** ## Video Generation Generate video clips from text prompts and optional media references. [Learn more](/tiles/video-generation) | Model | Unit | | ---------- | ------------------ | | Seedance 2 | Generation Seconds | Seedance 2 output at 4K resolution is billed at 2x normal Seedance. *** ## Audio Generation Generate voiceovers or music from scripts and prompts. [Learn more](/tiles/audio-generation) | Model | Unit | | --------- | ------------------ | | Eleven v3 | Generation Seconds | | Music | Generation Seconds | *** ## Image Generation Generate still images from prompts and image context. [Learn more](/tiles/image-generation) | Model | Unit | | ----------- | ---------------- | | GPT Image 2 | Generated Images | *** Credits are consumed based on the model and generation duration. Check your usage anytime in **Settings > Usage**. [View usage](https://edit.mosaic.so/?settings_org=7cab1f8a-8161-4619-a36d-3dd3709dd7c0\&settings_tab=usage) # 8.1 API Source: https://docs.mosaic.so/more/api Programmatic access to Mosaic For full API documentation — including authentication, endpoints, webhooks, and triggers — visit the dedicated API reference: Explore the full API reference at docs.mosaic.so/api # 8.2 Community Source: https://docs.mosaic.so/more/community Join our Discord and communities Join the Mosaic community on Discord to share work, ask questions, and learn workflows: Join the community at discord.gg/26SAZzBTaP # 8.3 Enterprise Source: https://docs.mosaic.so/more/enterprise Scalable AI video infrastructure for teams and organizations. For enterprise plans, features, and pricing — visit the dedicated enterprise page: Explore scalable AI video infrastructure at mosaic.so/enterprise # 3.1 Our Product Philosophy Source: https://docs.mosaic.so/mosaic-concepts/product-philosophy The principles that guide Mosaic's design Mosaic is built for creators, editors, and teams who need fast, consistent, scalable editing without sacrificing quality. Here are the six principles that guide every design decision: People think visually — so workflows should be visual. Instead of writing scripts or navigating menus, you connect tiles on a canvas and see your workflow take shape in real time. Editing is a series of decisions. Tiles express those decisions clearly — each one represents a single creative or technical choice, making complex workflows easy to understand at a glance. Most users shouldn't need to configure 100 knobs. Mosaic ships with intelligent defaults so you can get great results immediately, and fine-tune only when you want to. Beginners should be able to publish in 5 minutes. Power users can go deeper with prompts, model selection, and API automation. The complexity is there — it's just not in the way. 9:16 is not 16:9 — formats matter. Mosaic understands where your content is going and adapts framing, pacing, and style to fit the platform. Users care about outcomes, not software. Every feature in Mosaic exists to get you from raw footage to published content faster — nothing more, nothing less. # 2.1 The Creative Process Source: https://docs.mosaic.so/quickstart/creative-process The simple 3-step Mosaic creative flow The Mosaic creative flow has 3 simple steps: Upload or import your raw video — from your device, Google Drive, Dropbox, or a link. Connect creation and action tiles to build your editing workflow visually. Publish to social platforms, export files, or share your Mosaic publicly. Think of it like a storyboard for automation — each tile is a creative or technical decision. *** ## Three Types of Tiles Every tile falls into one of three categories: | Type | Role | Examples | | ------------------ | --------------------- | ---------------------------------- | | **Input Tiles** | Bring media in | Video Upload, YouTube Trigger | | **Creation Tiles** | Generate new media | AI Avatar, AI B-Roll, AI Music | | **Action Tiles** | Modify existing media | Captions, Reframe, Silence Removal | The pattern is always the same: **bring it in, create what's missing, shape it into something great.** For a deeper dive into how tiles connect and work together, see [How Tiles Work](/tiles/how-tiles-work). # 2.2 Sign Up & Set Up Source: https://docs.mosaic.so/quickstart/sign-up Get started with Mosaic in minutes Image Getting started takes less than a minute: Open [**edit.mosaic.so**](https://edit.mosaic.so) in your browser — no downloads or installs needed. Sign up using Google or email, then verify your email address. You'll arrive at your **Mosaic Canvas** — your visual workspace where all editing happens. That's it — no installers, no plugins, no messy setup. You're ready to build your first workflow. Learn what you can do on the canvas and how to start editing # 2.3 Welcome to Your Video Canvas Source: https://docs.mosaic.so/quickstart/video-canvas Explore your Mosaic workspace Image The canvas is your workspace — everything in Mosaic happens here. It's a visual, infinite space where you build editing workflows by connecting tiles. On the canvas you can: * **Upload footage** — drag and drop or use the Video Input tile * **Add tiles** — double-click anywhere to open the tile picker * **Preview results** — watch outputs directly in the canvas * **Branch workflows** — create multiple edits from the same source * **Re-run anytime** — tweak settings and run again instantly * **Share or export** — publish to platforms or download your files Every Mosaic workflow is visual, modular, and editable at any time. Understand the building blocks of every workflow Start with a pre-built workflow and customize it # 1. AI Avatar Source: https://docs.mosaic.so/tiles/ai-avatar Create reusable AI presenters and generate talking-head videos from scripts. AI Avatar creates a reusable presenter from a short reference clip or image/voice pair, then generates talking-head videos from a script. It is best for founder updates, explainers, UGC ads, training videos, and repeatable spokesperson content. ## How It Works The AI Avatar flow has two parts: * **Create an avatar:** provide a 4-15 second source video, or provide an image plus a 4-15 second voice reference. Mosaic processes this into reusable avatar references. * **Generate a video:** select the avatar profile, write the script, choose the model and take style, then run the agent. AI Avatar ## Avatar Profiles Avatars live in your workspace library and can be used from the editor or API. Mosaic prepares the reference video, reference image, and voice audio during processing. Recommended source video: * 4-15 seconds long * Exactly one person on screen * Clear face, direct-to-camera framing * Natural speech with visible mouth movement from that person * Clean single-speaker audio from that person; avoid background speakers, music, heavy noise, or dubbing * Minimal cuts, overlays, or visual effects If you use an image plus voice reference instead of a source video, the image should show the same single person you want to generate, and the voice reference should contain only that person's clear speech. ## Single Take vs Multitake **Single take** asks the model for one continuous delivery. Use it for short scripts where a natural uninterrupted performance matters most. **Multitake** lets Mosaic split longer scripts into sentence-complete chunks, render multiple takes, normalize them, and stitch the final output. Use it for longer scripts, retries, or workflows where reliability matters more than one uninterrupted provider clip. Seedance 2 and Seedance 2 Fast support both modes in Mosaic. In multitake mode, Mosaic still preserves the avatar identity and voice while chunking the script behind the scenes. ## Model Options Seedance 2 and Seedance 2 Fast are the recommended AI Avatar models. They are Mosaic's most cost-effective and life-like avatar generation options, and they support both single take and multitake generation with avatars from your library. | Model | Best For | Notes | | ------------------ | -------------------------------------------- | ---------------------------------------------------------------------------------- | | `seedance-2-fast` | Recommended fast avatar generation | Most cost-effective option. Fast provider output is upscaled to 1080p when needed. | | `seedance-2` | Recommended high-quality avatar generation | Most life-like option. Supports 16:9 and 9:16. | | `avatar-v4` | Legacy Longcat 1 single-take avatars | Requires a voice reference or avatar profile. | | `fabric-1` | Legacy lip-sync style single-take generation | Can use an uploaded voiceover. | | `kling-2.6-pro` | Legacy multitake avatar generation | Supports product and character references. | | `kling-3-standard` | Legacy multitake avatar generation | Shown as Kling 3 in the editor. | | `kling-3-pro` | Legacy multitake avatar generation | Higher-cost legacy Kling option. | ## API Workflow 1. Create an avatar with `POST /avatar-profiles/create`. 2. Create an agent with `POST /agent/create`, then add an AI Avatar node with `POST /agent/{agent_id}/update`. 3. Run the agent with `POST /agent/{agent_id}/run` and no video inputs. Avatar processing starts automatically when you create the avatar. You can use the avatar ID in an AI Avatar tile immediately; if the avatar is still processing, the run waits for it to become ready. If the avatar's `processing_status` is `failed`, create a new avatar before using it. Create an avatar: ```bash theme={null} curl -X POST "https://api.mosaic.so/avatar-profiles/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Founder Avatar", "sources": { "video_url": "https://example.com/founder-reference.mp4" } }' ``` Create an agent shell: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Seedance Avatar Generator", "visibility": "private" }' ``` Add an AI Avatar node: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/update" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "create_node", "node_type_id": "b3b4c9e2-2a47-4fa9-8ce8-0c1fa1d7b6ef", "params_used": { "avatar_profile_id": "AVATAR_PROFILE_ID", "video_model": "seedance-2-fast", "single_take": false, "aspect_ratio": "9:16", "script": "Here is the exact script the avatar should say." } } ] }' ``` Run the AI Avatar agent: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "callback_url": "https://your-webhook.com/mosaic" }' ``` Use `video_model: "seedance-2"` for the higher-quality Seedance 2 path. Set `single_take: true` for one continuous delivery, or `false` for multitake chunking. *** ## API Info * **Node ID:** `b3b4c9e2-2a47-4fa9-8ce8-0c1fa1d7b6ef` ### Node params | Param | Type | Required | Default | Notes | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ----------- | ------------------- | ----------------------------------------------------------------------------- | | `brief` | `string` | Yes | `""` | High-level intent/context (validated, \~1-1000 chars). | | `script` | `string` | Yes | `""` | Spoken script. | | `video_model` | `"seedance-2-fast" \| "seedance-2" \| "kling-2.6-pro" \| "kling-3-standard" \| "kling-3-pro" \| "fabric-1" \| "avatar-v4"` | No | `"seedance-2-fast"` | Generation model choice. | | `single_take` | `boolean` | No | `true` | `true` for one continuous delivery; `false` for multitake chunking/stitching. | | `aspect_ratio` | `"9:16" \| "16:9" \| "auto"` | No | `"9:16"` | Output framing mode. | | `avatar_profile_id` | `string` (UUID) | Conditional | unset | Reusable avatar. Required for Seedance 2 models. | | `creation_mode` | `"manual" \| "video_reference"` | No | `"manual"` | Avatar generation flow selection. | | `reference_video_id` | `string` (UUID) | Conditional | unset | Used when `creation_mode="video_reference"`. | | `reference_change_request` | `string` | No | `""` | Optional instructions when using video-reference mode. | | `product_image_id` | `string` (UUID) | No | unset | Product reference image. | | `character_image_id` | `string` (UUID) | No | unset | Avatar/character image override. | | `voice_reference_id` | `string` (UUID) | No | unset | Voice reference asset ID for cloning. | | `voice_reference_type` | `"audio" \| "video"` | Conditional | unset | Required when `voice_reference_id` is provided. | | `voiceover_id` | `string` (UUID) | Conditional | unset | Optional voiceover upload for Fabric 1 lip-sync path. | | `voiceover_type` | `"audio" \| "video"` | Conditional | unset | Required when `voiceover_id` is provided. | | `elevenlabs_model_id` | `string` | No | unset | Explicit ElevenLabs model override. | | `elevenlabs_voice_settings` | `{stability?:number,similarity_boost?:number,style?:number,use_speaker_boost?:boolean,speed?:number}` | No | unset | Fine-grained TTS tuning object. | | `voice_dictionary` | `Array<{word:string,audio_id:string,enabled:boolean}>` | No | `[]` | Up to three pronunciation references for Seedance 2. | ### Parameter groups * **Core generation:** `brief`, `script`, `video_model`, `single_take`, `aspect_ratio` * **Avatar library:** `avatar_profile_id` * **Creation flow:** `creation_mode`, `reference_video_id`, `reference_change_request` * **Visual references:** `product_image_id`, `character_image_id` * **Voice references:** `voice_reference_id`, `voice_reference_type`, `voiceover_id`, `voiceover_type` * **Voice tuning:** `elevenlabs_model_id`, `elevenlabs_voice_settings`, `voice_dictionary` ### Example ```json theme={null} { "avatar_profile_id": "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", "script": "We built this to help teams publish polished videos in minutes.", "aspect_ratio": "9:16", "video_model": "seedance-2-fast", "single_take": false } ``` # 2. AI B-Roll Source: https://docs.mosaic.so/tiles/ai-broll Automatically generate or source relevant B-roll that matches what's being said in your video. Automatically generate or source relevant B-roll that matches what's being said in your video, helping you increase visual variety, storytelling quality, and audience retention. AI B-roll is especially useful for **talking-head videos, interviews, podcasts, explainers, and educational content** that benefit from visual support. ## How It Works The AI B-Roll tile analyzes your video's speech, plans relevant visual cutaways, generates short video clips, and overlays them at appropriate timestamps. You can control: * B-roll density * Video generation model * Aspect ratio * Whether generated clips include audio * Maximum number of generated clips * Visual style and content focus ## Input & Settings ### Coverage Level Defines how much B-roll gets added per minute. Options include (may vary by build): * **Minimal** * **Moderate** ← Balanced default * **High** * **Maximal** Use **Minimal** for subtle enhancement and **Maximal** for heavy coverage. ### Video Model Select which AI model to generate B-roll with. Supported API values: * `seedance-2` * `veo-3.1` * `veo-3.1-fast` * `veo-3.1-lite` Different models produce different visual styles (cinematic, realistic, stylized, etc.). ### Aspect Ratio Controls the shape of generated B-roll. Options: * **Auto** (recommended) → Matches your input video or target platform * **16:9** for YouTube/desktop * **9:16** for TikTok/Reels/Shorts Choose based on your **final output format**. ### Generate Audio (Optional) Toggle to include audio in the generated B-roll. Notes: * Not all models support audio * Useful for cinematic segments * Not required for overlay-style B-roll ### Max Video Generations Sets the max number of B-roll scenes to create. The backend caps this at 20 generated clips for deterministic runtime. ### Style & Content Prompt (Optional) Use this to define: * Visual style * Subject matter * Tone / vibe Examples: * "Cinematic city skyline shots, wide angle, slow motion" * "Stock footage of office work and laptops, clean and modern" * "Playful animated visuals matching educational content" * "Nature and planet shots, documentary style" Leave blank to let Mosaic choose based on content. ## Usage Recommendations Use AI B-roll to: * Break up long talking segments * Add visual context to explanations * Support storytelling * Improve audience retention AI B-roll works great when combined with: * **Clips** (extract highlights first) * **Reframe** (convert to 9:16 for TikTok) * **Captions** (add subtitles) * **AI Music** (background audio) *** ## API Info * **Node ID:** `2160392b-ebe8-4f3d-b81e-fd11bdbbeb77` ### Node params | Param | Type | Required | Default | Notes | | ----------------------- | --------------------------------------------------------------- | -------- | -------------- | ---------------------------------------------------------------------- | | `coverage_level` | `"low" \| "moderate" \| "high" \| "max"` | No | `"moderate"` | Amount/frequency of generated B-roll. | | `prompt` | `string` | No | `""` | Optional visual/style guidance. | | `video_model` | `"seedance-2" \| "veo-3.1" \| "veo-3.1-fast" \| "veo-3.1-lite"` | No | `"seedance-2"` | Model choice for generated B-roll clips. | | `asset_types` | `("video")[]` | No | `["video"]` | Fixed to video generation in current implementation. | | `aspect_ratio` | `"auto" \| "16:9" \| "9:16"` | No | `"auto"` | Generated clip framing mode. | | `generate_audio` | `boolean` | No | `false` | Include audio in generated clips when supported by the selected model. | | `max_video_generations` | `number` | No | `20` effective | UI/metadata may allow higher values; backend hard cap is 20. | ### Parameter groups * **Coverage strategy:** `coverage_level`, `max_video_generations` * **Generation model:** `video_model`, `asset_types`, `aspect_ratio`, `generate_audio` * **Creative guidance:** `prompt` ### Scenario requirements * Keep `max_video_generations` within `1..20` for deterministic behavior. * Some model/aspect combinations are rejected by backend validators. ### Runtime notes * `coverage_level` controls target placement density and minimum gaps. * `max_video_generations` is capped at 20. ### Example ```json theme={null} { "coverage_level": "moderate", "video_model": "seedance-2", "aspect_ratio": "9:16", "generate_audio": false, "max_video_generations": 10, "prompt": "Add short cinematic cutaways that reinforce key points." } ``` # 4. AI Music Source: https://docs.mosaic.so/tiles/ai-music Generate custom AI-composed music that matches your video's mood, pacing, and style. Generate custom AI-composed music that matches your video's mood, pacing, and style. Useful for creators who want original, copyright-safe background music without hunting through libraries. ## How It Works The AI Music tile analyzes your video (if enabled) and generates a score that fits the visual context. You can leave it fully automatic or guide it with prompts and settings. ## Input and Settings ### Intelligent Video Analysis When enabled, Mosaic inspects your video to determine mood, intensity, genre, BPM, and timing. Use when: * You want music that "just fits" * You don't want to configure settings manually * The video carries clear emotional or pacing cues ### Prompt (Optional) Describe the mood/style you want. Examples: * *"Chill lofi background with soft drums"* * *"Epic orchestral build-up for cinematic travel footage"* * *"Corporate ambient for a product demo"* Use when: * You want creative direction * You don't want full auto * You want a specific genre or vibe ### Genre (Optional) Choose the category of music (e.g., EDM, Acoustic, Ambient, Cinematic, Corporate) Use cases: * *Ambient* → tutorial voiceovers * *Cinematic* → travel edits * *Corporate* → product demos * *EDM* → fast montage edits **Tip:** Leave on **Auto** for best scene-matching. ### Mood (Optional) Controls emotional tone (e.g., Calm, Energetic, Dramatic, Dark, Happy) Use when: * The scene's emotion is clear * You want specific storytelling vibes ### Intensity (Optional) Adjusts how "big" or "dense" the music feels. Levels: * **Low** → subtle background * **Medium** → balanced presence * **High** → impactful or dramatic ### BPM (Optional) Sets musical tempo (Beats Per Minute). Mapping: * **60–80 BPM** → slow, emotional * **90–120 BPM** → balanced * **130–160+ BPM** → energetic Use when your edit follows rhythmic cuts. ### Style (Optional) Further refines the musical aesthetic (e.g., Cinematic, Ambient, Retro, Corporate) Use cases: * "Ambient" for explainer voiceovers * "Cinematic" for travel or story edits * "Corporate" for product demos ### Timing (Optional) Allows partial coverage: * **Start Time (s)** * **End Time (s)** Use when: * Music should appear only in montage sections * You want intro music only * You want outro music only *** ## API Info * **Node ID:** `3b281fb9-9eb2-40f6-b05b-4b6f909a3da9` ### Node params | Param | Type | Required | Default | Notes | | -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ----------- | ------- | ------------------------------------------------------------------- | | `use_intelligent_analysis` | `boolean` | No | `true` | If true, music profile is inferred from source video. | | `prompt` | `string` | Conditional | `""` | Freeform direction. Strongly recommended when analysis is disabled. | | `genre` | `"Electronic" \| "Orchestral" \| "Ambient" \| "Rock" \| "Pop" \| "Jazz" \| "Classical" \| "Cinematic" \| "Synthwave" \| "Lo-Fi" \| "Trap" \| "House"` | No | unset | Optional style anchor. | | `mood` | `"Energetic" \| "Calm" \| "Dramatic" \| "Mysterious" \| "Uplifting" \| "Melancholic" \| "Tense" \| "Peaceful" \| "Epic" \| "Contemplative"` | No | unset | Emotional direction. | | `intensity` | `"Low" \| "Medium" \| "High" \| "Dynamic/Building"` | No | unset | Density/energy target. | | `style` | `string` | No | `""` | Additional style text, often combined with prompt. | | `bpm` | `number` | No | unset | Tempo. UI constrains 60-180; backend model accepts 0-200. | | `start_timestamp` | `number` (milliseconds) | No | unset | Music region start in ms. | | `end_timestamp` | `number` (milliseconds) | No | unset | Music region end in ms. | ### Parameter groups * **Analysis mode:** `use_intelligent_analysis` * **Creative guidance:** `prompt`, `genre`, `mood`, `intensity`, `style`, `bpm` * **Timing window:** `start_timestamp`, `end_timestamp` ### Scenario requirements * If `use_intelligent_analysis=false`, send at least one of `prompt`, `genre`, `mood`, `intensity`, or `style` for deterministic behavior. * If both `start_timestamp` and `end_timestamp` are set, `end_timestamp` must be greater than `start_timestamp`. ### Runtime notes * UI displays timing in seconds, then converts to milliseconds in node params. ### Example ```json theme={null} { "use_intelligent_analysis": false, "prompt": "Warm cinematic score with soft piano and subtle percussion", "genre": "Cinematic", "mood": "Uplifting", "intensity": "Medium", "bpm": 95, "start_timestamp": 0, "end_timestamp": 45000 } ``` # 3. AI Voiceover Source: https://docs.mosaic.so/tiles/ai-voiceover Generate a narrated voiceover for your video using AI. Generate a narrated voiceover for your video using AI. This is useful for explainer videos, product demos, documentary-style narration, storytelling, and any situation where spoken audio enhances context. ## How It Works The AI Voiceover tile takes a written script (or auto-generated script, depending on mode), synthesizes a natural-sounding voice, and aligns it with your video. You choose the voice style and script mode, and Mosaic handles the timing and audio mixing. ## Input and Settings ### Voice Select from a range of AI voices with different genders, tones, and delivery styles.\ You can preview the selected voice before committing. Use cases: * Professional narration (corporate, training, onboarding) * Energetic narration for social content * Calm educational explanations ### Script Mode Choose how the narration script is created. Modes include: * **Custom Script:** You provide the exact text * **(Other modes may include auto-generated, depending on provider)** If using **Custom Script**, the script field becomes required. Use cases: * Precise storytelling * Product walkthroughs * Brand-compliant messaging * Reading long-form copy without re-recording ### Custom Script Enter the exact text you want spoken in the voiceover. Best practices: * Keep sentences short for clarity * Use punctuation for natural pauses * Mention on-screen references ("as you can see here…") ### Time Script to Video Moments *(Optional)* When enabled, Mosaic attempts to align portions of the script with visual beats in the video. Benefits: * More dynamic pacing * Better alignment with scene changes * Reduces manual timing work *** ## API Info * **Node ID:** `9570c960-b32b-4e4d-8871-5775d886f7cb` ### Node params | Param | Type | Required | Default | Notes | | ---------------------- | ----------------------------- | ----------- | ------------------------ | -------------------------------------------------- | | `voice_provider` | `"elevenlabs"` | No | `"elevenlabs"` | Other providers are currently rejected by runtime. | | `voice_id` | `string` | No | `"UgBBYS2sOqTuMpoF3BR0"` | ElevenLabs voice ID (curated or custom). | | `script_mode` | `"custom_script" \| "prompt"` | Yes | `"custom_script"` | Controls which text source is used. | | `custom_script` | `string` | Conditional | `""` | Required when `script_mode="custom_script"`. | | `prompt` | `string` | Conditional | `""` | Required when `script_mode="prompt"`. | | `time_script_to_video` | `boolean` | No | `false` | Attempts beat/scene-aware timing. | ### Parameter groups * **Voice selection:** `voice_provider`, `voice_id` * **Script source mode:** `script_mode`, `custom_script`, `prompt` * **Timing behavior:** `time_script_to_video` ### Scenario requirements * `script_mode="custom_script"` -> non-empty `custom_script` required. * `script_mode="prompt"` -> non-empty `prompt` required. ### Runtime notes * UI filtering keeps only the active text field for the selected mode. * If `voice_provider` is omitted, runtime hard-defaults to ElevenLabs. ### Example ```json theme={null} { "voice_provider": "elevenlabs", "voice_id": "UgBBYS2sOqTuMpoF3BR0", "script_mode": "custom_script", "custom_script": "Today we're launching a faster way to review and publish your videos.", "time_script_to_video": true } ``` # 19. Audio Enhance Source: https://docs.mosaic.so/tiles/audio-enhance Automatically improve the clarity and quality of your video's audio using AI. Automatically improve the clarity and quality of your video's audio using AI. This helps make voices sound cleaner, reduces noise, and enhances overall listening experience—especially useful for talking-head videos, podcasts, and interviews. ## How It Works When applied, Audio Enhance processes your audio track to: * Reduce background noise * Improve speech clarity * Balance audio levels * Smooth harsh or muffled sections There are **no settings to configure**—it's designed to be a one-click enhancement. *** ## API Info * **Node ID:** `425274c9-7735-4cf2-b7cb-46c6a7f0066a` ### Node params | Param | Type | Required | Default | Notes | | ---------------------- | ---- | -------- | ------- | ------------------------------------------- | | *(none exposed in UI)* | - | - | - | Current tile UI is intentionally no-config. | ### Runtime notes * This tile currently has no user-configurable parameters. ### Example ```json theme={null} {} ``` # 6. Audio Generation Source: https://docs.mosaic.so/tiles/audio-generation Generate voiceovers or music from text prompts and optional voice references. Audio Generation creates new audio assets. Use **voiceover** mode for spoken narration and **music** mode for background tracks. ## How It Works For voiceover, provide a script and optionally attach a voice reference. For music, describe the mood, genre, instrumentation, and target length. The output can feed video-generation, AI Avatar, captions, or publishing workflows. ## API Usage Create an agent shell: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Launch voiceover", "visibility": "private" }' ``` Add an Audio Generation node: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/update" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "create_node", "node_type_id": "14687f30-5fd0-468f-8239-2784d83df95b", "params_used": { "mode": "voiceover", "model": "eleven_v3", "script": "Introducing the fastest way to turn ideas into publish-ready videos.", "use_upstream_voice_reference": false } } ] }' ``` Run the agent with no video inputs: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "callback_url": "https://your-webhook.com/mosaic" }' ``` ## API Info * **Node ID:** `14687f30-5fd0-468f-8239-2784d83df95b` ### Node params | Param | Type | Required | Default | Notes | | ------------------------------ | ---------------------------------------------------------- | ----------- | --------------- | ------------------------------------------------------- | | `mode` | `"voiceover" \| "music"` | No | `"voiceover"` | Audio generation mode. | | `model` | `"eleven_v3" \| "music"` | No | `"eleven_v3"` | Audio model for the selected mode. | | `script` | `string` | Conditional | `""` | Required for voiceover mode. | | `voice_id` | `string` | No | curated default | Voice ID when no upstream voice reference is used. | | `use_upstream_voice_reference` | `boolean` | No | `true` | Use selected upstream audio/video as a voice reference. | | `selected_context` | `{audio:string[],videos:string[],voice_reference?:string}` | No | empty lists | Attached references. | | `music_prompt` | `string` | Conditional | `""` | Required for music mode. | | `music_length_ms` | `number` | No | `30000` | Music duration, 5-300 seconds. | ### Voiceover example ```json theme={null} { "mode": "voiceover", "model": "eleven_v3", "script": "This is the voiceover text.", "use_upstream_voice_reference": false } ``` ### Music example ```json theme={null} { "mode": "music", "model": "music", "music_prompt": "Warm upbeat electronic background music for a product launch", "music_length_ms": 45000 } ``` # 21. Captions Source: https://docs.mosaic.so/tiles/captions Add dynamic, stylized captions that match your video's tone and improve accessibility. Add dynamic, stylized captions that match your video's tone, improve retention, and boost accessibility. Ideal for social platforms where *sound-off viewing* is common (TikTok, Reels, Shorts, LinkedIn). ## How It Works The Captions tile listens to your video audio, transcribes speech, and overlays timed captions. You control how they look — from fonts and stroke to placement and coloring. Captions are auto-timed to speech and update in real-time based on your styling choices. Clean captions ## Input and Settings ### Caption Style Controls how captions are visually rendered. API `caption_style` values: * **`colored`** → Highlights key words with your `highlight_color` * **`scaling`** → Emphasis via animated word scaling * **`karaoke`** → Progressive karaoke-style emphasis `stroke_color` and `stroke_enabled` are controlled separately from `caption_style`. Great for: * Retention editing * Educational clips * Talking-head explanatory content ### Colors You can customize three visual layers: **Base Color**\ Default text color (e.g., `#FFFFFF` for white) **Highlight Color**\ Used to emphasize specific words — increases engagement & readability **Stroke Color**\ Outline around text for contrast on busy footage ### Font Options Set the typography style to match your brand. Controls include: * **Font Family** (e.g., Montserrat) * **Font Weight** (e.g., 400 / 700) * **Exact Size** (optional pixel value) Use cases: * Bold fonts for TikTok/Shorts * Light/fonts for cinematic edits Supported local brand fonts include all Sun fonts (`The Sun Heavy Condensed`, `The Sun Heavy Narrow`, `The Sun Bold`, `The Sun Bold Italic`, `The Sun Medium`, `The Sun Medium Italic`, `The Sun Regular`, `The Sun Italic`) and `Knockout`. These render from bundled font files rather than Google Fonts. By default, caption size is automatic and scales to the composition. Set `caption_font_size_px` only when you need an exact pixel size; send `null` to clear an existing exact-size setting. ### Drop Shadow Enable a drop shadow when captions need extra separation from busy footage. Controls: * `shadow_enabled` * `shadow_color` * `shadow_blur` * `shadow_opacity` ### Vertical Position Adjust how high/low captions sit in the frame (via percentage slider). Examples: * `90%` → Just above bottom edge (common for shorts) * `50%` → Centered (cinematic) * `20%` → Top aligned (when lower third is busy) ### Words per Caption Controls pacing and readability. Two sliders: * **Minimum words** * **Maximum words** Examples: * `Min 1 / Max 3` → Fast TikTok pacing * `Min 3 / Max 7` → YouTube educational pacing *** ## API Info * **Node ID:** `cdccb204-168e-4aec-aa72-480b11e74324` ### Node params | Param | Type | Required | Default | Notes | | --------------------------- | ------------------------------------- | -------- | -------------- | ---------------------------------------------------------------------------------------------------- | | `caption_style` | `"colored" \| "scaling" \| "karaoke"` | No | `"colored"` | Visual style preset. | | `base_color` | `string` (hex) | No | `"#F8FAFC"` | Primary text color. | | `highlight_color` | `string` (hex) | No | `"#A78BCA"` | Highlight/accent color. | | `stroke_color` | `string` (hex) | No | `"#0B0B0B"` | Stroke/outline color. | | `stroke_enabled` | `boolean` | No | `true` | Toggle the text outline on or off. | | `caption_font` | `string` | No | `"Montserrat"` | Font family. | | `caption_font_weight` | `string` | No | `"700"` | Font weight as string token. | | `caption_font_size_px` | `number \| null` | No | omitted | Exact caption font size in pixels. Send `null` to clear exact sizing and return to automatic sizing. | | `shadow_enabled` | `boolean` | No | `false` | Toggle the drop shadow. | | `shadow_color` | `string` (hex) | No | `"#000000"` | Drop shadow color. | | `shadow_blur` | `number` | No | `10` | Drop shadow blur radius in pixels (`0-40`). | | `shadow_opacity` | `number` | No | `0.5` | Drop shadow opacity (`0-1`). | | `caption_vertical_position` | `number` (percent) | No | `88` | Vertical caption placement (`10-90`). | | `caption_min_words` | `number` | No | `2` | Minimum words grouped per caption chunk (`1-8`). | | `caption_max_words` | `number` | No | `4` | Maximum words grouped per caption chunk (`1-8`). | ### Parameter groups * **Render style:** `caption_style`, `base_color`, `highlight_color`, `stroke_color`, `stroke_enabled`, `shadow_enabled`, `shadow_color`, `shadow_blur`, `shadow_opacity` * **Typography:** `caption_font`, `caption_font_weight`, `caption_font_size_px` * **Layout & pacing:** `caption_vertical_position`, `caption_min_words`, `caption_max_words` ### Scenario requirements * Keep `caption_min_words <= caption_max_words`. * Use valid hex color strings for color fields. * `caption_font_weight` must be sent as a **string** (for example `"700"`), not a number. * Omit `caption_font_size_px` to preserve the current sizing mode; set it for exact pixel sizing; send `null` to clear exact sizing and return to automatic sizing. ### Runtime notes * For deterministic output, set style, typography, and pacing fields explicitly. * For API overrides, pass these fields via `update_params[agent_node_id]`. ### Example ```json theme={null} { "caption_style": "colored", "base_color": "#FFFFFF", "highlight_color": "#EC81EE", "caption_font": "Montserrat", "caption_font_weight": "700", "caption_font_size_px": 42, "stroke_enabled": true, "shadow_enabled": true, "shadow_color": "#000000", "shadow_blur": 10, "shadow_opacity": 0.5, "caption_vertical_position": 88, "caption_min_words": 2, "caption_max_words": 4 } ``` # 6. Cinematic Captions Source: https://docs.mosaic.so/tiles/cinematic-captions Add stylized captions designed to look cinematic or 'YouTube documentary' style. Adds stylized captions designed to look cinematic or "YouTube documentary" style. Cc **Font Selection:** Choose fonts for your captions. Primary font is used for most words, secondary font adds visual variety for emphasis. **Color Override:** Override the AI-selected text colors with a fixed color for all captions. **Let AI choose colours:** Mosaic AI will choose colours based off the colours in the video. Good for: * Talking head videos * Interviews * Short-form content *** ## API Info * **Node ID:** `dfa94b02-6a18-4922-9613-636bd202d69d` ### Node params | Param | Type | Required | Default | Notes | | ------------------- | ------------------------------------------------------------------------------------------------------------------------------ | -------- | -------------- | --------------------------------------------------------------------- | | `font1` | `string` | No | `"Montserrat"` | Primary font family. | | `font2` | `string \| null` | No | `null` | Secondary/accent font family. Set to `null`/omit to use only `font1`. | | `color_override` | `string \| null` (hex) | No | `null` | If set, forces this color onto generated caption spec. | | `text_bg_enabled` | `boolean` | No | `false` | Enable text background box. | | `text_bg_color` | `string` (hex) | No | `"#000000"` | Text background color. | | `text_bg_opacity` | `number` | No | `0.6` | Text background opacity (`0.1-1.0`). | | `text_bg_roundness` | `number` | No | `6` | Text background corner radius (`0-20`). | | `animation_style` | `"pop" \| "slide" \| "fade" \| "bounce" \| "typewriter" \| "wave" \| "cinematic" \| "highlight"` | No | `"pop"` | Caption animation preset. | | `stroke_enabled` | `boolean` | No | `true` | Enable stroke on caption text. | | `stroke_color` | `string` (hex) | No | `"#000000"` | Stroke color. | | `stroke_width` | `number` | No | `2` | Stroke width (`0-8`). | | `shadow_enabled` | `boolean` | No | `false` | Enable text shadow. | | `shadow_blur` | `number` | No | `10` | Shadow blur radius (`0-40`). | | `shadow_color` | `string` (hex) | No | `"#000000"` | Shadow color. | | `shadow_opacity` | `number` | No | `0.5` | Shadow opacity (`0.1-1.0`). | | `uniform_word_size` | `boolean` | No | `false` | Force consistent word sizing. | | `single_line` | `boolean` | No | `false` | Force single-line captions. | | `caption_position` | `"auto" \| "top-left" \| "top" \| "top-right" \| "left" \| "center" \| "right" \| "bottom-left" \| "bottom" \| "bottom-right"` | No | `"auto"` | Caption placement. | ### Parameter groups * **Font pairing:** `font1`, `font2` * **Color policy:** `color_override`, `text_bg_*` * **Animation & layout:** `animation_style`, `caption_position`, `single_line`, `uniform_word_size` * **Edge styling:** `stroke_*`, `shadow_*` ### Runtime notes * If `color_override` is null, AI style generation chooses colors from scene analysis. * Runtime validates/fetches fonts from remotion template; invalid font names can fail render. * `font1`/`font2` should be valid Google Font family names. * For API overrides, pass these via `update_params[agent_node_id]`. ### Example ```json theme={null} { "font1": "Montserrat", "font2": "Besley", "color_override": null, "animation_style": "cinematic", "caption_position": "bottom", "text_bg_enabled": true, "text_bg_color": "#000000", "text_bg_opacity": 0.55, "stroke_enabled": true, "stroke_color": "#000000", "stroke_width": 2 } ``` # 9. Clips Source: https://docs.mosaic.so/tiles/clips Automatically extract short, standalone clips from a longer video for social platforms. Automatically extract short, standalone clips from a longer video. These clips are moments that can be shared directly on social platforms or used in editing workflows. This tile is ideal for repurposing podcasts, interviews, webinars, or speaking content into short-form highlights. ## How It Works Mosaic scans your video and finds segments that contain interesting, insightful, funny, emotional, or impactful moments. You can: * **Let Mosaic decide** what's interesting, or * **Guide it** using your own prompt (optional) Each clip becomes an individual video you can send to other tiles (like Reframe or Captions) or export directly. Clips ## Input Options ### 1. Prompt (Optional) > *"Write what kind of video you want to create"* Use this if you want specific types of clips.\ Examples: * "Educational tips and insights" * "Funny reactions" * "Motivational quotes" * "Controversial takes or debates" * "Moments explaining frameworks or concepts" If you leave it **empty**, Mosaic will return a variety of interesting moments by default. ### 2. Number of Clips (max) Set how many clips you want.\ Example: `10` → returns up to 10 clips. If unsure, **set a number higher than you need** and filter later. ### 3. Target Duration (seconds) How long each clip should roughly be. Examples: * `15` for TikTok/Reels/Shorts * `30–60` for YouTube or Twitter clips This is a target, not an exact enforcement — clips may vary slightly for natural context. ## Best Use Cases Use the Clips tile when you want to quickly generate short videos from long footage, such as: * Podcasts → TikTok/Reels/Shorts * Interviews → Highlight moments * Webinars → Key insights * Reaction videos → Funny parts * Commentary streams → Shareable segments *** ## API Info * **Node ID:** `bcc5cb04-76b7-48e9-a344-0e8a29c19be0` ### Node params | Param | Type | Required | Default | Notes | | ----------------- | ------------------ | -------- | ------- | -------------------------------------------------------------------------------------- | | `prompt` | `string` | No | `""` | Optional selection guidance for clip scoring/ranking. Empty = all interesting moments. | | `num_clips` | `number` | No | unset | Requested number of clips (integer, 1–20). | | `target_duration` | `number` (seconds) | No | unset | Preferred duration per clip (seconds, 1–300). | ### Parameter groups * **Selection guidance:** `prompt` * **Output sizing:** `num_clips`, `target_duration` ### Runtime notes * If both `num_clips` and `target_duration` are omitted, backend picks clips using default heuristics. * If source is shorter than requested `target_duration`, backend may return pass-through/single output behavior. * If `num_clips * target_duration` exceeds source runtime, backend reduces effective clipping strategy. ### Example ```json theme={null} { "prompt": "Extract punchy educational tips with clear hooks", "num_clips": 8, "target_duration": 30 } ``` # 17. Color Correction Source: https://docs.mosaic.so/tiles/color-correction Apply color grading to your video to improve mood, consistency, or cinematic style. Apply color grading to your video to improve mood, consistency, or cinematic style. This tile lets you use preset LUTs, custom LUTs, or match the look of a reference image. ## How It Works Color Correction adjusts the color profile of your footage. You choose one grading method (preset, reference image, or custom LUT), and Mosaic applies that look across your video. Add colour grade to your footage ## Input & Settings ### 1. Preset LUT Select a ready-made look such as: * Golden Hour * Filmic * Vibrant * Cool Tones * Neutral Clean **Best for:**\ Fast results when you don't want to think about color science. ### 2. Reference Image Upload an image whose color style you want to match. **Example:**\ Upload a still from a movie → Mosaic matches that cinematic look. **Best for:**\ Brand aesthetics or mood matching. ### 3. Custom LUT (.cube) Upload your own **.cube LUT** file exported from: * DaVinci Resolve * Premiere Pro * Final Cut * Photoshop * Other grading software **Best for:**\ Colorists or agencies with existing grading pipelines. *** ## API Info * **Node ID:** `8254e1f8-dfea-42f9-90d8-aa91ec859bec` ### Node params | Param | Type | Required | Default | Notes | | --------------------- | --------------------------------------------------- | ----------- | -------------------- | -------------------------------------------------------------------- | | `mode` | `"reference_image" \| "preset_lut" \| "custom_lut"` | Yes | UI: `"preset_lut"` | Determines which source drives grading. | | `reference_image_id` | `string` (UUID) | Conditional | unset | Required when `mode="reference_image"`. | | `preset_lut` | `string` | Conditional | `"golden_hour"` (UI) | Required when `mode="preset_lut"`. | | `custom_lut_id` | `string` (UUID) | Conditional | unset | Required when `mode="custom_lut"`; references a workspace LUT asset. | | `custom_lut_filename` | `string` | No | unset | Display/traceability metadata for uploaded LUT. | | `strength` | `number` | No | `35` | Blend strength. UI slider: 10-40. Runtime accepts 0-40. | ### Parameter groups * **Mode selector:** `mode` * **Reference-image mode:** `reference_image_id`, `strength` * **Preset LUT mode:** `preset_lut` * **Custom LUT mode:** `custom_lut_id`, `custom_lut_filename` ### Supported `preset_lut` values * `warm_amber` * `sunset_boulevard` * `royal_blue` * `retro_forest` * `peach_melba` * `pastel_mint` * `lavender_dust` * `golden_hour` * `butter_cream` * `blueberry_dream` ### Scenario requirements * `mode="reference_image"` -> `reference_image_id` required. * `mode="preset_lut"` -> `preset_lut` required. * `mode="custom_lut"` -> `custom_lut_id` required (workspace LUT asset ID). ### Runtime notes * UI persists only one active grading source; changing `mode` clears conflicting fields. ### Example ```json theme={null} { "mode": "preset_lut", "preset_lut": "golden_hour", "strength": 35 } ``` # 23. Destination Source: https://docs.mosaic.so/tiles/destination Export, schedule, or publish your video directly to social platforms from Mosaic. The Destination tile lets you export, schedule, or publish your video directly to social platforms from Mosaic — no need to download and re-upload manually. ## How It Works Add the Destination tile at the end of your workflow. When it runs, Mosaic formats your video for the target platform(s), optionally generates social captions, and publishes or exports. Destination UI ## Input & Options ### Publishing Mode | Mode | What it does | | ---------------------------- | ------------------------------------------------- | | **Review before publishing** | Preview and approve posts before they go live | | **Publish immediately** | Posts go out as soon as they're ready | | **Export only** | Skip platform publishing — just download the file | ### Publishing Platforms Connect and publish to: * X (Twitter) * LinkedIn * Instagram * Facebook * TikTok * YouTube Click **Manage Social Media Integrations** to connect, disconnect, or refresh your accounts. You only need to do this once per account. ### AI Captions for Posts (Optional) Tell the AI how to write your social media post text. Examples: * "Make it witty and add relevant hashtags" * "Write for LinkedIn with a strong hook and CTA" * "Write for TikTok using casual language and emojis" Leave empty for a neutral auto-generated caption. Destination works best at the end of a workflow chain like: [Clips](/tiles/clips) → [Reframe](/tiles/reframe) → [Captions](/tiles/captions) → **Destination** *** ## API Info * **Node ID:** `e840b66c-488c-4247-9e46-756b914fc287` ### Node params | Param | Type | Required | Default | Notes | | ----------------- | ----------------------------------------------------------------------------- | -------- | ---------- | ------------------------------------------------ | | `platforms` | `("x" \| "linkedin" \| "instagram" \| "facebook" \| "tiktok" \| "youtube")[]` | Yes | `[]` | At least one platform required. | | `approval_mode` | `"manual" \| "auto"` | No | `"manual"` | Manual review queue vs immediate publishing. | | `ai_instructions` | `string` | No | `""` | Prompt for social caption generation style/tone. | ### Parameter groups * **Destination routing (required):** `platforms` * **Publish policy:** `approval_mode` * **Caption generation guidance:** `ai_instructions` ### Scenario requirements * `platforms` must be non-empty. ### Runtime notes * Backend resolves caption instruction text from multiple keys (`ai_instructions`, `ai_prompt`, `instructions`, `prompt`) for backward compatibility. * Only connected social accounts are selectable in UI, but API clients can still submit valid platform IDs directly. ### Example ```json theme={null} { "platforms": ["linkedin", "youtube"], "approval_mode": "manual", "ai_instructions": "Write concise posts with a hook and one CTA." } ``` # 4.1 How Tiles Work Source: https://docs.mosaic.so/tiles/how-tiles-work Understanding the building blocks of Mosaic * Double click on the canvas to see the tile option * The **first tile** is usually a **Video Input** tile * You then connect **creation tiles** or **action tiles** to it * Mosaic performs the actions in order * Outputs get passed along the chain Tiles make editing understandable even for first-time users. ## Mental Model for Tiles Understanding the three types of tiles is key to getting the most out of Mosaic: * **Input Tiles** bring media in — they are the starting point of every workflow (e.g. Video Input, YouTube Trigger) * **Creation Tiles** generate new media — they produce entirely new content like AI-generated B-roll, avatars, voiceovers, or music * **Action Tiles** modify media — they transform existing media by adding captions, reframing, trimming silence, color correcting, etc. Every workflow follows this flow: **Input → Creation / Action → Output**. Once this clicks, building any workflow becomes intuitive. *** ## Explore Tile Types Bring your media into Mosaic Generate new media with AI Transform and refine your content # 7. Image Generation Source: https://docs.mosaic.so/tiles/image-generation Generate images from prompts and optional image context. Image Generation creates still images from text prompts. Use it for thumbnails, reference frames, product concepts, style exploration, or as input context for Video Generation. ## How It Works Write a prompt, choose an output size and quality, and optionally attach image references. Mosaic stores the generated image as a workspace asset so it can be reused by downstream tiles or API runs. ## API Usage Create an agent shell: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Hero frame generator", "visibility": "private" }' ``` Add an Image Generation node: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/update" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "create_node", "node_type_id": "18b998a0-2ea7-4676-a5d3-3ae6c8ac0b72", "params_used": { "prompt": "A premium studio product photo of a chrome espresso machine on a marble counter", "model": "gpt-image-2", "image_size": "landscape_4_3", "quality": "high", "output_format": "png" } } ] }' ``` Run the agent with no video inputs: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "callback_url": "https://your-webhook.com/mosaic" }' ``` ## API Info * **Node ID:** `18b998a0-2ea7-4676-a5d3-3ae6c8ac0b72` ### Node params | Param | Type | Required | Default | Notes | | ------------------ | --------------------------------------------------------------------------------------------------------------------------- | ----------- | ----------------- | ----------------------------------------------------------------- | | `prompt` | `string` | Yes | `""` | Image prompt. | | `model` | `"gpt-image-2"` | No | `"gpt-image-2"` | Image model. | | `image_size` | `"square_hd" \| "square" \| "portrait_4_3" \| "portrait_16_9" \| "landscape_4_3" \| "landscape_16_9" \| "auto" \| "custom"` | No | `"landscape_4_3"` | Output size preset. | | `custom_width` | `number` | Conditional | `1280` | Required when `image_size` is `custom`; multiple of 16, 256-3840. | | `custom_height` | `number` | Conditional | `960` | Required when `image_size` is `custom`; multiple of 16, 256-3840. | | `quality` | `"low" \| "medium" \| "high"` | No | `"high"` | Generation quality. | | `output_format` | `"jpeg" \| "png" \| "webp"` | No | `"png"` | Generated image format. | | `selected_context` | `{images:string[]}` | No | empty list | Uploaded image references. | ### Example ```json theme={null} { "prompt": "A clean ecommerce hero image of white running shoes on blue acrylic", "model": "gpt-image-2", "image_size": "landscape_4_3", "quality": "high", "output_format": "png" } ``` # 4.2 Input Tiles Source: https://docs.mosaic.so/tiles/input-tiles Tiles for importing your footage Input tiles are the starting point of every Mosaic workflow. Upload the footage you want to work with, from your desired input source. Input Tiles Overview *** ## Video Input Drag and drop or browse to upload your footage directly. You can also paste a link to import videos from YouTube and other sources. | | Details | | ----------------- | ---------------------------------------- | | **Max file size** | 20 GB | | **Max duration** | 300 minutes | | **Sources** | Local upload, Paste Link (YouTube, etc.) | *** ## YouTube Trigger Watches a YouTube channel and automatically triggers your workflow when a new video is published. Add a channel by handle (e.g. `@mkbhd`) or URL, and optionally set a **Callback URL** to receive webhook notifications. Best for automating clipping from a creator or channel. *** ## Google Drive Trigger Connect a Google Drive folder and Mosaic will monitor it for new files. When a new video lands in the folder, your workflow kicks off automatically. If you have duplicate folder names, use **Browse...** to pick the exact folder. *** ## AWS S3 Trigger Connect an AWS S3 bucket to automatically trigger workflows when new files are uploaded. Ideal for teams with cloud-based media pipelines. *** Input Tiles UI Google Drive and AWS S3 triggers are available on certain plans. [Manage your subscription](/how-to/manage-subscription) to unlock automated triggers. # 13. Intro Source: https://docs.mosaic.so/tiles/intro Add a short intro to the beginning of your video for brand consistency and professionalism. Add a short intro to the beginning of your video. This helps create brand consistency, improve viewer retention, and make your videos feel more professional. ## How It Works The Intro tile inserts an intro clip **before** your main video. You can choose between Mosaic's built-in intros or upload your own. ## Input & Settings ### Intro Source Two choices: 1. **Use Mosaic Intro** * Mosaic adds a simple, pre-built intro for you. 2. **Use Custom Intro** * You upload your own intro clip (e.g., brand bumper, logo reveal, short animation). Choose **Custom** if you already have branded assets. *** ## API Info * **Node ID:** `ef3f8d59-26be-4ea0-b655-9a08b10577cc` ### Node params | Param | Type | Required | Default | Notes | | ----------------------- | ---------------------- | ----------- | ---------- | ----------------------------------------------- | | `use_custom_intro` | `"mosaic" \| "custom"` | Yes | `"mosaic"` | Select built-in intro vs uploaded custom intro. | | `custom_intro_video_id` | `string` (UUID) | Conditional | unset | Required when `use_custom_intro="custom"`. | ### Scenario requirements * If `use_custom_intro="custom"`, provide `custom_intro_video_id`. ### Runtime notes * UI currently uploads and stores custom intros as video asset IDs (`custom_intro_video_id`) and limits uploads to MP4. ### Example ```json theme={null} { "use_custom_intro": "custom", "custom_intro_video_id": "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee" } ``` # Mimir Export Source: https://docs.mosaic.so/tiles/mimir-export Export workflow renders to Mimir and optionally link them to an original Mimir asset. The Mimir Export tile uploads rendered workflow outputs into the Mimir connection configured for the workflow workspace. Use it at the end of a workflow after a tile that produces a render, such as Clips, Reframe, Captions, or a final processing step. ## Settings ### Destination Set `mimir_folder_id` to the destination Mimir folder UUID or folder path. ### File Naming Leave `file_name` blank to use the default output names: * `render.mp4` for a single output * `render.mp4`, `render-1.mp4`, `render-2.mp4`, etc. for multiple outputs Set `file_name` to override the base filename. For multiple outputs, Mosaic keeps the first filename as provided and adds `-1`, `-2`, etc. to later files. ### Link To Mimir Asset Enable `link_to_mimir_asset` when the exported render should be linked to an original Mimir asset. Mosaic sends the selected original item id as Mimir `parentItemIds` when creating the exported item. Provide `mimir_parent_item_id` explicitly, or omit it when the upstream source came from Mimir and Mosaic can infer the original item id from source metadata. ## API Info * **Node ID:** `5b2e8a91-8c36-4d3e-93f5-8a36ad4e9e77` ### Node params | Param | Type | Required | Default | Notes | | ----------------------- | ---------- | -------- | ------- | ----------------------------------------------------------- | | `mimir_folder_id` | `string` | Yes | `""` | Mimir destination folder UUID or folder path. | | `file_name` | `string` | No | `""` | Optional filename override. Blank uses `render.mp4` naming. | | `link_to_mimir_asset` | `boolean` | No | `false` | When true, send `parentItemIds` on Mimir item creation. | | `mimir_parent_item_id` | `string` | No | `""` | Original Mimir item id to send as `parentItemIds[0]`. | | `mimir_parent_item_ids` | `string[]` | No | `[]` | Advanced API option for multiple parent item ids. | ### Example ```json theme={null} { "mimir_folder_id": "8c5d9360-f7a6-4d28-8a63-1c6c5fdc1791", "file_name": "render.mp4", "link_to_mimir_asset": true, "mimir_parent_item_id": "OG_MIMIR_ASSET_ID" } ``` When `link_to_mimir_asset` is true, Mosaic creates the Mimir item with: ```json theme={null} { "parentItemIds": ["OG_MIMIR_ASSET_ID"] } ``` # 18. Mirror Source: https://docs.mosaic.so/tiles/mirror Flip your video horizontally or vertically for corrections or creative effects. Flip your video horizontally or vertically. This is useful for correcting mirrored webcam footage, achieving creative effects, or adjusting composition for platform layouts. ## How It Works The Mirror tile applies a flip transformation to your entire video. You choose whether to flip horizontally, vertically, or both. Flip your footage vertically or horizontally ## Input and Settings ### Horizontal Flip Mirrors the video **left ↔ right**. Use cases: * Fix mirrored webcam footage * Correct orientation when text/screen is reversed * Creative reflections or symmetrical effects ### Vertical Flip Mirrors the video **top ↕ bottom**. Use cases: * Creative effects * Stylized edits * Inverted scene looks *** ## API Info * **Node ID:** `71156aca-3e21-45b0-8960-099dba07c83a` ### Node params | Param | Type | Required | Default | Notes | | ----------------- | --------- | -------- | ------- | ------------------------------------- | | `horizontal_flip` | `boolean` | No | `false` | Mirrors frame on X-axis (left-right). | | `vertical_flip` | `boolean` | No | `false` | Mirrors frame on Y-axis (top-bottom). | ### Runtime notes * Both flags can be enabled simultaneously. * Tile is deterministic and one-to-one (single input render -> single output render). ### Example ```json theme={null} { "horizontal_flip": true, "vertical_flip": false } ``` # 10. Montage Source: https://docs.mosaic.so/tiles/montage Automatically create a montage by stitching together multiple videos or clips with rhythm, pacing, and style. Automatically create a montage by stitching together multiple videos or clips with rhythm, pacing, and style. This is ideal for fast recap videos, highlight reels, travel edits, product showcases, or hype sequences. Montage helps you turn raw media into something visually exciting without manually aligning clips or matching beats. ## How It Works The Montage tile takes one or more input clips and arranges them into a cohesive sequence based on your creative style prompt. It can optionally sync cuts to music, making it feel more cinematic or energetic. ## Input & Options ### 1. Style Prompt (Required) > *"How do you want the montage to look?"* Describe the visual pacing and tone.\ Good examples: * "Energetic montage with quick cuts" * "Slow emotional montage with long shots" * "TikTok-style fast-paced montage with hard cuts" * "Cinematic travel montage with smooth transitions" * "Sports highlight reel with snappy edits" This tells Mosaic *how* to arrange your clips. ### 2. Audio Track (Optional) You can **upload your own music** to control pacing. Why use audio? * Helps drive emotion * Syncs cuts to beat (if BPM is provided) * Gives more cinematic output If no audio is uploaded: * Mosaic will time clips based on visual pacing only. ### 3. Desired BPM (Optional) If you provide music, you can enter a **beats per minute** value. Examples: * `60–90` → slow, emotional * `100–130` → upbeat, pop * `130–160+` → energetic, hype, sports Mosaic uses BPM to: * Decide cut frequency * Match energy level * Improve beat synchronization If unsure, you can leave it as-is or remove it entirely. *** ## API Info * **Node ID:** `627f0700-7417-414d-9793-58140a374e8f` ### Node params | Param | Type | Required | Default | Notes | | --------------- | --------------- | -------- | ------------------------------------- | -------------------------------------------------------------- | | `prompt` | `string` | Yes | `"Energetic montage with quick cuts"` | Creative direction for sequencing/cut style. | | `bpm` | `number` | No | `140` | Target beat pacing; UI range is 60-500. | | `audio_file_id` | `string` (UUID) | No | unset | User-provided audio track; takes precedence over stock lookup. | ### Parameter groups * **Creative intent (required):** `prompt` * **Timing controls:** `bpm`, `audio_file_id` ### Runtime notes * If `audio_file_id` is present, backend tries to fetch and use that exact audio file. * If no `audio_file_id` is present, backend can select stock music based on `bpm`. * UI default for `bpm` is typically 140 via node defaults. ### Example ```json theme={null} { "prompt": "Fast-paced sports recap with punchy cuts", "bpm": 140, "audio_file_id": "bbbbbbbb-cccc-dddd-eeee-ffffffffffff" } ``` # 7. Motion Graphics Source: https://docs.mosaic.so/tiles/motion-graphics Add motion graphics and animations to your video to emphasize information, highlight talking points, or create engaging visual storytelling. Add motion graphics and animations to your video to emphasize information, highlight talking points, or create a more engaging visual storytelling style. Motion graphics are AI-generated based on your instructions. They can appear as overlays during speech, fullscreen explainer slides, or contextual inserts depending on how you configure the tile. ## How It Works The Motion Graphics tile takes in your video and a **prompt describing the type of motion graphics you want**, then generates visual elements that match your style and intent. Mogr ## Input Fields & Controls ### Style Prompt (Required) Describe the **visual style** and **function** of the graphics. Examples: * "Cinematic Vox-style graphics that explain the talking points" * "Minimal tech UI diagrams with arrows and labels" * "Playful YouTube-style pop-up text for comedic emphasis" * "Infographic overlays using bold colors and icons" ### Full Screen Toggle (Optional) When **enabled**, motion graphics appear as fullscreen slides — the speaker video may cut away entirely. Best for explainers, charts, and data slides. When **disabled** (default), graphics appear as overlays on top of your video. Ideal for speaking-head, narrative, or commentary videos. ### Reference Links (Optional) Comma-separated URLs the AI will research for factual content (e.g., product pages, Wikipedia articles, docs). ### Style Reference Video (Optional) Paste a **reference video URL** (typically YouTube) to extract style direction. Mosaic uses this for typography, color, transitions, and layout guidance (`style_video_url`). ### Frequency (Optional) Choose how often motion graphics should appear: * **Auto** lets Mosaic choose based on the content * **Low** targets about 3 graphics per minute * **Medium** targets about 5 graphics per minute * **High** targets about 10 graphics per minute ### Style Suggestions (Quick Buttons) Common presets like **VOX Style** and **Ali Abdaal Style** that instantly fill the prompt for you. For longer videos (over \~1–2 minutes), this tile may time out. We're actively working on removing this limitation. For now, it works best with **short clips, intros, and explainers**. ## Best Use Cases Motion Graphics works great for explainers, educational content, product breakdowns, tutorials, commentary videos, and infographic storytelling. It boosts retention when explaining complex topics. * Provide **functional intent** (e.g. "help explain talking points", "highlight key stats") * Provide **style** + **context** instead of just style alone * Use reference videos for best results * Enable fullscreen mode for heavy infographic content * Recommended prompt structure: `[Style] + [Function] + [Tone] + [Timeline Behavior]` **Explainer style:** > "Clean vector infographic overlays with labels and arrows, educational tone." **YouTube short:** > "Fast-paced kinetic text and icons, playful tone, highlight key punchlines." **Product tutorial:** > "UI-style overlays showing click targets and step-by-step labels, minimal style." **Vox-style:** > "Vox-style infographic overlays that highlight statistics during key sentences, clean modern typography, minimal color palette, educational tone." Motion Graphics pairs well with [Rough Cut](/tiles/rough-cut) (condense first, then add graphics), [Reframe](/tiles/reframe) (adapt for different platforms), and [Captions](/tiles/captions) (add subtitles on top). *** ## API Info * **Node ID:** `19144346-8714-4a02-b19c-32c18bd1ad13` ### Node params | Param | Type | Required | Default | Notes | | ------------------------------------ | ------------------------------ | -------- | -------- | ------------------------------------------------------------------------------- | | `prompt` | `string` | Yes | `""` | Primary generation instruction. | | `model_tier` | `"fast" \| "pro"` | No | `"fast"` | Controls model quality/speed profile. | | `reference_links` | `string \| string[]` | No | `""` | URLs used as research context. Runtime normalizes comma/newline/array forms. | | `style_video_url` | `string` | No | `""` | Reference video URL (UI expects YouTube URL format). | | `frequency_per_minute` | `"auto" \| "3" \| "5" \| "10"` | No | `"auto"` | Motion graphics frequency: auto, low (3/min), medium (5/min), or high (10/min). | | `only_generate_full_screen_graphics` | `boolean` | No | `false` | Fullscreen-only graphics mode. | ### Parameter groups * **Core intent (required):** `prompt` * **Generation quality:** `model_tier` * **Research/style references:** `reference_links`, `style_video_url` * **Layout behavior:** `frequency_per_minute`, `only_generate_full_screen_graphics` ### Runtime notes * Handler resolves prompt from multiple fields (`node params.prompt`, `node params.user_prompt`, `agent_node.user_prompt`, `agent_node.prompt`). * `reference_links` normalization accepts strings, arrays, or mixed delimiters. * `style_video_url` is the strongest style signal. Set it when you need consistent visual style matching. * `reference_links` provide factual/research context and are not a direct replacement for style references. * Use the exact API key `only_generate_full_screen_graphics` for fullscreen mode. ### Example ```json theme={null} { "prompt": "Create clean infographic overlays that emphasize key talking points.", "model_tier": "pro", "reference_links": [ "https://example.com/research/article-1", "https://example.com/research/article-2" ], "style_video_url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ", "frequency_per_minute": "5", "only_generate_full_screen_graphics": false } ``` # 14. Outro Source: https://docs.mosaic.so/tiles/outro Add an outro to the end of your video to wrap up content and encourage viewer actions. Add an outro to the end of your video. Outros help wrap up content cleanly and can encourage viewers to take actions like subscribing, following, or watching the next clip. ## How It Works The Outro tile inserts an outro clip **after** your main content. You can choose between Mosaic's pre-made outros or upload your own branded outro. ## Input & Settings ### Outro Source Two choices: 1. **Use Mosaic Outro** * Adds a simple, generic outro for quick exports. 2. **Use Custom Outro** * Lets you upload your own outro, such as: * End cards * Social handles * Subscribe prompts * Brand bumpers Use **Custom** if you have branding assets. *** ## API Info * **Node ID:** `cf517f33-3f78-4d55-88c2-a7d8478f8ef9` ### Node params | Param | Type | Required | Default | Notes | | ----------------------- | ---------------------- | ----------- | ---------- | ----------------------------------------------- | | `use_custom_outro` | `"mosaic" \| "custom"` | Yes | `"mosaic"` | Select built-in outro vs uploaded custom outro. | | `custom_outro_video_id` | `string` (UUID) | Conditional | unset | Required when `use_custom_outro="custom"`. | ### Scenario requirements * If `use_custom_outro="custom"`, provide `custom_outro_video_id`. ### Runtime notes * UI upload flow is MP4-focused and stores custom outro as an asset ID. ### Example ```json theme={null} { "use_custom_outro": "custom", "custom_outro_video_id": "dddddddd-eeee-ffff-0000-111111111111" } ``` # 11. Reframe Source: https://docs.mosaic.so/tiles/reframe Automatically convert your video into 9:16 or 1:1 while keeping the subject in view. Automatically convert your video into a social-ready aspect ratio (`9:16` or `1:1`) while keeping the subject in view. This is essential for repurposing videos across different platforms without manually cropping, zooming, or tracking faces. ## How It Works The Reframe tile analyzes your footage and automatically chooses the best framing for each moment. It outputs a new lossy video render with the reframing baked in, so downstream tiles receive a normal video with no crop keyframes to preserve. Reframe always keeps blurred/letterboxed padding enabled when it needs to preserve more of the source frame. This is especially useful for zoom-out moments where a tight crop would lose important context. Reframe ## Input & Settings ### 1. Shape (Required) Select the output shape of your video. Options: * **9:16 (Portrait)** — TikTok, Reels, Shorts * **1:1 (Square)** — Instagram Feed, Facebook Choose based on **where you're publishing**. ### 2. Zoom Out Enable or disable zoom-out framing. When enabled, Reframe can choose to show more of the source frame instead of cropping tightly. Padding stays enabled either way; disabling zoom-out only prevents zoom-out segments from being used. ### 3. Dual Crop For `9:16`, Reframe can optionally use a stacked dual-crop layout for moments such as split-screen conversations or two important subjects. For `1:1`, dual crop is always disabled. *** ## API Info * **Node ID:** `0e3a90e4-173f-42fc-b7ef-0df6a062e26c` ### Node params | Param | Type | Required | Default | Notes | | --------------------- | ----------------- | -------- | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | | `shape` | `"9:16" \| "1:1"` | No | `"9:16"` | Target output shape. | | `zoom_out_enabled` | `boolean` | No | `true` | Allows zoom-out framing with padding. | | `allow_dual_crop` | `boolean` | No | `true` for `9:16`, `false` for `1:1` | Allows stacked dual-crop output when the target shape is `9:16`. | | `static_reframe_mode` | `boolean` | No | `false` | Static Reframe mode for talking-head footage where people mostly speak in place, such as podcasts or interviews. | | `aspect` | `"9:16" \| "1:1"` | No | `"9:16"` | Legacy alias for `shape`. | | `aspect_ratio` | `"9:16" \| "1:1"` | No | `"9:16"` | Legacy alias for `shape`. | ### Parameter groups * **Output framing:** `shape` * **Framing behavior:** `zoom_out_enabled`, `allow_dual_crop`, `static_reframe_mode` ### Runtime notes * Padding is always enabled and is not user-configurable. * Framing decisions are automatic and adapt to the content of the video. * Safe-zone and graphics-avoidance controls are not exposed in this tile. * Existing nodes with older `aspect` or `aspect_ratio` settings continue to work. `1:1` stays square; any older unsupported ratios are coerced to `9:16`. ### Example ```json theme={null} { "shape": "9:16", "zoom_out_enabled": true, "allow_dual_crop": true, "static_reframe_mode": false } ``` # 8. Rough Cut Source: https://docs.mosaic.so/tiles/rough-cut Automatically create a rough cut from your raw footage by keeping meaningful sections and removing filler, silence, or irrelevant content. Automatically create a rough cut from your raw footage by keeping the meaningful sections and removing filler, silence, or irrelevant content — based on your creative intent. This tile is useful when you want to quickly condense long-form footage into a cleaner baseline edit without manually scrubbing timelines. ## How It Works The Rough Cut tile analyzes your footage and applies edits based on **your prompt**, not just simple silence trimming. You tell Mosaic what kind of cut you want, and it will: * Detect meaningful segments * Remove dead air or unimportant parts * Preserve emotional, narrative, or informational beats * Produce a condensed timeline you can build on ## Input Fields ### Creative Intent Prompt (Required) This prompt defines the *logic* of your cut — **what stays** and **what gets cut**. Examples: * "Highlight only the parts where the speaker gives key takeaways." * "Cut everything except the emotional or dramatic beats." * "Make an efficient, fast-paced summary version under 90 seconds." ### Quick Suggestions For users who don't know what to write, Mosaic offers preset buttons for common patterns like storytelling, narrative, tone, and mood-based cuts. ### Multi-Input Behavior By default, Rough Cut combines all connected input videos into **one cohesive rough cut output**. This is best when you connect many source videos and want Mosaic to choose the strongest moments across the whole set. Turn off **Combine inputs into one cohesive cut** (`combine_input_renders=false`) when each input should be edited independently. For example, 20 connected videos will produce 20 separate rough-cut outputs instead of one combined timeline. ## Best Use Cases * Long podcast → short narrative episode * Interview → highlight reel * Commentary → tight opinion piece * Vlog → emotional storyline * Raw footage → clip-ready baseline ## What Comes Next Rough Cut produces a clean foundation you can send to: * [**Clips**](/tiles/clips) — extract short-form highlights * [**Captions**](/tiles/captions) — add subtitles * [**Reframe**](/tiles/reframe) — convert to 9:16 for TikTok * [**Montage**](/tiles/montage) — build a beat-matched sequence * [**Destination**](/tiles/destination) — export or publish **Informational:** > "Keep only the sections where the speaker explains key concepts or answers questions." **Emotional:** > "Keep emotional reactions, laughter, suspense, and heartfelt moments." **Motivational:** > "Extract inspiring sentences and moments where the speaker offers wisdom." **Clip Prep:** > "Produce a high-signal rough cut that's suitable for extracting shorts." * The more specific your prompt, the better the cut * Mention **what to keep**, not just what to remove * Include mood cues if you care about emotional curation (e.g. "uplifting," "funny," "tense") * If you want short-form highlights, combine Rough Cut with [Clips](/tiles/clips) *** ## API Info * **Node ID:** `e6098dd4-4a6e-470f-981e-2618c11eee21` ### Node params | Param | Type | Required | Default | Notes | | ----------------------- | ----------------- | -------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | | `prompt` | `string` | Yes | `""` | Defines what content to preserve/remove. | | `model_tier` | `"fast" \| "pro"` | No | `"fast"` | Controls model quality and speed. | | `combine_input_renders` | `boolean` | No | `true` | Combined output behavior. When `true`, all inputs become one cohesive rough cut. When `false`, each input render gets its own rough cut output. | ### Parameter groups * **Cut intent (required):** `prompt` * **Model quality:** `model_tier` * **Combined outputs:** `combine_input_renders` ### Behavior notes * By default, this tile consolidates multiple inputs into one rough-cut output (`combine_input_renders=true`). * Set `combine_input_renders=false` to create one rough-cut output per input render. ### Example ```json theme={null} { "prompt": "Keep only concise key takeaways and remove repetitive tangents.", "model_tier": "pro", "combine_input_renders": true } ``` # 12. Silence Removal Source: https://docs.mosaic.so/tiles/silence-removal Automatically removes awkward pauses, long gaps, and dead air from your video. Automatically removes awkward pauses, long gaps, and dead air from your video to make pacing tighter and more engaging. This is especially useful for podcasts, commentary, educational content, and talking-head videos. ## How It Works Silence Removal analyzes the audio and: * Detects segments with no speech * Cuts or shortens those gaps * Rejoins the clips smoothly for a natural flow This saves hours of manual timeline trimming. ## Input & Settings ### Remove Filler Words (Optional) If enabled, Mosaic can also remove filler words like: * "um" * "uh" * "like" * "you know" * "basically" * "so…" Set to: * **Yes** → Removes filler words for cleaner speech * **No** → Keeps natural speech patterns *** ## API Info * **Node ID:** `a22d0b93-2bbf-479d-8efd-d446163982e8` ### Node params | Param | Type | Required | Default | Notes | | --------------------- | --------- | -------- | ------- | ------------------------------------------------- | | `remove_filler_words` | `boolean` | No | `true` | Removes filler words in addition to silence cuts. | ### Parameter groups * **Speech cleanup toggle:** `remove_filler_words` ### Runtime behavior (important) * Current flow explicitly cuts **all detected inter-word gaps** (no threshold filtering path). * `remove_filler_words` is the only user-facing control in current UI. * For deterministic automation, always set `remove_filler_words` explicitly. ### Example ```json theme={null} { "remove_filler_words": true } ``` # 5. Video Generation Source: https://docs.mosaic.so/tiles/video-generation Generate videos from prompts and optional media references with Seedance 2. Video Generation creates new video clips from text prompts. Use it when you want AI-generated footage rather than an edit of existing footage. ## How It Works Describe the shot, subject, style, camera motion, and desired duration. Mosaic sends the prompt and any selected image, video, or audio references to the generation model, then returns a video asset that can feed downstream tiles. Use Video Generation for: * Product shots and cinematic b-roll * Social clips from a creative prompt * Reference-guided motion from uploaded images or clips * Sound-enabled generated scenes ## API Usage Create an agent shell: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/create" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "name": "Seedance product shot", "visibility": "private" }' ``` Add a Video Generation node: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/update" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "operations": [ { "op": "create_node", "node_type_id": "a2eb3ec2-da7a-4f97-94d2-a9a537548522", "params_used": { "prompt": "A cinematic handheld shot of a matte black water bottle on a mountain trail at sunrise", "model": "seedance-2", "resolution": "1080p", "duration": "8", "aspect_ratio": "9:16", "generate_audio": true } } ] }' ``` Then run the agent with no video inputs: ```bash theme={null} curl -X POST "https://api.mosaic.so/agent/AGENT_ID/run" \ -H "Authorization: Bearer mk_your_api_key" \ -H "Content-Type: application/json" \ -d '{ "callback_url": "https://your-webhook.com/mosaic" }' ``` ## API Info * **Node ID:** `a2eb3ec2-da7a-4f97-94d2-a9a537548522` ### Node params | Param | Type | Required | Default | Notes | | ------------------ | ----------------------------------------------------------------- | -------- | -------------- | ---------------------------------------------------------------- | | `prompt` | `string` | Yes | `""` | Generation prompt. | | `model` | `"seedance-2"` | No | `"seedance-2"` | Video model. | | `resolution` | `"1080p" \| "4k"` | No | `"1080p"` | Requested output resolution. 4K is billed at 2x normal Seedance. | | `duration` | `"auto" \| "4" ... "15"` | No | `"auto"` | Duration in seconds, or automatic model choice. | | `aspect_ratio` | `"auto" \| "21:9" \| "16:9" \| "4:3" \| "1:1" \| "3:4" \| "9:16"` | No | `"auto"` | Output aspect ratio. | | `generate_audio` | `boolean` | No | `true` | Generate synchronized audio when supported. | | `selected_context` | `{images:string[],videos:string[],audio:string[]}` | No | empty lists | Uploaded references to guide generation. | ### Example ```json theme={null} { "prompt": "A cinematic macro shot of coffee pouring into a glass mug", "model": "seedance-2", "resolution": "1080p", "duration": "8", "aspect_ratio": "16:9", "generate_audio": true } ``` For 4K output, use: ```json theme={null} { "prompt": "A cinematic macro shot of coffee pouring into a glass mug", "model": "seedance-2", "resolution": "4k", "duration": "8", "aspect_ratio": "16:9", "generate_audio": true } ``` 4K Seedance generations are billed at 2x normal Seedance. # 20. Voice Source: https://docs.mosaic.so/tiles/voice Modify spoken audio in your video using AI — including dubbing, word swapping, and lip-sync. Modify spoken audio in your video using AI — including dubbing into different languages, swapping specific words, and generating lip-synced speech. This is valuable for repurposing videos globally, correcting misspoken words, or adjusting terminology without re-recording. ## How It Works The Voice tile analyzes your video's speech, generates replacement audio based on your selections, and merges it back into the timeline. If enabled, it also adjusts lip movements to match the new audio. Voice UI ## Input and Settings ### Target Language Choose the output language for the voice. Use cases: * Global distribution (English → Spanish → French, etc.) * Multilingual short-form content * Translating educational or tutorial content ### Preserve Background Audio Choose whether to keep original ambient sounds or music. * **Yes** — keeps natural room tone, gameplay audio, background music * **No** — outputs clean isolated speech for controlled mixing ### Lip Sync Aligns mouth movements to match the new speech. Essential when dubbing to another language, replacing script sections, or creating seamless speech edits. **Advanced features (limited provider support):** The Voice tile also supports **Safewords** (words that should never be modified, like brand names) and a **Translation Dictionary** (custom word/phrase replacements for fine-tuned localization). Availability depends on your selected voice provider. Voice pairs well with [Captions](/tiles/captions) (add subtitles in the new language), [Reframe](/tiles/reframe) (adapt for different platforms), and [Audio Enhance](/tiles/audio-enhance) (polish the final audio). *** ## API Info * **Node ID:** `14abd0c1-402c-40b8-8ec8-defd951efe01` ### Node params | Param | Type | Required | Default | Notes | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- | ------------------------------- | ------------------------------------------------------------------------------------------- | | `target_language` | `"english" \| "hindi" \| "portuguese" \| "mandarin" \| "spanish" \| "french" \| "german" \| "japanese" \| "arabic" \| "russian" \| "korean" \| "indonesian" \| "italian" \| "dutch" \| "turkish" \| "polish" \| "swedish" \| "tagalog" \| "malay" \| "romanian" \| "ukrainian" \| "greek" \| "czech" \| "danish" \| "finnish" \| "bulgarian" \| "croatian" \| "slovak" \| "tamil"` | No | metadata/UI default `"english"` | Backend flow fallback is `"spanish"` if missing. Set explicitly for deterministic behavior. | | `preserve_background_audio` | `boolean` | No | `true` | If false, background mix is dropped. | | `enable_lipsync` | `boolean` | No | `true` | Lip sync control for dubbed output. | | `safewords` | `string` | No | `""` | Present in schema; currently marked unsupported in ElevenLabs path. | | `translation_dictionary` | `{source:string,target:string}[]` | No | unset | Present in schema; currently marked unsupported in ElevenLabs path. | ### Parameter groups * **Language & output:** `target_language`, `preserve_background_audio`, `enable_lipsync` * **Advanced lexical controls:** `safewords`, `translation_dictionary` ### Runtime notes * There is a known default mismatch across layers (`target_language`, `enable_lipsync`), so API agents should always send both explicitly. * ElevenLabs language normalization happens server-side before synthesis request. ### Example ```json theme={null} { "target_language": "spanish", "preserve_background_audio": true, "enable_lipsync": false } ``` # 15. Watermark Source: https://docs.mosaic.so/tiles/watermark Add a watermark or logo to your video for branding, ownership, or attribution. Add a watermark or logo to your video for branding, ownership, or attribution. Useful for creators, brands, agencies, or clients who want consistent visual identity across content. ## How It Works The Watermark tile places an image overlay (logo or watermark) on top of your final video. You can use Mosaic's default branding or upload your own logo for custom branding. Add your beautiful logos/@name tags ## Input & Settings ### Logo Source Choose one: * **Use Mosaic Logo** — Quick default branding * **Use Custom Logo** — Upload your own PNG/JPG (recommended for creators & brands) ### Position Pick where the watermark should appear. Common presets include: * Bottom Right (default) * Bottom Left * Top Right * Top Left Choose based on platform and composition. ### Size Adjusts logo size as a percentage of video width.\ Example from screenshot: * **30% of width** → medium branding ### Opacity Controls visibility (0–100%).\ Examples: * **20–40%** → subtle watermark * **70–100%** → strong visible branding ### Margin Adds spacing (in pixels) from the video edges to avoid clipping or interference with captions. *** ## API Info * **Node ID:** `6808af58-2d9a-4e3b-aacb-2d9c143b7729` ### Node params | Param | Type | Required | Default | Notes | | ----------------- | -------------------------------------------------------------- | ----------- | ---------------- | ----------------------------------------- | | `use_custom_logo` | `"mosaic" \| "custom"` | Yes | `"mosaic"` | Source mode for watermark image. | | `image_id` | `string` (UUID) | Conditional | `null` | Required when `use_custom_logo="custom"`. | | `logo_position` | `"top-left" \| "top-right" \| "bottom-left" \| "bottom-right"` | Yes | `"bottom-right"` | Overlay anchor position. | | `logo_size` | `number` (percent) | Yes | `30` | Relative watermark width scale. | | `logo_opacity` | `number` (percent) | Yes | `80` | 10-100 in UI contract. | | `logo_margin_x` | `number` (px) | Yes | `20` | Horizontal edge offset. | | `logo_margin_y` | `number` (px) | Yes | `20` | Vertical edge offset. | ### Parameter groups * **Logo source:** `use_custom_logo`, `image_id` * **Placement & sizing:** `logo_position`, `logo_size`, `logo_opacity`, `logo_margin_x`, `logo_margin_y` ### Scenario requirements * If `use_custom_logo="custom"`, provide a valid image UUID in `image_id`. ### Runtime notes * Backend validates `image_id` and fetches source dimensions before composing placement. * Existing watermark-related tracks are removed/replaced by the new operation. ### Example ```json theme={null} { "use_custom_logo": "custom", "image_id": "cccccccc-dddd-eeee-ffff-000000000000", "logo_position": "bottom-right", "logo_size": 30, "logo_opacity": 80, "logo_margin_x": 20, "logo_margin_y": 20 } ``` # Welcome to Mosaic Docs Source: https://docs.mosaic.so/welcome Image Mosaic is an intelligent video editing platform that turns raw footage into publish-ready content using a visual workflow made of tiles. Upload video, clip it, caption it, add b-roll, reframe it for different platforms, export it, and automate your editing process — all without needing to learn complex editing software. *** ## Jump Right In Learn the 3-step creative flow and start editing in minutes Understand the building blocks of every Mosaic workflow Start with a pre-built workflow and customize it Quick answers to the most common questions *** ## What's in These Docs * Understand what Mosaic is and why it exists * Learn how to start your first editing workflow * Understand core concepts like Tiles & Canvas * Know what each Tile does and when to use it * Manage your subscription and settings * Learn how to export, collaborate, and share * Connect with our community and support If you ever feel stuck, open this doc, find the relevant part, and you'll have a clear next step.