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": "CallFlow \u2014 ElevenLabs Post-Call WhatsApp",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "elevenlabs-postcall",
"responseMode": "responseNode",
"options": {}
},
"id": "a1b2c3d4-0001-0001-0001-000000000001",
"name": "ElevenLabs Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "// ElevenLabs post-call webhook payload\nconst body = $input.first().json.body || $input.first().json;\n\n// Temel alanlar\nconst conversationId = body.conversation_id || '';\nconst agentId = body.agent_id || '';\nconst callDuration = body.call_duration_secs || 0;\nconst transcript = body.transcript || [];\nconst callSuccess = body.call_successful || false;\n\n// Telefon numaras\u0131\nconst metadata = body.metadata || {};\nconst clientData = body.conversation_initiation_client_data || {};\nconst rawPhone = metadata.phone_number\n || clientData.to_number\n || body.to_number\n || '';\nconst whatsappNumber = rawPhone.replace(/\\D/g, '');\n\n// Data collection\nconst dc = body.data_collection_results || {};\nconst customerName = dc.customer_name?.value || '';\nconst appointmentDate = dc.appointment_date?.value || '';\nconst appointmentTime = dc.appointment_time?.value || '';\nconst rawAddr = dc.appointment_address?.value || '';\nlet appointmentLat = dc.appointment_lat?.value ? parseFloat(dc.appointment_lat.value) : null;\nlet appointmentLng = dc.appointment_lng?.value ? parseFloat(dc.appointment_lng.value) : null;\n\n// \u2500\u2500 Adres koordinat m\u0131? \u00d6rn: \"39.994784, 32.768634\" \u2500\u2500\n// ElevenLabs bazen adres alan\u0131na koordinat yaz\u0131yor.\nconst COORD_RE = /^\\s*(-?\\d{1,3}\\.\\d+)\\s*,\\s*(-?\\d{1,3}\\.\\d+)\\s*$/;\nconst coordMatch = rawAddr.match(COORD_RE);\nlet appointmentAddr = rawAddr;\n\nif (coordMatch) {\n // Koordinatlar\u0131 parse et, adres metnini bo\u015falt\n appointmentLat = parseFloat(coordMatch[1]);\n appointmentLng = parseFloat(coordMatch[2]);\n appointmentAddr = ''; // harita mesaj\u0131yla g\u00f6nderilecek\n}\n\n// S\u00fcre format\u0131\nconst mins = Math.floor(callDuration / 60);\nconst secs = callDuration % 60;\nconst durationText = mins > 0 ? `${mins} dk ${secs} sn` : `${secs} sn`;\n\nreturn [{\n json: {\n conversationId,\n agentId,\n callDuration,\n durationText,\n callSuccess,\n whatsappNumber,\n customerName,\n appointmentDate,\n appointmentTime,\n appointmentAddr,\n appointmentLat,\n appointmentLng,\n hasAppointment: !!(appointmentDate || appointmentTime || appointmentLat),\n hasLocation: !!(appointmentLat && appointmentLng)\n }\n}];"
},
"id": "a1b2c3d4-0002-0002-0002-000000000002",
"name": "Veriyi \u0130\u015fle",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-phone",
"leftValue": "={{ $json.whatsappNumber }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "notEmpty"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "a1b2c3d4-0003-0003-0003-000000000003",
"name": "Telefon var m\u0131?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
720,
300
]
},
{
"parameters": {
"method": "GET",
"url": "=https://supabase.lueratech.com/rest/v1/whatsapp_templates?is_active=eq.true&order=created_at.desc&limit=1",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "<redacted-credential>"
},
{
"name": "Authorization",
"value": "<redacted-credential>"
}
]
},
"options": {}
},
"id": "a1b2c3d4-0009-0009-0009-000000000009",
"name": "Supabase: Aktif \u015eablonu Al",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
960,
160
]
},
{
"parameters": {
"jsCode": "// Supabase'den gelen aktif \u015fablon\nconst templates = $input.first().json;\nconst callData = $('Veriyi \u0130\u015fle').first().json;\n\n// \u2500\u2500\u2500 Fallback: Supabase'de aktif \u015fablon yoksa bunu kullan \u2500\u2500\u2500\nconst FALLBACK = [\n '\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501',\n '\ud83e\udd16 *LUERA CallFlow*',\n '\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501',\n '',\n 'Merhaba *{{isim}}!* \ud83d\udc4b',\n '',\n 'AI asistan\u0131m\u0131zla g\u00f6r\u00fc\u015fmeniz ba\u015far\u0131yla tamamland\u0131. \u2705',\n '\u23f1 G\u00f6r\u00fc\u015fme s\u00fcresi: _{{sure}}_',\n '{{randevu_bolumu}}',\n '',\n 'Herhangi bir sorunuz i\u00e7in bizi aramaktan \u00e7ekinmeyin. \ud83d\ude0a',\n '',\n '_Te\u015fekk\u00fcrler, g\u00f6r\u00fc\u015fmek \u00fczere!_ \ud83d\ude4f',\n '*LUERA Ekibi*'\n].join('\\n');\n\n// \u015eablon i\u00e7eri\u011fini belirle (Supabase'den \"message\" veya \"content\" alan\u0131)\nlet templateContent = '';\nif (Array.isArray(templates) && templates.length > 0) {\n const tpl = templates[0];\n templateContent = tpl.message || tpl.content || '';\n}\nif (!templateContent.trim()) {\n templateContent = FALLBACK;\n}\n\n// Randevu b\u00f6l\u00fcm\u00fc \u2014 sadece veri varsa g\u00f6ster\nlet randevuBolumu = '';\nif (callData.appointmentDate || callData.appointmentTime || callData.hasLocation) {\n randevuBolumu = '\\n\ud83d\udcc5 *Randevu Bilgileriniz*\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500';\n if (callData.appointmentDate) randevuBolumu += `\\n\ud83d\udcc6 Tarih: *${callData.appointmentDate}*`;\n if (callData.appointmentTime) randevuBolumu += `\\n\ud83d\udd50 Saat: *${callData.appointmentTime}*`;\n if (callData.appointmentAddr) {\n randevuBolumu += `\\n\ud83d\udccd Adres: ${callData.appointmentAddr}`;\n } else if (callData.hasLocation) {\n randevuBolumu += `\\n\ud83d\udccd _Konum a\u015fa\u011f\u0131da harita olarak payla\u015f\u0131ld\u0131_ \ud83d\udc47`;\n }\n}\n\n// M\u00fc\u015fteri ad\u0131 \u2014 bo\u015fsa nazik fallback\nconst isim = (callData.customerName || '').trim() || 'De\u011ferli M\u00fc\u015fterimiz';\n\n// De\u011fi\u015fken yerine koy (her iki adres format\u0131n\u0131 da destekle)\nconst messageText = templateContent\n .replace(/\\{\\{isim\\}\\}/gi, isim)\n .replace(/\\{\\{sure\\}\\}/gi, callData.durationText || '')\n .replace(/\\{\\{randevu_tarihi\\}\\}/gi, callData.appointmentDate || '')\n .replace(/\\{\\{randevu_saati\\}\\}/gi, callData.appointmentTime || '')\n .replace(/\\{\\{randevu_adresi\\}\\}/gi, callData.appointmentAddr || '')\n .replace(/\\{\\{adres\\}\\}/gi, callData.appointmentAddr || '')\n .replace(/\\{\\{randevu_bolumu\\}\\}/gi, randevuBolumu)\n .replace(/\\{\\{konusma_id\\}\\}/gi, callData.conversationId || '');\n\nreturn [{\n json: {\n ...callData,\n messageText\n }\n}];"
},
"id": "a1b2c3d4-0010-0010-0010-000000000010",
"name": "\u015eablonu \u0130\u015fle",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
160
]
},
{
"parameters": {
"method": "POST",
"url": "=https://evoapi.lueratech.com/message/sendText/wms",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "yaCLHuAqSTS4CwUadOBhD23SYca2ZhF1"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $json.whatsappNumber }}\",\n \"text\": {{ JSON.stringify($json.messageText) }}\n}",
"options": {}
},
"id": "a1b2c3d4-0004-0004-0004-000000000004",
"name": "WhatsApp Mesaj G\u00f6nder",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1440,
160
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-loc",
"leftValue": "={{ $('\u015eablonu \u0130\u015fle').first().json.hasLocation }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equal"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "a1b2c3d4-0006-0006-0006-000000000006",
"name": "Konum var m\u0131?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
960,
380
]
},
{
"parameters": {
"method": "POST",
"url": "=https://evoapi.lueratech.com/message/sendLocation/wms",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "yaCLHuAqSTS4CwUadOBhD23SYca2ZhF1"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"number\": \"{{ $('\u015eablonu \u0130\u015fle').first().json.whatsappNumber }}\",\n \"name\": \"Randevu Konumu\",\n \"address\": \"{{ $('\u015eablonu \u0130\u015fle').first().json.appointmentAddr || 'Randevu Adresi' }}\",\n \"latitude\": {{ $('\u015eablonu \u0130\u015fle').first().json.appointmentLat }},\n \"longitude\": {{ $('\u015eablonu \u0130\u015fle').first().json.appointmentLng }}\n}",
"options": {}
},
"id": "a1b2c3d4-0005-0005-0005-000000000005",
"name": "Konum G\u00f6nder",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1200,
380
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={ \"status\": \"ok\", \"conversation_id\": \"{{ $('Veriyi \u0130\u015fle').first().json.conversationId }}\" }",
"options": {}
},
"id": "a1b2c3d4-0007-0007-0007-000000000007",
"name": "Webhook Yan\u0131tla",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
1680,
270
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{ \"status\": \"skipped\", \"reason\": \"no phone number\" }",
"options": {}
},
"id": "a1b2c3d4-0008-0008-0008-000000000008",
"name": "Telefon Yok \u2014 Atla",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
960,
520
]
},
{
"parameters": {
"method": "POST",
"url": "=https://supabase.lueratech.com/rest/v1/appointments",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "apikey",
"value": "<redacted-credential>"
},
{
"name": "Authorization",
"value": "<redacted-credential>"
},
{
"name": "Content-Type",
"value": "application/json"
},
{
"name": "Prefer",
"value": "resolution=merge-duplicates"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"conversation_id\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.conversationId) }},\n \"customer_name\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.customerName || null) }},\n \"customer_phone\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.whatsappNumber || null) }},\n \"appointment_date\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.appointmentDate || null) }},\n \"appointment_time\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.appointmentTime || null) }},\n \"appointment_address\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.appointmentAddr || null) }},\n \"latitude\": {{ $('Veriyi \u0130\u015fle').first().json.appointmentLat || 'null' }},\n \"longitude\": {{ $('Veriyi \u0130\u015fle').first().json.appointmentLng || 'null' }},\n \"call_duration_secs\": {{ $('Veriyi \u0130\u015fle').first().json.callDuration || 0 }},\n \"agent_id\": {{ JSON.stringify($('Veriyi \u0130\u015fle').first().json.agentId || null) }},\n \"status\": \"confirmed\"\n}",
"options": {}
},
"id": "a1b2c3d4-0011-0011-0011-000000000011",
"name": "Supabase: Randevu Kaydet",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1680,
420
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"id": "cond-appt",
"leftValue": "={{ $('Veriyi \u0130\u015fle').first().json.hasAppointment }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equal"
}
}
],
"combinator": "and"
},
"options": {}
},
"id": "a1b2c3d4-0012-0012-0012-000000000012",
"name": "Randevu var m\u0131?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1440,
380
]
}
],
"connections": {
"ElevenLabs Webhook": {
"main": [
[
{
"node": "Veriyi \u0130\u015fle",
"type": "main",
"index": 0
}
]
]
},
"Veriyi \u0130\u015fle": {
"main": [
[
{
"node": "Telefon var m\u0131?",
"type": "main",
"index": 0
}
]
]
},
"Telefon var m\u0131?": {
"main": [
[
{
"node": "Supabase: Aktif \u015eablonu Al",
"type": "main",
"index": 0
},
{
"node": "Konum var m\u0131?",
"type": "main",
"index": 0
}
],
[
{
"node": "Telefon Yok \u2014 Atla",
"type": "main",
"index": 0
}
]
]
},
"Supabase: Aktif \u015eablonu Al": {
"main": [
[
{
"node": "\u015eablonu \u0130\u015fle",
"type": "main",
"index": 0
}
]
]
},
"\u015eablonu \u0130\u015fle": {
"main": [
[
{
"node": "WhatsApp Mesaj G\u00f6nder",
"type": "main",
"index": 0
}
]
]
},
"WhatsApp Mesaj G\u00f6nder": {
"main": [
[
{
"node": "Webhook Yan\u0131tla",
"type": "main",
"index": 0
},
{
"node": "Randevu var m\u0131?",
"type": "main",
"index": 0
}
]
]
},
"Randevu var m\u0131?": {
"main": [
[
{
"node": "Supabase: Randevu Kaydet",
"type": "main",
"index": 0
}
],
[]
]
},
"Konum var m\u0131?": {
"main": [
[
{
"node": "Konum G\u00f6nder",
"type": "main",
"index": 0
}
],
[]
]
},
"Konum G\u00f6nder": {
"main": [
[
{
"node": "Webhook Yan\u0131tla",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1"
},
"staticData": null,
"tags": [
"callflow",
"whatsapp",
"elevenlabs"
]
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
CallFlow — ElevenLabs Post-Call WhatsApp. Uses httpRequest. Webhook trigger; 12 nodes.
Source: https://github.com/furkanulgr/callflow/blob/7e933ad19094442d592de059f7e34e66344427da/n8n-callflow-workflow.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.
Flujowhatsapp. Uses @aldinokemal2104/n8n-nodes-gowa, postgres, httpRequest. Webhook trigger; 65 nodes.
HR teams, IT Operations, and System Administrators managing employee onboarding at scale. It’s perfect if you use Odoo 18 to trigger account requests and need Redmine + GitLab accounts created instant
This workflow is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS
WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.
Backbrief: transcripts (Zoom webhook -> Slack + vault). Uses httpRequest, slack. Webhook trigger; 52 nodes.