Skip to main content

n8n Automation with ViralSync

Automate video generation workflows in n8n by connecting ViralSync's Render API to your existing data sources, AI tools, and notification systems.


Prerequisites

  • n8n instance (self-hosted or cloud at app.n8n.cloud)
  • ViralSync API key (Pro plan or higher) — create in Dashboard → Settings → API Keys
  • Your ViralSync project ID — visible in Dashboard → Projects

Pattern 1: Submit and poll (beginner)

This simple workflow submits a render job and polls until it completes. Good for workflows where n8n isn't publicly reachable.

Step 1 — HTTP Request: Submit render job

Configure an HTTP Request node:

SettingValue
MethodPOST
URLhttps://api.viralsync.io/v1/render/jobs
AuthenticationHeader Auth
Header Namex-api-key
Header Value{{ $vars.VIRALSYNC_API_KEY }} (store in n8n Variables)
BodyJSON

Body content:

{
"kind": "movie",
"projectId": "proj_abc123",
"movie": {
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_1",
"duration": 5,
"bgColor": "#1a1a2e",
"layers": [
{
"id": "title",
"type": "text",
"text": "{{ $json.title }}",
"startTime": 0,
"duration": 5,
"zIndex": 1,
"position": { "x": 360, "y": 460 },
"size": { "width": 1200, "height": 160 },
"fontSize": 72,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "center"
}
]
}
]
}
}

This returns { "jobId": "job_..." }. Save the jobId for subsequent nodes.

Step 2 — Wait node

Add a Wait node set to 30 seconds. This gives the render job time to process before the first status check.

Step 3 — HTTP Request: Check status

SettingValue
MethodGET
URLhttps://api.viralsync.io/v1/jobs/{{ $('Submit Render Job').item.json.jobId }}
Header Namex-api-key
Header Value{{ $vars.VIRALSYNC_API_KEY }}

Step 4 — If node: check status

Add an If node with two conditions:

Branch 1 (done): {{ $json.status }} equals done → proceed to your success handler (download video, send Slack message, etc.)

Branch 2 (failed): {{ $json.status }} equals failed → proceed to your error handler

Branch 3 (otherwise): Loop back to the Wait node for another 30 seconds, then re-check

Step 5 — Use the output URL

In the success branch, access the video URL:

{{ $json.outputUrl }}

Instead of polling, receive a push notification when the job completes. Requires n8n to have a public URL.

Step 1 — Webhook node

Add a Webhook node (trigger type: POST). Copy the webhook URL — it will look like:

https://your-n8n.com/webhook/viralsync-render

Step 2 — Submit render job with callbackUrl

In your HTTP Request node, add callbackUrl to the JSON body:

{
"kind": "movie",
"projectId": "proj_abc123",
"callbackUrl": "https://your-n8n.com/webhook/viralsync-render",
"movie": { ... }
}

Step 3 — Process the webhook event

When the job completes, ViralSync sends:

{
"jobId": "job_a1b2c3d4e5f6",
"status": "done",
"outputUrl": "https://r2.viralsync.io/outputs/job_a1b2c3d4e5f6/output.mp4",
"mediaData": { "duration": 10.0, "width": 1920, "height": 1080 }
}

Access values in downstream nodes:

  • Output URL: {{ $json.outputUrl }}
  • Duration: {{ $json.mediaData.duration }}
  • Status: {{ $json.status }}

Step 4 — Handle different event types

Add an If node or Switch node on {{ $json.status }}:

  • done → success branch (save URL, send notification)
  • failed → error branch (log error, alert)
  • running / progress → optional: update a progress indicator

Building dynamic movie JSON

Use n8n expressions to inject data from upstream nodes into the movie JSON:

Example: product video with dynamic title and image

Assume an upstream node returns { "productName": "Widget Pro", "imageUrl": "https://cdn...." }:

{
"kind": "movie",
"projectId": "proj_abc123",
"movie": {
"width": 1920,
"height": 1080,
"fps": 30,
"scenes": [
{
"id": "scene_product",
"duration": 6,
"bgColor": "#0f172a",
"layers": [
{
"id": "product_image",
"type": "image",
"source": "{{ $json.imageUrl }}",
"startTime": 0,
"duration": 6,
"zIndex": 0,
"position": { "x": 0, "y": 0 },
"size": { "width": 960, "height": 1080 }
},
{
"id": "product_name",
"type": "text",
"text": "{{ $json.productName }}",
"startTime": 0,
"duration": 6,
"zIndex": 1,
"position": { "x": 980, "y": 400 },
"size": { "width": 880, "height": 120 },
"fontSize": 56,
"fontWeight": "bold",
"color": "#ffffff",
"textAlign": "left"
}
]
}
]
}
}

Handling errors in n8n

ViralSync error responses include a code field. Use this in an If node to handle specific errors:

Error coden8n action
CONCURRENCY_LIMIT_EXCEEDEDAdd a 30-second Wait, then retry the submission
RATE_LIMITEDRead Retry-After from headers; add a Wait node for that duration
RENDER_QUOTA_EXCEEDEDSend a notification and stop the workflow
ASSET_NOT_FOUNDLog the failed URL, alert the team

In the HTTP Request node, enable "Continue on Fail" and check {{ $json.code }} in a downstream If node.


Tips

Store your API key in n8n Variables, not hardcoded in nodes: go to Settings → Variables → Add Variable (VIRALSYNC_API_KEY). Then use {{ $vars.VIRALSYNC_API_KEY }} in all HTTP Request headers.

Use n8n's built-in retry: In the HTTP Request node's Options, set Retry on Fail: 3 and Retry Interval: 2000ms to automatically handle transient 5xx errors.

For multi-scene videos from a list: Use n8n's Loop Over Items node to build a scenes array from a list of data items, then pass it as the movie.scenes field.

Webhook tunnel for local development: If running n8n locally, use ngrok http 5678 to expose it and use the ngrok URL as your callbackUrl.