This workflow follows the Gmail → Google Sheets 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 →
{
"name": "Sales Voice Agent - ElevenLabs + n8n",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "elevenlabs-tool",
"responseMode": "lastNode",
"options": {}
},
"id": "webhook-mid-call",
"name": "Mid-Call Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "elevenlabs-postcall",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-postcall",
"name": "Post-Call Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
700
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "condition-calendar",
"leftValue": "={{ $json.body.action }}",
"rightValue": "check_calendar",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-action-router",
"name": "Route by Action",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
480,
300
]
},
{
"parameters": {
"method": "GET",
"url": "https://www.googleapis.com/calendar/v3/calendars/primary/freeBusy",
"authentication": "genericCredentialType",
"genericAuthType": "oAuth2Api",
"options": {},
"headerParameters": {
"parameters": []
},
"queryParameters": {
"parameters": []
}
},
"id": "check-calendar",
"name": "Check Calendar Availability",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
720,
200
],
"notes": "Replace with your actual calendar API call. This is a placeholder \u2014 connect Google Calendar, Cal.com, or Calendly."
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ result: 'Available times: Monday 2pm, Tuesday 10am, Wednesday 3pm. Which works best for you?' }) }}",
"options": {}
},
"id": "respond-calendar",
"name": "Respond - Calendar",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
960,
200
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ result: 'I can help with that. Let me look into it and have a specialist follow up with you.' }) }}",
"options": {}
},
"id": "respond-default",
"name": "Respond - Default",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
720,
420
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ status: 'received' }) }}",
"options": {}
},
"id": "respond-postcall-ok",
"name": "Respond 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
480,
700
]
},
{
"parameters": {
"model": "gpt-4o",
"messages": {
"values": [
{
"role": "system",
"content": "You are a lead qualification analyst. Analyze the following sales call transcript and return a JSON object with these fields:\n- qualification_status: \"hot\", \"warm\", or \"cold\"\n- pain_points: array of strings\n- budget_range: string or null\n- timeline: string or null\n- next_steps: string\n- prospect_email: string or null\n- prospect_name: string or null\n- summary: 2-3 sentence summary of the call\n\nReturn ONLY valid JSON, no other text."
},
{
"role": "user",
"content": "=Analyze this sales call transcript:\n\n{{ $json.body.transcript || $json.body.data?.transcript || 'No transcript available' }}"
}
]
},
"options": {
"temperature": 0.3
}
},
"id": "analyze-transcript",
"name": "Analyze Call Transcript",
"type": "@n8n/n8n-nodes-langchain.openAi",
"typeVersion": 1.8,
"position": [
480,
900
],
"notes": "Configure your OpenAI API credentials here. Uses GPT-4o to analyze the call transcript and qualify the lead."
},
{
"parameters": {
"jsCode": "// Parse the AI analysis and prepare data for downstream nodes\nconst aiResponse = $input.first().json;\nlet analysis;\n\ntry {\n // Handle different response shapes from OpenAI node\n const content = aiResponse.message?.content || aiResponse.choices?.[0]?.message?.content || aiResponse.text || '{}';\n analysis = JSON.parse(content);\n} catch (e) {\n analysis = {\n qualification_status: 'warm',\n pain_points: ['Unable to parse transcript'],\n budget_range: null,\n timeline: null,\n next_steps: 'Manual review needed',\n prospect_email: null,\n prospect_name: null,\n summary: 'Call transcript could not be automatically analyzed. Please review manually.'\n };\n}\n\n// Add metadata\nanalysis.call_date = new Date().toISOString();\nanalysis.agent_id = $('Post-Call Webhook').first().json.body?.agent_id || 'unknown';\nanalysis.call_duration = $('Post-Call Webhook').first().json.body?.call_duration || null;\n\nreturn [{ json: analysis }];"
},
"id": "parse-analysis",
"name": "Parse AI Analysis",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
720,
900
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "condition-hot",
"leftValue": "={{ $json.qualification_status }}",
"rightValue": "hot",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "if-hot-lead",
"name": "Is Hot Lead?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
960,
900
]
},
{
"parameters": {
"sendTo": "={{ $json.prospect_email || 'YOUR_SALES_TEAM_EMAIL@company.com' }}",
"subject": "=Hot Lead: {{ $json.prospect_name || 'New Prospect' }} - Follow Up ASAP",
"emailType": "text",
"message": "=Hi {{ $json.prospect_name || 'there' }},\n\nGreat speaking with you today! As discussed, I'd love to set up a more detailed conversation with one of our specialists.\n\nHere's a quick recap:\n{{ $json.summary }}\n\nNext steps: {{ $json.next_steps }}\n\nLooking forward to connecting again soon!\n\nBest regards,\n[Your Company Name]"
},
"id": "send-hot-lead-email",
"name": "Send Hot Lead Follow-Up",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1200,
800
],
"notes": "Connect your Gmail credentials. This sends a personalized follow-up email to hot leads."
},
{
"parameters": {
"sendTo": "YOUR_SALES_TEAM_EMAIL@company.com",
"subject": "=Lead Update: {{ $json.prospect_name || 'Unknown' }} - {{ $json.qualification_status }}",
"emailType": "text",
"message": "=New lead qualification result:\n\nName: {{ $json.prospect_name || 'Unknown' }}\nStatus: {{ $json.qualification_status }}\nPain Points: {{ ($json.pain_points || []).join(', ') }}\nBudget: {{ $json.budget_range || 'Not discussed' }}\nTimeline: {{ $json.timeline || 'Not discussed' }}\nNext Steps: {{ $json.next_steps }}\n\nCall Summary:\n{{ $json.summary }}\n\nCall Date: {{ $json.call_date }}\nDuration: {{ $json.call_duration || 'Unknown' }}"
},
"id": "notify-team",
"name": "Notify Sales Team",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1200,
1020
],
"notes": "Sends a summary to your sales team for all leads (warm and cold)."
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_GOOGLE_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Sheet1",
"mode": "list"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Date": "={{ $json.call_date }}",
"Name": "={{ $json.prospect_name || 'Unknown' }}",
"Email": "={{ $json.prospect_email || '' }}",
"Status": "={{ $json.qualification_status }}",
"Pain Points": "={{ ($json.pain_points || []).join(', ') }}",
"Budget": "={{ $json.budget_range || '' }}",
"Timeline": "={{ $json.timeline || '' }}",
"Next Steps": "={{ $json.next_steps }}",
"Summary": "={{ $json.summary }}"
}
},
"options": {}
},
"id": "log-to-sheets",
"name": "Log to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
960,
1140
],
"notes": "Logs every call result to a Google Sheet for tracking. Replace YOUR_GOOGLE_SHEET_ID with your actual sheet ID."
},
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 1
}
]
}
},
"id": "schedule-trigger",
"name": "Hourly Check for New Leads",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
1500
]
},
{
"parameters": {
"operation": "read",
"documentId": {
"__rl": true,
"value": "YOUR_GOOGLE_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Leads",
"mode": "list"
},
"filters": {
"conditions": [
{
"condition": "equal",
"value1": "={{ $json.Status }}",
"value2": "new"
}
]
},
"options": {}
},
"id": "read-new-leads",
"name": "Read New Leads",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
480,
1500
],
"notes": "Reads leads with status 'new' from your Leads sheet. Create a sheet with columns: Name, Email, Phone, Company, Source, Status"
},
{
"parameters": {
"batchSize": 1,
"options": {
"reset": false
}
},
"id": "batch-leads",
"name": "Process One at a Time",
"type": "n8n-nodes-base.splitInBatches",
"typeVersion": 3,
"position": [
720,
1500
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.elevenlabs.io/v1/convai/conversations",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"agent_id\": \"YOUR_AGENT_ID\",\n \"dynamic_variables\": {\n \"lead_name\": \"{{ $json.Name }}\",\n \"company_name\": \"{{ $json.Company }}\",\n \"lead_source\": \"{{ $json.Source }}\"\n }\n}",
"options": {}
},
"id": "initiate-call",
"name": "Initiate ElevenLabs Call",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
960,
1500
],
"notes": "Calls the ElevenLabs API to start a conversation. Set your API key in the HTTP Header Auth credential (header name: xi-api-key)."
},
{
"parameters": {
"options": {
"waitBetweenBatches": 30000
}
},
"id": "wait-between-calls",
"name": "Wait 30s Between Calls",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1200,
1500
]
},
{
"parameters": {},
"id": "noop-start",
"name": "Start",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
40,
300
]
}
],
"connections": {
"Mid-Call Webhook": {
"main": [
[
{
"node": "Route by Action",
"type": "main",
"index": 0
}
]
]
},
"Route by Action": {
"main": [
[
{
"node": "Check Calendar Availability",
"type": "main",
"index": 0
}
],
[
{
"node": "Respond - Default",
"type": "main",
"index": 0
}
]
]
},
"Check Calendar Availability": {
"main": [
[
{
"node": "Respond - Calendar",
"type": "main",
"index": 0
}
]
]
},
"Post-Call Webhook": {
"main": [
[
{
"node": "Respond 200 OK",
"type": "main",
"index": 0
},
{
"node": "Analyze Call Transcript",
"type": "main",
"index": 0
}
]
]
},
"Analyze Call Transcript": {
"main": [
[
{
"node": "Parse AI Analysis",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Analysis": {
"main": [
[
{
"node": "Is Hot Lead?",
"type": "main",
"index": 0
},
{
"node": "Log to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Is Hot Lead?": {
"main": [
[
{
"node": "Send Hot Lead Follow-Up",
"type": "main",
"index": 0
}
],
[
{
"node": "Notify Sales Team",
"type": "main",
"index": 0
}
]
]
},
"Hourly Check for New Leads": {
"main": [
[
{
"node": "Read New Leads",
"type": "main",
"index": 0
}
]
]
},
"Read New Leads": {
"main": [
[
{
"node": "Process One at a Time",
"type": "main",
"index": 0
}
]
]
},
"Process One at a Time": {
"main": [
[
{
"node": "Initiate ElevenLabs Call",
"type": "main",
"index": 0
}
]
]
},
"Initiate ElevenLabs Call": {
"main": [
[
{
"node": "Wait 30s Between Calls",
"type": "main",
"index": 0
}
]
]
},
"Wait 30s Between Calls": {
"main": [
[
{
"node": "Process One at a Time",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
{
"name": "Sales",
"id": "1"
},
{
"name": "Voice Agent",
"id": "2"
},
{
"name": "ElevenLabs",
"id": "3"
}
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Sales Voice Agent - ElevenLabs + n8n. Uses httpRequest, openAi, gmail, googleSheets. Webhook trigger; 19 nodes.
Source: https://github.com/venglishkc/ai-sales-voice-agent/blob/main/sales-voice-agent.json — 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.
leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.
Universal Expense tracker. Uses telegram, httpRequest, openAi, googleSheets. Webhook trigger; 33 nodes.
ANIS_HUB 1. Uses gmail, googleDrive, googleSheets, httpRequest. Webhook trigger; 89 nodes.
This n8n workflow orchestrates a powerful suite of AI Agents and automations to manage and optimize various aspects of an e-commerce operation, particularly for platforms like Shopify. It leverages La
Inbox Guardian. Uses gmailTrigger, lmChatOpenAi, agent, textClassifier. Event-driven trigger; 66 nodes.