Skip to main content

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

  1. A Songs2VID account with YouTube connected (Google OAuth with YouTube scopes)
  2. Developer & Automation on songs2vid.com (or a self-hosted instance)
  3. An n8n instance (Cloud or self-hosted) that can reach Songs2VID over HTTPS

Step 1 — Install the Songs2VID community node

  1. Open n8n → SettingsCommunity nodes (or Settingsnpm depending on your n8n version)
  2. Install package:
n8n-nodes-songs2vid
  1. Restart n8n if prompted
  2. 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:

ActionMethodPath
UploadPOST/api/v1/upload
Start renderPOST/api/v1/render
Poll statusGET/api/v1/jobs/:id
Manage keysGET/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

  1. Sign in at songs2vid.com
  2. Open Dashboard → Settings
  3. Under API access, create a key (Developer plan required)
  4. 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).

caution

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

  1. In any Songs2VID node → Credential to connect withCreate new
  2. Paste your API key
  3. Set Base URL to https://songs2vid.com (or your self-hosted origin, no trailing slash)

HTTP Request (Header Auth)

  1. Credentials → Header Auth
  2. Name: Authorization
  3. Value: Bearer s2yt_live_... (include the word Bearer and a space)
  4. 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

  1. Trigger — Google Drive File Created / Dropbox File Created (filter .mp3 / .wav / .flac)
  2. Download the audio binary into the workflow
  3. Upload coverPOST /api/v1/upload multipart: file = cover image, type=image
    Save path from the JSON response
  4. Upload audio — same endpoint with type=audio
    Response may include audioTags.title / audioTags.artist for metadata
  5. Create renderPOST /api/v1/render with 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
}
}
]
}
  1. 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
  2. On success, the webhook (or poll response) includes youtubeVideoId — post that to Discord, Notion, etc.
tip

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)

  1. Add an n8n Webhook node (POST), path e.g. songs2vid-complete
  2. Activate the workflow and copy the Production URL
  3. Pass that URL as webhookUrl when calling /api/v1/render
  4. 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"
}
eventMeaning
job.item.completedOne track finished
job.item.failedOne track failed (error set)
job.completedAll items succeeded
job.failedAll items failed
job.partialMix 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.

  1. Create Header Auth credentials (Authorization = Bearer s2yt_live_…)
  2. Replace credential placeholders on the HTTP Request nodes
  3. Wire binary inputs (cover, audio) from your Drive/Dropbox download nodes
  4. Set the Webhook node’s Production URL as webhookUrl on Create Render (or use a Wait node + poll statusUrl)

Download workflow JSON

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)

PlanREST APIMonthly rendersAudio encode
FreeNo3 (Web UI)192 kbps AAC
Independent Producer (€7)No — 40330 (Web UI)320 kbps
Developer & Automation (€15)Yes60 (UI + API)320 kbps · priority queue
EnterpriseYesCustom320 kbps · priority queue

Common API responses:

StatusMeaning
401Missing/invalid API key
403"REST API access requires the Developer & Automation plan." or YouTube not connected
402Monthly quota / credits exhausted
429Rate 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