n8n integration
Automate music-video pipelines with Songs2VID Developer & Automation (€15/mo) and n8n. Renders run asynchronously on Songs2VID; n8n can either poll job status or receive a webhook when encoding finishes — so long FFmpeg jobs never hit HTTP timeouts in your workflow.
:::info Cloud vs self-hosted
Hosted API: https://songs2vid.com — requires Developer & Automation or Enterprise (Independent Producer €7 is Web UI only).
Self-hosted OSS: your own BASE_URL — API keys work without a paid plan. Same endpoints.
:::
Prerequisites
- A Songs2VID account with YouTube connected (Google OAuth with YouTube scopes)
- Developer & Automation on songs2vid.com (or a self-hosted instance)
- An n8n instance (Cloud or self-hosted) that can reach Songs2VID over HTTPS
Step 1 — Install the Songs2VID community node
Option A — Official community node (recommended)
- Open n8n → Settings → Community nodes (or Settings → npm depending on your n8n version)
- Install package:
n8n-nodes-songs2vid
- Restart n8n if prompted
- In the canvas, search for Songs2VID — you should see nodes such as Upload File, Create Render, and Get Job
If the package is not yet listed on your n8n build, use Option B (HTTP Request). Both talk to the same REST API documented in API overview.
Option B — HTTP Request nodes (works today)
Use n8n’s built-in HTTP Request node against:
| Action | Method | Path |
|---|---|---|
| Upload | POST | /api/v1/upload |
| Start render | POST | /api/v1/render |
| Poll status | GET | /api/v1/jobs/:id |
| Manage keys | GET/POST/DELETE | /api/v1/user/api-keys |
Authentication header on every call:
Authorization: Bearer s2yt_live_your_key_here
Step 2 — Generate an API key
- Sign in at songs2vid.com
- Open Dashboard → Settings
- Under API access, create a key (Developer plan required)
- Copy the token once — it is shown only at creation and starts with
s2yt_live_
You can also create keys via the API:
curl -X POST "https://songs2vid.com/api/v1/user/api-keys" \
-H "Cookie: <your session cookie>" \
-H "Content-Type: application/json" \
-d '{"name":"n8n production"}'
Or with an existing Bearer key (rotate / add keys from automation).
Treat API keys like passwords. Revoke compromised keys immediately from Settings or DELETE /api/v1/user/api-keys?id=....
Step 3 — Authenticate in n8n Credentials
Community node
- In any Songs2VID node → Credential to connect with → Create new
- Paste your API key
- Set Base URL to
https://songs2vid.com(or your self-hosted origin, no trailing slash)
HTTP Request (Header Auth)
- Credentials → Header Auth
- Name:
Authorization - Value:
Bearer s2yt_live_...(include the wordBearerand a space) - Attach that credential to every Songs2VID HTTP Request node
Recipe 1 — Auto render & upload
Goal: New audio in Google Drive / Dropbox → Songs2VID → YouTube (and optionally Discord / socials).
Logic
flowchart LR
A[New file in Drive/Dropbox] --> B[Download binary]
B --> C[POST /api/v1/upload cover]
B --> D[POST /api/v1/upload audio]
C --> E[POST /api/v1/render]
D --> E
E --> F[Webhook or poll job]
F --> G[YouTube live]
Steps in n8n
- Trigger — Google Drive File Created / Dropbox File Created (filter
.mp3/.wav/.flac) - Download the audio binary into the workflow
- Upload cover —
POST /api/v1/uploadmultipart:file= cover image,type=image
Savepathfrom the JSON response - Upload audio — same endpoint with
type=audio
Response may includeaudioTags.title/audioTags.artistfor metadata - Create render —
POST /api/v1/renderwith JSON:
{
"imagePath": "/uploads/.../cover.jpg",
"webhookUrl": "https://your-n8n.example/webhook/songs2vid-complete",
"items": [
{
"audioPath": "/uploads/.../track.mp3",
"audioFilename": "track.mp3",
"metadata": {
"title": "Artist - Track (Official Audio)",
"songTitle": "Track",
"artist": "Artist",
"privacy": "UNLISTED",
"categoryId": "10",
"resolution": "1920x1080",
"includeWatermark": false
}
}
]
}
- Songs2VID encodes at 1080p (and plan-allowed resolutions), 320 kbps AAC on Developer, priority queue, then uploads to the YouTube channel linked in the dashboard
- On success, the webhook (or poll response) includes
youtubeVideoId— post that to Discord, Notion, etc.
Keep a reusable cover image uploaded once and reuse its path, or upload a per-track cover via metadata.imagePath.
Recipe 2 — Webhook callbacks (async jobs)
Renders can take minutes. Do not leave a single HTTP Request waiting for the finished video.
Pattern A — Wait for webhook (preferred)
- Add an n8n Webhook node (POST), path e.g.
songs2vid-complete - Activate the workflow and copy the Production URL
- Pass that URL as
webhookUrlwhen calling/api/v1/render - Songs2VID POSTs JSON when items/jobs finish:
{
"event": "job.completed",
"jobId": "clxxxxxxxx",
"status": "COMPLETED",
"itemId": "clitemxxx",
"youtubeVideoId": "dQw4w9WgXcQ",
"error": null,
"completedAt": "2026-08-08T12:34:56.000Z"
}
event | Meaning |
|---|---|
job.item.completed | One track finished |
job.item.failed | One track failed (error set) |
job.completed | All items succeeded |
job.failed | All items failed |
job.partial | Mix of success and failure |
Pattern B — Poll status
After create, response includes:
{
"jobId": "clxxxxxxxx",
"status": "PENDING",
"statusUrl": "/api/v1/jobs/clxxxxxxxx",
"webhookUrl": "https://..."
}
Loop with Wait + GET https://songs2vid.com{{ $json.statusUrl }} until status is COMPLETED, FAILED, or PARTIAL (every 15–30s). Prefer webhooks when n8n is reachable from the public internet.
Copy-paste workflow template
Import this into n8n: ⋯ menu → Import from File / URL, or paste after copying below.
- Create Header Auth credentials (
Authorization=Bearer s2yt_live_…) - Replace credential placeholders on the HTTP Request nodes
- Wire binary inputs (
cover,audio) from your Drive/Dropbox download nodes - Set the Webhook node’s Production URL as
webhookUrlon Create Render (or use a Wait node + pollstatusUrl)
Preview workflow JSON
{
"name": "Songs2VID — Drive → Render → YouTube (webhook)",
"meta": {
"templateCredsSetupCompleted": false,
"instanceId": "songs2vid-docs-template"
},
"nodes": [
{
"parameters": {},
"id": "manual-trigger",
"name": "When clicking ‘Test workflow’",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
0
]
},
{
"parameters": {
"path": "songs2vid-complete",
"httpMethod": "POST",
"responseMode": "onReceived",
"options": {}
},
"id": "webhook-complete",
"name": "Songs2VID Job Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
0,
280
],
"webhookId": "songs2vid-complete"
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.SONGS2VID_BASE_URL || 'https://songs2vid.com' }}/api/v1/upload",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "file",
"inputDataFieldName": "cover"
},
{
"name": "type",
"value": "image"
}
]
},
"options": {}
},
"id": "upload-cover",
"name": "Upload Cover Image",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
260,
0
],
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE_ME",
"name": "Songs2VID API Key"
}
}
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.SONGS2VID_BASE_URL || 'https://songs2vid.com' }}/api/v1/upload",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"contentType": "multipart-form-data",
"bodyParameters": {
"parameters": [
{
"parameterType": "formBinaryData",
"name": "file",
"inputDataFieldName": "audio"
},
{
"name": "type",
"value": "audio"
}
]
},
"options": {}
},
"id": "upload-audio",
"name": "Upload Audio",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
500,
0
],
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE_ME",
"name": "Songs2VID API Key"
}
}
},
{
"parameters": {
"method": "POST",
"url": "={{ $env.SONGS2VID_BASE_URL || 'https://songs2vid.com' }}/api/v1/render",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"imagePath\": \"{{ $('Upload Cover Image').item.json.path }}\",\n \"webhookUrl\": \"{{ $execution.resumeUrl || $('Songs2VID Job Webhook').item.json.webhookUrl || '' }}\",\n \"items\": [{\n \"audioPath\": \"{{ $('Upload Audio').item.json.path }}\",\n \"audioFilename\": \"{{ $('Upload Audio').item.json.filename }}\",\n \"metadata\": {\n \"title\": \"{{ $('Upload Audio').item.json.audioTags.title || $('Upload Audio').item.json.filename }}\",\n \"songTitle\": \"{{ $('Upload Audio').item.json.audioTags.title || '' }}\",\n \"artist\": \"{{ $('Upload Audio').item.json.audioTags.artist || '' }}\",\n \"description\": \"Uploaded via n8n + Songs2VID\",\n \"tags\": \"music\",\n \"privacy\": \"UNLISTED\",\n \"categoryId\": \"10\",\n \"resolution\": \"1920x1080\",\n \"notifySubscribers\": false,\n \"madeForKids\": false,\n \"embeddable\": true,\n \"creativeCommons\": false,\n \"includeWatermark\": false\n }\n }]\n}",
"options": {}
},
"id": "create-render",
"name": "Create Render Job",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
740,
0
],
"credentials": {
"httpHeaderAuth": {
"id": "REPLACE_ME",
"name": "Songs2VID API Key"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "job-done",
"leftValue": "={{ $json.body.event || $json.event }}",
"rightValue": "job.completed",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "or"
},
"options": {}
},
"id": "if-completed",
"name": "Job Completed?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
260,
280
]
},
{
"parameters": {
"content": "## Job finished\nYouTube video ID: `{{ $json.body.youtubeVideoId || $json.youtubeVideoId || 'see items' }}`\n\nPoll fallback: `GET {{ $env.SONGS2VID_BASE_URL || 'https://songs2vid.com' }}{{ $('Create Render Job').item.json.statusUrl }}`",
"height": 240,
"width": 360
},
"id": "sticky-note",
"name": "Next steps",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
520,
240
]
}
],
"connections": {
"When clicking ‘Test workflow’": {
"main": [
[
{
"node": "Upload Cover Image",
"type": "main",
"index": 0
}
]
]
},
"Upload Cover Image": {
"main": [
[
{
"node": "Upload Audio",
"type": "main",
"index": 0
}
]
]
},
"Upload Audio": {
"main": [
[
{
"node": "Create Render Job",
"type": "main",
"index": 0
}
]
]
},
"Songs2VID Job Webhook": {
"main": [
[
{
"node": "Job Completed?",
"type": "main",
"index": 0
}
]
]
},
"Job Completed?": {
"main": [
[
{
"node": "Next steps",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "songs2vid"
},
{
"name": "n8n"
}
],
"triggerCount": 0,
"updatedAt": "2026-08-08T00:00:00.000Z",
"versionId": "1"
}:::note About the template
The shipped template uses HTTP Request + Webhook nodes so it works even before the community package is installed. After installing n8n-nodes-songs2vid, you can swap HTTP nodes for native Songs2VID nodes with the same credentials.
:::
Plans, quotas, and errors (quick reference)
| Plan | REST API | Monthly renders | Audio encode |
|---|---|---|---|
| Free | No | 3 (Web UI) | 192 kbps AAC |
| Independent Producer (€7) | No — 403 | 30 (Web UI) | 320 kbps |
| Developer & Automation (€15) | Yes | 60 (UI + API) | 320 kbps · priority queue |
| Enterprise | Yes | Custom | 320 kbps · priority queue |
Common API responses:
| Status | Meaning |
|---|---|
401 | Missing/invalid API key |
403 | "REST API access requires the Developer & Automation plan." or YouTube not connected |
402 | Monthly quota / credits exhausted |
429 | Rate limit (default 60 req/min per API key) — honor Retry-After |
Full curl catalog: Endpoints.
Next steps
- API overview — auth, rate limits, two-step upload flow
- Endpoints — every
/api/v1/*route with examples - Pricing — upgrade to Developer & Automation