AutomationFlowsGeneral › Text to speech Voice clone using Zonos via API(local storage)

Text to speech Voice clone using Zonos via API(local storage)

Text to speech Voice clone using Zonos via API(local storage). Uses readWriteFile, httpRequest, respondToWebhook, stickyNote. Webhook trigger; 18 nodes.

Webhook trigger★★★★☆ complexity18 nodesRead Write FileHttp Request
General Trigger: Webhook Nodes: 18 Complexity: ★★★★☆

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 →

Download .json
{
  "name": "Text to speech Voice clone using Zonos via API(local storage)",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "voice-clone",
        "options": {}
      },
      "id": "76f2c278-c769-443f-8aa5-541713323b51",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        -560,
        60
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "string": [
            {
              "name": "text",
              "value": "={{ $json.body.text || 'Hello, this is a test of voice cloning!' }}"
            },
            {
              "name": "speaking_rate",
              "value": "={{ $json.body.speaking_rate || 15 }}"
            },
            {
              "name": "language_iso_code",
              "value": "={{ $json.body.language_iso_code || 'en-us' }}"
            },
            {
              "name": "mime_type",
              "value": "={{ $json.body.mime_type || 'audio/wav'}}"
            },
            {
              "name": "sample_voice_path",
              "value": "={{ $json.body.sample_voice_path }}"
            },
            {
              "name": "model",
              "value": "={{ $json.body.model || 'zonos-v0.1-transformer' }}"
            },
            {
              "name": "output_path",
              "value": "={{ $json.body.output_path }}"
            }
          ],
          "number": [
            {
              "name": "happiness",
              "value": "={{ $json.body.emotion.happiness || 0.6}}"
            },
            {
              "name": "neutral",
              "value": "={{ $json.body.emotion.neutral || 0.6}}"
            },
            {
              "name": "sadness",
              "value": "={{ $json.body.emotion.sadness || 0.05}}"
            },
            {
              "name": "disgust",
              "value": "={{ $json.body.emotion.disgust || 0.05}}"
            },
            {
              "name": "fear",
              "value": "={{ $json.body.emotion.fear || 0.05}}"
            },
            {
              "name": "surprise",
              "value": "={{ $json.body.emotion.surprise || 0.05}}"
            },
            {
              "name": "anger",
              "value": "={{ $json.body.emotion.anger || 0.05}}"
            },
            {
              "name": "other",
              "value": "={{ $json.body.emotion.other || 0.5}}"
            }
          ]
        },
        "options": {}
      },
      "id": "0772d98e-7cd8-487d-a3db-26c3d6d50304",
      "name": "Set Clone Parameters",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        -340,
        60
      ]
    },
    {
      "parameters": {
        "fileSelector": "={{ $json.sample_voice_path }}",
        "options": {
          "mimeType": "={{ $json.mime_type }}",
          "dataPropertyName": ""
        }
      },
      "id": "b3dc1528-90d7-4397-83e6-18c5f2dbf495",
      "name": "Read Sample Voice",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        40,
        60
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "file-exists-check",
              "leftValue": "={{ $ifEmpty($binary.data, false) !== false }}\n",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "86e0f9bf-ccec-4bb1-b9ce-7d1b94fdfcca",
      "name": "Check File Loaded",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        560,
        -80
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "http://api.zyphra.com/v1/audio/text-to-speech",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-API-Key",
              "value": "put-your-API-key-here"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={\n  \"text\": \"{{ $('Set Clone Parameters').item.json.text }}\",\n  \"speaking_rate\": {{ parseFloat($('Set Clone Parameters').item.json.speaking_rate) }},\n  \"language_iso_code\": \"{{ $('Set Clone Parameters').item.json.language_iso_code }}\",\n  \"mime_type\": \"{{ $('Set Clone Parameters').item.json.mime_type }}\",\n  \"model\": \"{{ $('Set Clone Parameters').item.json.model }}\",\n  \"emotion\": {\n    \"happiness\": {{ $('Set Clone Parameters').item.json.happiness }},\n    \"neutral\": {{ $('Set Clone Parameters').item.json.neutral }},\n    \"sadness\": {{ $('Set Clone Parameters').item.json.sadness }},\n    \"disgust\": {{ $('Set Clone Parameters').item.json.disgust }},\n    \"fear\": {{ $('Set Clone Parameters').item.json.fear }},\n    \"surprise\": {{ $('Set Clone Parameters').item.json.surprise }},\n    \"anger\": {{ $('Set Clone Parameters').item.json.anger }},\n    \"other\": {{ $('Set Clone Parameters').item.json.other }}\n  },\n  \"speaker_audio\": \"{{ $json.base64_content }}\"\n}\n",
        "options": {
          "response": {
            "response": {}
          }
        }
      },
      "id": "2980ae94-30e3-4065-8d2c-b607c73c3c5f",
      "name": "Call Zyphra Clone API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.1,
      "position": [
        980,
        -120
      ],
      "onError": "continueErrorOutput"
    },
    {
      "parameters": {
        "operation": "write",
        "fileName": "={{ $('Set Clone Parameters').item.json.output_path }}{{ 'cloned_voice_' + new Date().getTime() + '.webm' }}",
        "options": {}
      },
      "id": "0f896518-98ce-4176-8977-1f0380b54469",
      "name": "Save Cloned Audio",
      "type": "n8n-nodes-base.readWriteFile",
      "typeVersion": 1,
      "position": [
        1440,
        0
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "true"
            },
            {
              "name": "message",
              "value": "Voice cloning completed successfully!"
            },
            {
              "name": "filename",
              "value": "={{ $json.fileName }}"
            },
            {
              "name": "text_processed",
              "value": "={{ $('Set Clone Parameters').item.json.text }}"
            },
            {
              "name": "sample_voice_used",
              "value": "={{ $('Set Clone Parameters').item.json.sample_voice_path }}"
            }
          ]
        },
        "options": {}
      },
      "id": "02f1b766-953a-4834-8d93-4cc596ffe77c",
      "name": "Success Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1660,
        0
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "false"
            },
            {
              "name": "error_type",
              "value": "file_not_found"
            },
            {
              "name": "message",
              "value": "Sample voice file could not be read from: {{ $('Set Clone Parameters').item.json.sample_voice_path }}"
            },
            {
              "name": "suggestion",
              "value": "Please check the file path and ensure the file exists"
            }
          ]
        },
        "options": {}
      },
      "id": "7da98d65-08e3-4d6e-9957-ead2c8f1133f",
      "name": "File Error Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        860,
        480
      ]
    },
    {
      "parameters": {
        "values": {
          "string": [
            {
              "name": "success",
              "value": "false"
            },
            {
              "name": "error_type",
              "value": "api_error"
            },
            {
              "name": "message",
              "value": "Voice cloning API request failed"
            },
            {
              "name": "error_details",
              "value": "={{ $json.error ? $json.error.message : 'Unknown API error' }}"
            },
            {
              "name": "suggestion",
              "value": "Please check your API key and try again"
            }
          ]
        },
        "options": {}
      },
      "id": "44006f98-4241-436d-b8cf-1c586271a35a",
      "name": "API Error Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1100,
        480
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json }}",
        "options": {}
      },
      "id": "e2c14808-e209-4daf-93dd-9c7049261e60",
      "name": "Webhook Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        1880,
        100
      ]
    },
    {
      "parameters": {
        "content": "\ud83c\udf99\ufe0f VOICE CLONING WORKFLOW - ZONOS API\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\nThis workflow clones voices using Zyphra's Zonos API\n\ud83d\udccb Input: Text + sample voice file + parameters  \n\ud83c\udfb5 Output: Generated audio file with cloned voice\n\u26a1 Trigger: Webhook POST to /voice-clone endpoint\n\nBasic setup and use:\nConfigure your Zyphra API key in the \"Call Zyphra Clone API\" node under Header parameters \u2192 X-API-Key header parameter\n\nEnsure your sample voice files are accessible at the paths you'll specify\n\nTest the webhook endpoint is accessible\n\nSend valid POST request to your webhook\n",
        "height": 340,
        "width": 780,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -960,
        -1200
      ],
      "id": "8268fd4a-fd84-4462-9ad1-9af8152d0cf3",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "jsCode": "// Get binary data from previous node\nconst binaryData = $input.first().binary?.data;\n\nif (!binaryData) {\n  throw new Error(\"No binary data found\");\n}\n\n// Binary data in n8n is already base64 encoded\nconst base64String = binaryData.data;\n\nreturn {\n  json: {\n    base64_content: base64String,\n    // Add other fields as needed\n  }\n};\n"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        400,
        -80
      ],
      "id": "cdbb775f-8408-43a9-89b1-1039315c6678",
      "name": "Base64 convertor"
    },
    {
      "parameters": {
        "content": "\ud83d\udce5 REQUIRED WEBHOOK PARAMETERS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\u2705 text: Text to synthesize\n\u2705 sample_voice_path: Path to your voice sample file  \n\u2705 output_path: Where to save generated audio\n\n\ud83d\udd27 OPTIONAL PARAMETERS (with defaults):\n\u2022 speaking_rate: 15 (speech speed)\n\u2022 language_iso_code: \"en-us\" \n\u2022 mime_type: \"audio/wav\"\n\u2022 model: \"zonos-v0.1-transformer\"\n\u2022 emotion: Various emotion levels (0-1 scale)\n",
        "height": 1020,
        "width": 780,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -960,
        -740
      ],
      "id": "88b0131c-f93b-4593-9c88-ed4f91b74c88",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "\ud83d\udd10 API KEY CONFIGURATION REQUIRED!\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n1\ufe0f\u20e3 Register account at: playground.zyphra.com  \n2\ufe0f\u20e3 Get API key from: playground.zyphra.com/settings/api-keys\n3\ufe0f\u20e3 Add key to \"Call Zyphra Clone API\" node\n   \u2192 Header parameters section\n   \u2192 Header: X-API-Key\n   \u2192 Value: [Your API Key]\n\n\u274c Workflow will fail without proper API key setup!\n",
        "height": 460,
        "width": 480,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        820,
        -380
      ],
      "id": "3be24130-054d-4435-9aac-d5ad9c7b92d0",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "\ud83d\udcc1 FILE HANDLING PROCESS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n1. Read sample voice from specified path\n2. Convert audio file to base64 format\n3. Validate file loaded successfully  \n\n\u26a0\ufe0f IMPORTANT: Ensure sample voice file exists \n   at the path specified in sample_voice_path!\n",
        "height": 560,
        "width": 740,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -280
      ],
      "id": "08780e5a-4663-4a0d-aeff-69f4059495ce",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "\ud83d\udea8 ERROR HANDLING & RESPONSES\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\u2705 SUCCESS: Returns success message + filename\n\u274c FILE_NOT_FOUND: Sample voice file missing/unreadable\n\u274c API_ERROR: Zyphra API request failed\n\u274c AUTH_ERROR: Invalid or missing API key\n\nAll errors return JSON with error details and suggestions\n",
        "height": 480,
        "width": 480,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        820,
        180
      ],
      "id": "223743b2-aeb2-45cc-8094-9bef48fc815e",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "\ud83c\udfb5 OUTPUT DETAILS\n\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n\ud83d\udccd Location: [output_path]/cloned_voice_[timestamp].webm\n\ud83d\udcca Format: Specified by mime_type parameter\n\ud83d\udd50 Filename: Auto-generated with timestamp\n\ud83d\udcdd Response: JSON with success status and file details\n\nGenerated audio ready for download!\n",
        "height": 540,
        "width": 660,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1400,
        -220
      ],
      "id": "939714c2-9feb-4ccb-b3b6-fd133c65c56a",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "content": "POST http://localhost:5678/webhook-test/voice-clone\nContent-Type: application/json\n\n{\n  \"text\": \"Hello there, kupo! This voice sounds just like the sample!\",\n  \"speaking_rate\": 18,\n  \"sample_voice_path\": \"/data/output/sampleVoice.wav\",\n  \"output_path\": \"/data/output/\",\n  \"language_iso_code\": \"en-us\",\n  \"mime_type\": \"audio/wav\",\n  \"model\": \"zonos-v0.1-transformer\",\n  \"emotion\": {\n    \"happiness\": 0.8,\n    \"neutral\": 0.3,\n    \"sadness\": 0.05,\n    \"disgust\": 0.05,\n    \"fear\": 0.05,\n    \"surprise\": 0.05,\n    \"anger\": 0.05,\n    \"other\": 0.5\n  }\n}\n",
        "height": 440,
        "width": 700,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -940,
        -440
      ],
      "id": "0a90485e-417a-415e-a9a4-f128aea6b9f1",
      "name": "Sticky Note6"
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Set Clone Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Clone Parameters": {
      "main": [
        [
          {
            "node": "Read Sample Voice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Sample Voice": {
      "main": [
        [
          {
            "node": "Base64 convertor",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "File Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check File Loaded": {
      "main": [
        [
          {
            "node": "Call Zyphra Clone API",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "File Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call Zyphra Clone API": {
      "main": [
        [
          {
            "node": "Save Cloned Audio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "API Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Cloned Audio": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "File Error Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "API Error Response": {
      "main": [
        [
          {
            "node": "Webhook Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Base64 convertor": {
      "main": [
        [
          {
            "node": "Check File Loaded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c4a644b3-3029-47ed-9dad-6396d22a9841",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "hqMRsze38RaTmgQh",
  "tags": []
}

About this workflow

Text to speech Voice clone using Zonos via API(local storage). Uses readWriteFile, httpRequest, respondToWebhook, stickyNote. Webhook trigger; 18 nodes.

Source: https://gitlab.com/Tiartyos/n8n-workflows/-/blob/master/workflows/zyphry-zonos-api/workflow.json — original creator credit. Request a take-down →

More General workflows → · Browse all categories →