This workflow corresponds to n8n.io template #13542 — we link there as the canonical source.
This workflow follows the Agent → Agenttool recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "Gz17ZMdYF1sWpLHNl6sBW",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Suno Music Generation Chatbot",
"tags": [],
"nodes": [
{
"id": "e559b261-3def-4d04-9cfc-22d9109465d7",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
2928,
544
],
"parameters": {
"resume": "webhook",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 1.1
},
{
"id": "ef1aac81-1861-4b1b-b42d-699964fce8f5",
"name": "Split Out",
"type": "n8n-nodes-base.splitOut",
"position": [
1344,
1408
],
"parameters": {
"options": {},
"fieldToSplitOut": "response"
},
"typeVersion": 1
},
{
"id": "fd449974-c167-432f-bcff-2356a6594f48",
"name": "Loop Over Items",
"type": "n8n-nodes-base.splitInBatches",
"position": [
1568,
1408
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "d403377d-8282-4b61-8bc2-5a8a98bc467d",
"name": "When chat message received",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
944,
544
],
"parameters": {
"options": {
"responseMode": "lastNode"
}
},
"typeVersion": 1.4
},
{
"id": "88f039b5-ce10-4612-948f-590d4a353b02",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
2240,
768
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "4cfdc6cc-eb53-4681-b3fe-0fb02aece06d",
"name": "Simple Memory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
1200,
976
],
"parameters": {
"contextWindowLength": 10
},
"typeVersion": 1.3
},
{
"id": "7d42ebed-713f-4b48-b2a5-a785afd24612",
"name": "Google Gemini Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1504,
976
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "635dfa45-0c53-470a-b51a-92c9985e84bd",
"name": "Search songs",
"type": "n8n-nodes-gemini-search.geminiSearchToolTool",
"position": [
1296,
768
],
"parameters": {
"query": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Query', ``, 'string') }}",
"options": {},
"toolDescription": "Usa questo tool per cercare sul web i testi di una canzone gi\u00e0 scritta",
"enableUrlContext": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Enable_URL_Context_Tool', ``, 'boolean') }}",
"enableOrganizationContext": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Enable_Organization_Context', ``, 'boolean') }}"
},
"credentials": {
"geminiSearchApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "53456f2e-667b-4174-99b2-705871f26552",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
2368,
768
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"title\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n\t\t\"style\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n \"prompt\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n \"negativeTags\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n\t}\n}"
},
"typeVersion": 1.3
},
{
"id": "a17555ce-3f2e-4b0e-891b-d4a719d2e07e",
"name": "Songwriter",
"type": "@n8n/n8n-nodes-langchain.agentTool",
"position": [
1424,
768
],
"parameters": {
"text": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Prompt__User_Message_', ``, 'string') }}",
"options": {
"systemMessage": "You are a talented singer-songwriter with a poetic soul and a keen ear for melody and rhythm.\n\nWhen asked to write a song, you will generate original lyrics following these guidelines:\n\n- Structure the song with clearly labeled sections: [Verse 1], [Pre-Chorus] (optional), [Chorus], [Verse 2], [Bridge], [Outro], etc.\n- Adapt the style, tone, and language to the genre or mood requested (pop, rock, ballad, folk, R&B, etc.)\n- If no genre is specified, choose the one that best fits the theme provided\n- Use vivid imagery, metaphors, and emotional language to make the lyrics resonate\n- Ensure the chorus is catchy, memorable, and repeatable\n- Maintain a consistent rhyme scheme and syllabic flow suitable for singing\n- If a language is not specified, write in English by default\n\nOutput only the song lyrics with section labels. Do not add explanations or comments unless explicitly asked."
},
"toolDescription": "You are a singer-songwriter and when called upon you have to generate the lyrics of a song."
},
"typeVersion": 3
},
{
"id": "c72b7042-fc51-4b21-9355-5375c0b828ec",
"name": "Music Producer Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1168,
544
],
"parameters": {
"options": {
"systemMessage": "=You are a music production assistant specialized in collecting song information to generate music tracks.\n\nYour job is to gather the following details from the user before proceeding:\n\n1. **title** \u2013 The title of the song\n2. **style** \u2013 The musical style (e.g. pop, rock, jazz, electronic, folk, etc.)\n3. **negativeTags** \u2013 Styles or elements to AVOID in the song (e.g. rock, punk, aggressive, etc.)\n4. **prompt** \u2013 The song lyrics. You have two options:\n - If the user wants ORIGINAL lyrics: call the tool \"Cantautore\" to generate them\n - If the user wants lyrics from an EXISTING song: use the tool \"search song\" to find them on the web\n\nAsk for each piece of information conversationally, one step at a time if needed. Do not proceed until you have all four fields.\n\n---\n\nCRITICAL FORMATTING RULES for the \"prompt\" field (song lyrics):\n- NO line breaks or newline characters (\\n) \u2014 the entire lyrics must be on a single line\n- NO double quote characters (\") anywhere in the text\n- Use a space or a slash (/) to separate verses and sections if needed\n- The text must be safe to embed inside a JSON string variable without causing parsing errors\n\n---\n\nOnce you have collected ALL the required information, output ONLY the following JSON object and nothing else:\n\n{\n \"title\": {\n \"type\": \"string\"\n },\n \"style\": {\n \"type\": \"string\"\n },\n \"prompt\": {\n \"type\": \"string\"\n },\n \"negativeTags\": {\n \"type\": \"string\"\n }\n}\n\nReplace \"type\": \"string\" with the actual collected values. Do not include any explanation or additional text outside the JSON object."
},
"hasOutputParser": true
},
"typeVersion": 3.1
},
{
"id": "71b1c3ec-b6b6-438a-8f53-e36f3fab842a",
"name": "is Song?",
"type": "n8n-nodes-base.if",
"position": [
1632,
544
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "6b36f7ba-cca1-407f-b86a-184b1061d5aa",
"operator": {
"type": "string",
"operation": "startsWith"
},
"leftValue": "={{ $json.output }}",
"rightValue": "```json"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.3
},
{
"id": "93d5a3f7-6cd0-4848-94fe-60f33b177cac",
"name": "Parser",
"type": "n8n-nodes-base.code",
"position": [
1920,
528
],
"parameters": {
"jsCode": "for (const item of $input.all()) {\n \n try {\n let rawOutput = item.json.output;\n \n rawOutput = rawOutput\n .replace(/```json\\n?/gi, '')\n .replace(/```\\n?/g, '')\n .trim();\n \n rawOutput = rawOutput.replace(/\\\\'/g, \"'\");\n \n let parsedData = JSON.parse(rawOutput);\n \n const cleanData = parsedData.properties || parsedData;\n \n if (!cleanData.title || !cleanData.prompt) {\n throw new Error('Campi obbligatori mancanti: title e prompt');\n }\n \n item.json = {\n title: String(cleanData.title).trim(),\n style: cleanData.style ? String(cleanData.style).trim() : '',\n prompt: String(cleanData.prompt).trim(),\n negativeTags: cleanData.negativeTags ? String(cleanData.negativeTags).trim() : ''\n };\n \n } catch (error) {\n throw new Error('Errore nel parsing JSON: ' + error.message);\n }\n}\n\nreturn $input.all();"
},
"typeVersion": 2
},
{
"id": "cc8c15a6-a9c6-4505-8f38-7773589f6aac",
"name": "Fix Json Structure",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
2240,
544
],
"parameters": {
"text": "={{ JSON.stringify($json) }}",
"batching": {},
"messages": {
"messageValues": [
{
"message": "Based on the info you have... you have to transform it into a structured json"
}
]
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.9
},
{
"id": "a5ba81f7-09ce-42ea-ad5f-0f399cc260de",
"name": "Create song",
"type": "n8n-nodes-base.httpRequest",
"position": [
2704,
544
],
"parameters": {
"url": "https://api.kie.ai/api/v1/generate",
"method": "POST",
"options": {},
"jsonBody": "={\n \"model\": \"V4_5PLUS\",\n \"customMode\": true,\n \"instrumental\": false,\n \"title\": \"{{ $json.output.title }}\",\n \"callBackUrl\": \"{{ $execution.resumeUrl }}\",\n \"prompt\": \"{{ $json.output.prompt }}\",\n \"vocalGender\": \"m\",\n \"style\": \"{{ $json.output.style }}\",\n \"negativeTags\": \"{{ $json.output.negativeTags }}\",\n \"styleWeight\": 0.65,\n \"weirdnessConstraint\": 0.65,\n \"audioWeight\": 0.65,\n \"personaId\": \"\"\n}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth"
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "a41087c5-264b-47dc-9fd1-e8128fd17843",
"name": "Get response",
"type": "n8n-nodes-base.set",
"position": [
1120,
1408
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "ce1487dd-f2ac-496a-a7b1-8fb30f3487c5",
"name": "response",
"type": "array",
"value": "={{ $json.data.response.sunoData }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "69cc17b5-7c4c-4751-8cbc-d0b41ae2158d",
"name": "Get single song",
"type": "n8n-nodes-base.httpRequest",
"position": [
1792,
1344
],
"parameters": {
"url": "={{ $json.sourceStreamAudioUrl }}",
"options": {}
},
"typeVersion": 4.4
},
{
"id": "4b006a4f-930d-4d11-95f2-3733e499b094",
"name": "Get songs",
"type": "n8n-nodes-base.httpRequest",
"position": [
3184,
544
],
"parameters": {
"url": "=https://api.kie.ai/api/v1/generate/record-info ",
"options": {},
"sendQuery": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpBearerAuth",
"queryParameters": {
"parameters": [
{
"name": "taskId",
"value": "={{ $('Create song').item.json.data.taskId }}"
}
]
}
},
"credentials": {
"httpBearerAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "525bbc1a-8a10-47d6-88a7-4ce065148eea",
"name": "Upload song",
"type": "n8n-nodes-base.googleDrive",
"position": [
2016,
1408
],
"parameters": {
"name": "={{$now.format('yyyyLLddHHiiss')}}_{{ $binary.data.fileName }}",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"options": {},
"folderId": {
"__rl": true,
"mode": "list",
"value": "1iT2rs_A22QESeiTMH1cyk-zIO5xM8OYw",
"cachedResultUrl": "https://drive.google.com/drive/folders/1iT2rs_A22QESeiTMH1cyk-zIO5xM8OYw",
"cachedResultName": "Kie AI"
}
},
"credentials": {
"googleDriveOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 3
},
{
"id": "418ef426-743e-4766-a2de-b6349c3e292e",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
-448
],
"parameters": {
"width": 736,
"height": 784,
"content": "## Music Producer Chatbot using Gemini + Suno (via Kei AI) with Google Drive Upload\nThis workflow creates an **AI-powered chatbot** that generates **custom songs** through an interactive conversation, then uploads the results to Google Drive. \n\nThis workflow transforms n8n into a complete AI music production pipeline by combining:\n\n* Conversational AI\n* Structured data validation\n* Tool orchestration\n* External music generation API\n* Cloud automation\n\n### **How it works:**\n\nThis workflow orchestrates a full AI music production pipeline inside n8n using a conversational agent, structured validation, asynchronous API handling, and cloud storage. A Google Gemini-powered \u201cMusic Producer Agent\u201d interacts with the user to collect required inputs (title, genre, lyrics source, negative tags), dynamically calling tools for lyric generation or search as needed. The structured output is validated, cleaned, and enforced through strict JSON formatting before being sent to the [Kie.ai API](https://kie.ai?ref=188b79f5cb949c9e875357ac098e1ff5) for music generation via an asynchronous webhook callback. Once the API completes processing, the workflow resumes, retrieves generated tracks, loops through each result, downloads the audio files, and uploads them to Google Drive with properly formatted filenames. The architecture combines LLM agent logic, tool orchestration, and scalable async control flow.\n\n### **Setup steps:**\n\nConfigure three required API credentials: Google Gemini (for chat models), Gemini Search (for lyric lookup), and a [Kie.ai](https://kie.ai?ref=188b79f5cb949c9e875357ac098e1ff5) Bearer Token (for song creation and retrieval). Authenticate Google Drive OAuth2 in the upload node, verify the target folder ID, and ensure write permissions are correctly set. Expose the Wait node webhook publicly and register it as the callback URL in [Kie.ai](https://kie.ai?ref=188b79f5cb949c9e875357ac098e1ff5) settings to enable asynchronous completion handling. Optionally customize agent prompts, music generation parameters (e.g., styleWeight, weirdnessConstraint), vocal settings, or storage paths to fit your use case. After activation, test the workflow via chat input to validate conversational data collection, JSON formatting, API generation, and automated file upload to Drive.\n"
},
"typeVersion": 1
},
{
"id": "59302be0-3a7b-4166-8e53-66273a0ebe46",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
368
],
"parameters": {
"color": 7,
"width": 736,
"height": 768,
"content": "## STEP 1 - Chatbot\nA \"Music Producer Agent\" powered by Google Gemini engages with the user conversationally to gather all necessary song parameters."
},
"typeVersion": 1
},
{
"id": "0f2e9929-edf9-4ad9-bdf2-1072dc92c1b9",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1872,
368
],
"parameters": {
"color": 7,
"width": 672,
"height": 768,
"content": "## STEP2 - Validation & Formatting\nThe collected data passes through an IF condition checking for valid JSON format, then a Code node parses and cleans the JSON output. A \"Fix Json Structure\" node ensures proper formatting with strict rules (no line breaks, no double quotes)"
},
"typeVersion": 1
},
{
"id": "9cbb3d90-6a82-43eb-a0ff-de1fae61bcac",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
2576,
368
],
"parameters": {
"color": 7,
"width": 784,
"height": 768,
"content": "## STEP 3 - Song Generation\nThe formatted data is sent to the [Kie.ai API](https://kie.ai?ref=188b79f5cb949c9e875357ac098e1ff5) (HTTP Request node) which generates the actual music track. The workflow includes a callback URL for asynchronous processing."
},
"typeVersion": 1
},
{
"id": "13f80c20-bae4-4f93-bb1a-99cb6ec8fa8d",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
1200
],
"parameters": {
"color": 7,
"width": 1120,
"height": 560,
"content": "## STEP 4 - Process Results\nThe response is split out, and a Loop Over Items node processes each generated song individually.Upload songs to Google Drive"
},
"typeVersion": 1
},
{
"id": "b68492f7-425f-487e-b634-0fb3603c6836",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
1888,
-400
],
"parameters": {
"color": 7,
"width": 736,
"height": 736,
"content": "## MY NEW YOUTUBE CHANNEL\n\ud83d\udc49 [Subscribe to my new **YouTube channel**](https://youtube.com/@n3witalia). Here I\u2019ll share videos and Shorts with practical tutorials and **FREE templates for n8n**.\n\n[](https://youtube.com/@n3witalia)"
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "6868ebf5-f9db-479a-be93-8c5b83920467",
"connections": {
"Wait": {
"main": [
[
{
"node": "Get songs",
"type": "main",
"index": 0
}
]
]
},
"Parser": {
"main": [
[
{
"node": "Fix Json Structure",
"type": "main",
"index": 0
}
]
]
},
"is Song?": {
"main": [
[
{
"node": "Parser",
"type": "main",
"index": 0
}
]
]
},
"Get songs": {
"main": [
[
{
"node": "Get response",
"type": "main",
"index": 0
}
]
]
},
"Split Out": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Songwriter": {
"ai_tool": [
[
{
"node": "Music Producer Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Create song": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Upload song": {
"main": [
[
{
"node": "Loop Over Items",
"type": "main",
"index": 0
}
]
]
},
"Get response": {
"main": [
[
{
"node": "Split Out",
"type": "main",
"index": 0
}
]
]
},
"Search songs": {
"ai_tool": [
[
{
"node": "Music Producer Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Simple Memory": {
"ai_memory": [
[
{
"node": "Music Producer Agent",
"type": "ai_memory",
"index": 0
},
{
"node": "Songwriter",
"type": "ai_memory",
"index": 0
}
]
]
},
"Get single song": {
"main": [
[
{
"node": "Upload song",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Items": {
"main": [
[],
[
{
"node": "Get single song",
"type": "main",
"index": 0
}
]
]
},
"Fix Json Structure": {
"main": [
[
{
"node": "Create song",
"type": "main",
"index": 0
}
]
]
},
"Music Producer Agent": {
"main": [
[
{
"node": "is Song?",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "Music Producer Agent",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Fix Json Structure",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Fix Json Structure",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Google Gemini Chat Model1": {
"ai_languageModel": [
[
{
"node": "Songwriter",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"When chat message received": {
"main": [
[
{
"node": "Music Producer Agent",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
geminiSearchApigoogleDriveOAuth2ApigooglePalmApihttpBearerAuth
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow creates an AI-powered chatbot that generates custom songs through an interactive conversation, then uploads the results to Google Drive.
Source: https://n8n.io/workflows/13542/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This comprehensive workflow automates the complete financial document processing pipeline using AI. Upload invoices via chat, drop expense receipts into a folder, or add bank statements - the system a
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
This Chatbot automates the process of discovering job openings and generating tailored job application emails.
This project is an automation workflow that generates a personalized resume and cover letter for each job listing. Generates an HTML resume from your data. Hosts it live on GitHub Pages. Converts it t
Perfect for educators, consultants, and content creators who record sessions and want to repurpose them into social media posts, videos, and images without manual work. Chat interface triggers the AI