Authentication
All webhooks are sent with a signature in the X-Mosaic-Signature header when you have a webhook secret configured. The signature is your webhook secret sent as a plaintext string for simple validation.
Important: This is NOT encryption or hashing - it’s a direct plaintext string comparison for authentication.
Signature Validation Example
# Simple plaintext validation
webhook_signature = request.headers.get('X-Mosaic-Signature')
expected_secret = os.environ.get('MOSAIC_WEBHOOK_SECRET')
if expected_secret and webhook_signature != expected_secret:
return {"error": "Invalid webhook signature"}, 401
Webhook Types
Mosaic sends two types of webhooks:
- RUN_STARTED - Sent when an agent run begins processing
- RUN_FINISHED - Sent when an agent run completes (successfully or with failures)
RUN_STARTED
Sent immediately when an agent run begins processing. This webhook includes information about all input videos being processed.
Payload Structure
{
"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/.../input-thumb.jpg"
}
],
"node_status_counts": {
"completed": 1,
"in_progress": 5,
"failed": 0
},
"triggered_by": {
"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"
}
}
Field Descriptions
| Field | Type | Description |
|---|
flag | "RUN_STARTED" | Webhook type identifier |
agent_id | string | UUID of the agent being executed |
run_id | string | UUID of the agent run (same as agent_state_id) |
status | "running" | Current status of the run |
inputs | VideoInput[] | Array of input videos being processed |
node_status_counts | NodeStatusCounts | Counts of nodes in different statuses |
triggered_by | TriggerInfo | Optional information about what triggered this run |
RUN_FINISHED
Sent when an agent run completes processing (successfully or with failures). This webhook includes all final outputs produced by the run.
Payload Structure
{
"flag": "RUN_FINISHED",
"agent_id": "123e4567-e89b-12d3-a456-789012345678",
"run_id": "7f8d9c2b-4a6e-8b3f-1d5c-9e2f3a4b5c6d",
"status": "completed",
"inputs": [
{
"video_url": "https://storage.googleapis.com/.../input.mp4",
"thumbnail_url": "https://storage.googleapis.com/.../input-thumb.jpg"
}
],
"outputs": [
{
"video_url": "https://storage.googleapis.com/.../output.mp4",
"thumbnail_url": "https://storage.googleapis.com/.../thumb.jpg",
"completed_at": "2024-01-15T10:35:00Z"
}
],
"node_status_counts": {
"completed": 10,
"in_progress": 0,
"failed": 0
},
"triggered_by": {
"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"
}
}
Field Descriptions
| Field | Type | Description |
|---|
flag | "RUN_FINISHED" | Webhook type identifier |
agent_id | string | UUID of the agent that was executed |
run_id | string | UUID of the agent run (same as agent_state_id) |
status | "completed" | "partial_complete" | "failed" | Final status of the run |
inputs | VideoInput[] | Array of input videos that were processed |
outputs | VideoOutput[] | Array of final output videos produced by the run |
node_status_counts | NodeStatusCounts | Counts of nodes in different statuses |
triggered_by | TriggerInfo | Optional information about what triggered this run |
NodeStatusCounts Structure
| Field | Type | Description |
|---|
completed | integer | Number of nodes that finished successfully (status: "completed", "partial_complete") |
in_progress | integer | Number of nodes currently processing or waiting (status: "running", "queued") |
failed | integer | Number of nodes that failed or are blocked (status: "failed", "blocked") |
Triggered_by in RUN_STARTED and RUN_FINISHED is identical.
If a run is initiated manually via POST /agent/[agent_id]/run using a YouTube URL, triggered_by.type will still be "youtube", but trigger_id will be null because there is no saved channel-trigger configuration associated with the run.
In rare cases, triggered_by.channel_id may be null for manual YouTube runs if channel metadata is unavailable at run creation time. The webhook will still include video_id, video_title, and video_url.
Status Values
The status field can have the following values:
"completed" - All videos processed successfully with outputs generated
"partial_complete" - Some videos processed successfully, but others failed
"failed" - The entire run failed, no outputs generated