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 →
{
"name": "Voice-Agent Orchestrator (Spec Example - import into n8n and adapt secrets)",
"nodes": [
{
"parameters": {
"path": "voice-agent",
"options": {}
},
"id": "Webhook_VoiceAgent",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1
},
{
"parameters": {
"authentication": "none",
"options": {},
"url": "={{$json[\"audio\"] ? $env[\"RUNPOD_STT_ENDPOINT_URL\"] : ''}}",
"method": "POST",
"bodyParametersUi": {
"parameter": []
},
"headersUi": {
"parameter": []
}
},
"id": "STT",
"name": "STT (RunPod)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1
},
{
"parameters": {
"functionCode": "// Derive user_text from text or STT result; validate secret\nconst incomingSecret = $json[\"secret\"];\nif (incomingSecret !== $env[\"ORCHESTRATOR_WEBHOOK_SECRET\"]) {\n return [{ json: { error: \"unauthorized\" }, pairedItem: { item: 0 }, $continue: false }];\n}\n\nconst hasAudio = !!$json[\"audio\"];\nlet transcript_text = \"\";\nif (hasAudio && $items(\"STT\")[0]) {\n transcript_text = $items(\"STT\")[0].json.transcript || \"\";\n}\nconst text = $json[\"text\"] || transcript_text;\nif (!text) {\n return [{ json: { error: \"no_input\" } }];\n}\n\nreturn [{\n json: {\n conversation_id: $json[\"conversation_id\"] || null,\n user_text: text,\n transcript_text,\n }\n}];"
},
"id": "DeriveUserText",
"name": "Derive User Text & Validate Secret",
"type": "n8n-nodes-base.function",
"typeVersion": 1
},
{
"parameters": {
"url": "={{$env[\"SUPABASE_URL_VOICE_AGENT\"]}}/rest/v1/rpc/get_or_create_conversation",
"method": "POST",
"authentication": "none",
"sendHeaders": true,
"headers": {
"X-Client-Info": "voice-agent-n8n",
"apikey": "={{$env[\"SUPABASE_SERVICE_ROLE_KEY_VOICE_AGENT\"]}}",
"Content-Type": "application/json"
},
"sendBody": true,
"bodyParametersJson": "={{ { conversation_id: $json[\"conversation_id\"] } }}"
},
"id": "Conversation",
"name": "Get/Create Conversation",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1
},
{
"parameters": {
"url": "https://openrouter.ai/api/v1/chat/completions",
"method": "POST",
"authentication": "none",
"sendHeaders": true,
"headers": {
"Authorization": "={{\"Bearer \" + $env[\"OPENROUTER_API_KEY\"]}}",
"Content-Type": "application/json"
},
"sendBody": true,
"bodyParametersJson": "={{ { model: \"cognitivecomputations/dolphin-mistral-24b-venice-edition:free\", messages: [ { role: \"user\", content: $json[\"user_text\"] } ] } }}"
},
"id": "LLM",
"name": "OpenRouter Chat",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1
},
{
"parameters": {
"url": "={{$env[\"RUNPOD_TTS_ENDPOINT_URL\"]}}",
"method": "POST",
"authentication": "none",
"sendHeaders": true,
"headers": {
"Authorization": "={{\"Bearer \" + $env[\"RUNPOD_API_KEY\"]}}",
"Content-Type": "application/json"
},
"sendBody": true,
"bodyParametersJson": "={{ { voice: \"Katie\", text: $json[\"assistant_response_text\"] || $items(\"LLM\")[0].json.choices[0].message.content } }}"
},
"id": "TTS",
"name": "RunPod TTS",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1
},
{
"parameters": {
"functionCode": "// Shape final response according to contract\nconst convoId = $items(\"Conversation\")[0]?.json?.conversation_id || $json[\"conversation_id\"] || null;\nconst transcript_text = $items(\"DeriveUserText\")[0]?.json?.transcript_text || \"\";\nconst assistant = $items(\"LLM\")[0]?.json?.choices?.[0]?.message?.content || \"\";\nconst tts = $items(\"TTS\")[0]?.json?.tts_audio_url || $items(\"TTS\")[0]?.json?.audio || null;\n\nreturn [{\n json: {\n conversation_id: convoId,\n transcript_text,\n assistant_response_text: assistant,\n tts_audio_url: tts\n }\n}];"
},
"id": "ShapeResponse",
"name": "Shape Response",
"type": "n8n-nodes-base.function",
"typeVersion": 1
},
{
"parameters": {
"responseMode": "lastNode",
"options": {}
},
"id": "Respond",
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1
}
],
"connections": {
"Webhook_VoiceAgent": {
"main": [
[
{
"node": "STT",
"type": "main",
"index": 0
},
{
"node": "DeriveUserText",
"type": "main",
"index": 0
}
]
]
},
"STT": {
"main": [
[
{
"node": "DeriveUserText",
"type": "main",
"index": 0
}
]
]
},
"DeriveUserText": {
"main": [
[
{
"node": "Conversation",
"type": "main",
"index": 0
}
]
]
},
"Conversation": {
"main": [
[
{
"node": "LLM",
"type": "main",
"index": 0
}
]
]
},
"LLM": {
"main": [
[
{
"node": "TTS",
"type": "main",
"index": 0
}
]
]
},
"TTS": {
"main": [
[
{
"node": "ShapeResponse",
"type": "main",
"index": 0
}
]
]
},
"ShapeResponse": {
"main": [
[
{
"node": "Respond",
"type": "main",
"index": 0
}
]
]
}
}
}
About this workflow
Voice-Agent Orchestrator (Spec Example - import into n8n and adapt secrets). Uses httpRequest, respondToWebhook. Webhook trigger; 8 nodes.
Source: https://github.com/Jblast94/ai-workstation/blob/07cc37ffdc6591a6366c0f5987fba1e2dd4a25fb/n8n-workflows/voice_chat.json — original creator credit. Request a take-down →