# templates

name: AI-Powered Research Assistant for Platform Questions with GPT-4o and MCP
author_name: Onur
author_username: onurpolat05
nodes_used: ["@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]
categories: []
created_at: 2025-03-24T09:42:01.239Z
updated_at: 2025-03-24T09:42:01.239Z
url: https://n8n.io/workflows/3303
scraped_at: 2025-07-06 21:16:30
description:
  Description

  This workflow empowers you to effortlessly get answers to your n8n platform questions through an AI-powered assistant. Simply send your query, and the assistant will search documentation, forum posts, and example workflows to provide comprehensive, accurate responses tailored to your specific needs.

  &gt; Note: This workflow uses community nodes (n8n-nodes-mcp.mcpClientTool) and will only work on self-hosted n8n instances. You'll need to install the required community nodes before importing this workflow.

  !

  What does this workflow do?

  This workflow streamlines the information retrieval process by automatically researching n8n platform documentation, community forums, and example workflows, providing you with relevant answers to your questions.

  Who is this for?

  New n8n Users**: Quickly get answers to basic platform questions and learn how to use n8n effectively
  Experienced Developers**: Find solutions to specific technical issues or discover advanced workflows
  Teams**: Boost productivity by automating the research process for n8n platform questions
  Anyone** looking to leverage AI for efficient and accurate n8n platform knowledge retrieval

  Benefits

  Effortless Research**: Automate the research process across n8n documentation, forum posts, and example workflows
  AI-Powered Intelligence**: Leverage the power of LLMs to understand context and generate helpful responses
  Increased Efficiency**: Save time and resources by automating the research process
  Quick Solutions**: Get immediate answers to your n8n platform questions
  Enhanced Learning**: Discover new workflows, features, and best practices to improve your n8n experience

  How It Works

  Receive Request: The workflow starts when a chat message is received containing your n8n-related question
  AI Processing: The AI agent powered by OpenAI GPT-4o analyzes your question
  Research and Information Gathering: The system searches across multiple sources:
     Official n8n documentation for general knowledge and how-to guides
     Community forums for bug reports and specific issues
     Example workflow repository for relevant implementations
  Response Generation: The AI agent compiles the research and generates a clear, comprehensive answer
  Output: The workflow provides you with the relevant information and step-by-step guidance when applicable

  n8n Nodes Used

  When chat message received (Chat Trigger)
  OpenAI Chat Model (GPT-4o mini)
  N8N AI Agent
  n8n-assistant tools (MCP Client Tool - Community Node)
  n8n-assistant execute (MCP Client Tool - Community Node)

  Prerequisites

  Self-hosted n8n instance
  OpenAI API credentials
  MCP client community node installed
  MCP server configured to search n8n resources

  Setup

  Import the workflow JSON into your n8n instance
  Configure the OpenAI credentials
  Configure your MCP client API credentials
  In the n8n-assistant execute node, ensure the parameter is set to "specific" (corrected from "spesific")
  Test the workflow by sending a message with an n8n-related question

  MCP Server Connection

  To connect to the MCP server that powers this assistant's research capabilities, you need to use the following URL:
  https://smithery.ai/server/@onurpolat05/n8n-assistant

  This MCP server is specifically designed to search across three types of n8n resources:
  Official documentation for general platform information and workflow creation guidance
  Community forums for bug-related issues and troubleshooting
  Example workflow repositories for reference implementations

  Configure this URL in your MCP client credentials to enable the assistant to retrieve relevant information based on user queries.

  This workflow combines the convenience of chat with the power of AI to provide a seamless n8n platform research experience. Start getting instant answers to your n8n questions today!

workflow_json:
  {"meta":{"instanceId":"02e782574ebb30fbddb2c3fd832c946466d718819d25f6fe4b920124ff3fc2c1","templateCredsSetupCompleted":true},"nodes":[{"id":"bc58bd73-921a-445c-a905-6f1bbbc0e9c3","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[1160,420],"webhookId":"cf762550-98e7-42f0-a0f3-cd9594331c00","parameters":{"options":{}},"typeVersion":1.1},{"id":"308aea70-2831-4abd-90f6-d4cbf3901be4","name":"n8n Research AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[1440,420],"parameters":{"options":{"systemMessage":"You are an assistant integrated with the n8n Multi-Channel Platform (MCP). Your primary role is to interact with the MCP to retrieve available tools and content based on user queries about n8n. When a user asks for information or assistance regarding n8n, first send a request to the MCP to fetch the relevant tools and content. Analyze the retrieved data to understand the available options, then create a tailored response that addresses their specific needs regarding n8n functionalities, documentation, forum posts, or example workflows. Ensure that your responses are clear, actionable, and directly related to the user's queries about n8n."}},"typeVersion":1.8},{"id":"94cb78f5-3520-4432-b3c9-0524411113e9","name":"n8n-assistant Tool Lookup","type":"n8n-nodes-mcp.mcpClientTool","position":[1500,640],"parameters":{},"credentials":{"mcpClientApi":{"id":"w1ZOoPXYGz6W2g1T","name":"n8n-assistant"}},"typeVersion":1},{"id":"78a87949-afda-4c52-ae9f-f8d343fb6567","name":"n8n-assistant Execute Tool","type":"n8n-nodes-mcp.mcpClientTool","position":[1700,640],"parameters":{"toolName":"={{$fromAI(\"tool\",\"Set this specific tool name\")}}","operation":"executeTool","toolParameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Tool_Parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"w1ZOoPXYGz6W2g1T","name":"n8n-assistant"}},"typeVersion":1},{"id":"cc1619ec-6f49-45e6-8a7b-440da7ee5bc5","name":"OpenAI Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1320,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"q2i0xAiFxUOYOlJ0","name":"OpenAI_BCP"}},"typeVersion":1.2}],"connections":{"OpenAI Chat Model2":{"ai_languageModel":[[{"node":"n8n Research AI Agent","type":"ai_languageModel","index":0}]]},"n8n-assistant Tool Lookup":{"ai_tool":[[{"node":"n8n Research AI Agent","type":"ai_tool","index":0}]]},"When chat message received":{"main":[[{"node":"n8n Research AI Agent","type":"main","index":0}]]},"n8n-assistant Execute Tool":{"ai_tool":[[{"node":"n8n Research AI Agent","type":"ai_tool","index":0}]]}}}


name: WebSecScan: AI-Powered Website Security Auditor
author_name: Dale Dunlop
author_username: daledunlop
categories: []
created_at: 2025-03-24T18:13:24.596Z
updated_at: 2025-03-24T18:13:24.596Z
url: https://n8n.io/workflows/3314
scraped_at: 2025-07-06 21:16:30
description:
  WebSecScan: AI-Powered Website Security Auditor

  This n8n workflow provides comprehensive website security analysis by leveraging OpenAI's models to detect vulnerabilities, configuration issues, and security misconfigurations. The workflow generates a professional HTML security report delivered directly via Gmail.

  Key Features

  Dual-Layer Security Analysis:** Performs parallel security audits using specialized OpenAI agents:
    Header Configuration Audit: Analyzes HTTP headers, CORS policies, CSP implementation, and cookie security
    Vulnerability Assessment: Identifies XSS vectors, information disclosure, and client-side weaknesses
    
  Detailed Security Grading:** Automatically calculates a security grade (A+ to F) based on findings severity and quantity

  Professional Report Generation:** Creates a comprehensive HTML report with:
    Security grade visualization
    Color-coded vulnerability categories
    Detailed recommendations with example configuration fixes
    Header presence/absence indicators
    Implementation guidance for remediation

  Non-Invasive Testing:** Performs analysis without active scanning or exploitation attempts

  Technical Implementation

  Multi-Agent Architecture:** Utilizes two specialized OpenAI agents with custom prompts tailored for security analysis
  Advanced Header Analysis:** Detects presence and proper implementation of critical security headers:
    Content-Security-Policy
    Strict-Transport-Security
    X-Content-Type-Options
    X-Frame-Options
    Referrer-Policy
    Permissions-Policy

  Intelligent Issue Detection:** Uses JavaScript processing to analyze OpenAI outputs and count critical/warning issues
  Responsive HTML Report:** Dynamically generates a mobile-friendly report with detailed findings and recommendations

  Setup Requirements

  1. OpenAI API Configuration
  Create an OpenAI API key at platform.openai.com
  In n8n, go to Settings → Credentials → New → OpenAI API
  Enter your API key and save

  2. Gmail Integration
  Navigate to Settings → Credentials → New → Gmail OAuth2 API
  Complete the OAuth authentication flow
  Configure recipient email in the "Send Security Report" node

  3. Workflow Customization (Optional)
  Modify the form title/description in the Landing Page node
  Upgrade from gpt-4o-mini to gpt-4o for more comprehensive analysis
  Add additional recipients to the email report

  Usage Instructions

  Activate the workflow and access the form via the generated URL
  Enter any website URL to analyze (including the http:// or https:// prefix)
  Receive a detailed security report via email within minutes
  Share findings with your development team to implement fixes

  This workflow represents a non-invasive security assessment tool. For production environments, complement with professional penetration testing services.

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.gmail","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"meta":{"instanceId":"c2589fa234defe76e8a1321c3a7d0a73579d0120d64d927e88f5e3be584ae8d4"},"nodes":[{"id":"634f2fc5-0ba7-42ad-bdf5-ade3415dd288","name":"Landing Page Url","type":"n8n-nodes-base.formTrigger","position":[-200,580],"webhookId":"afe067a5-4878-4c9d-b746-691f77190f54","parameters":{"options":{},"formTitle":"Website Security Scanner","formFields":{"values":[{"fieldLabel":"Landing Page Url","placeholder":"https://example.com","requiredField":true}]},"formDescription":"Check your website for security vulnerabilities and get a detailed report"},"typeVersion":2.2},{"id":"6cee63ca-d0f6-444a-b882-22da1a9fd70c","name":"Scrape Website","type":"n8n-nodes-base.httpRequest","position":[0,580],"parameters":{"url":"={{ $json['Landing Page Url'] }}","options":{"redirect":{"redirect":{"maxRedirects":5}},"response":{"response":{"fullResponse":true,"responseFormat":"text"}}}},"typeVersion":4.2},{"id":"0d5d1e76-e627-4565-a1ee-6a610f4b2028","name":"OpenAI Headers Analysis","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,600],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yZ0AIg9abV8HJadB","name":"OpenAi account"}},"typeVersion":1.2},{"id":"04427ef7-515d-4a1a-88d2-ade10aeefc87","name":"OpenAI Content Analysis","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,980],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yZ0AIg9abV8HJadB","name":"OpenAi account"}},"typeVersion":1.2},{"id":"d4ee4db8-aa04-4068-9b97-d16acf98c027","name":"Security Vulnerabilities Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[360,780],"parameters":{"text":"=You are an elite cybersecurity expert specializing in web application security.\n\nIn this task, you will analyze the HTML and visible content of the webpage to identify potential security vulnerabilities.\n\nAudit Structure\nYou will review all client-side security aspects of the page and present your findings in three sections:\n- Critical Vulnerabilities – Issues that could lead to immediate compromise\n- Information Leakage – Sensitive data exposed in page source\n- Client-Side Weaknesses – JavaScript vulnerabilities, XSS opportunities, etc.\n\nFor each issue found, provide:\n1. A clear description of the vulnerability\n2. The potential impact\n3. A specific recommendation to fix it\n\nIf you find no issues in a particular section, explicitly state that no issues were found in that category.\n\nEnsure the output is properly formatted, clean, and highly readable. Focus only on issues that can be detected from the client-side code.\n\nHere is the content of the webpage: {{ $json.data }}","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"c9702f2b-845b-464d-9c32-3d5be308ef77","name":"Security Configuration Audit","type":"@n8n/n8n-nodes-langchain.agent","position":[360,380],"parameters":{"text":"=You are an elite web security expert specializing in secure configurations.\n\nIn this task, you will analyze the HTTP headers, cookies, and overall configuration of a webpage to identify security misconfigurations.\n\nAudit Structure\nYou will begin by listing ALL security headers that ARE present and properly configured.\n\nBe very clear and explicit about which headers are present and which are missing. For each header, clearly state whether it is present or missing, and if present, what its value is.\n\nThen, present your findings in three sections:\n- Header Security – Missing or misconfigured security headers\n- Cookie Security – Insecure cookie configurations\n- Content Security – CSP issues, mixed content, etc.\n\nFor each finding, provide:\n1. A clear description of the misconfiguration\n2. The security implications\n3. The recommended secure configuration with example code\n\nIf you find no issues in a particular section, explicitly state that no issues were found.\n\nUse proper formatting with code blocks for configuration examples. Only include issues that can be detected from client-side inspection.\nHere are the response headers: {{ $json.formattedHeaders }}\n\nPlease Respond like this\n\n### [any section heading that includes \"Headers]\n\n1. **[Header Title]**\n   - **Present?** Yes/No\n   - **Value:** `actual-header-value`\n","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"3b43be75-c35c-44e4-8ecc-a29c48e3625c","name":"Merge Security Results","type":"n8n-nodes-base.merge","position":[860,580],"parameters":{},"typeVersion":3,"alwaysOutputData":true},{"id":"da134256-d7fa-4a3f-ba24-acc320a944a2","name":"Aggregate Audit Results","type":"n8n-nodes-base.aggregate","position":[1060,580],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"output"}]}},"typeVersion":1},{"id":"aef1da93-0b01-4a7f-9439-1f74c2af12d6","name":"Process Audit Results","type":"n8n-nodes-base.code","position":[1240,580],"parameters":{"jsCode":"// ✅ Updated extractSecurityHeaders and related logic remains unchanged\n\nfunction extractSecurityHeaders(rawHeaders = {}, configOutput = '') {\n  const securityHeaders = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options',\n    'Referrer-Policy',\n    'Permissions-Policy',\n    'X-XSS-Protection',\n    'Cross-Origin-Embedder-Policy',\n    'Cross-Origin-Opener-Policy',\n    'X-Permitted-Cross-Domain-Policies'\n  ];\n\n  const headerStatus = {};\n  for (const header of securityHeaders) {\n    headerStatus[header] = { present: false, value: '' };\n  }\n\n  for (const header in rawHeaders) {\n    const norm = header.trim().toLowerCase();\n    for (const standard of securityHeaders) {\n      if (norm === standard.toLowerCase()) {\n        headerStatus[standard].present = true;\n        headerStatus[standard].value = rawHeaders[header];\n      }\n    }\n  }\n\n  const presentSection = configOutput.match(/(?:###|##|\\*\\*)[^\\n]*?\\bheaders?\\b[\\s\\S]*?(?=###|##|\\*\\*|$)/i);\n  if (presentSection) {\n    const section = presentSection[0];\n    for (const header of securityHeaders) {\n      const title = header.replace(/-/g, ' ').replace(/\\b\\w/g, c => c.toUpperCase());\n      const regex = new RegExp(`\\\\*\\\\*${title}\\\\*\\\\*[^\\\\n]*?\\\\*\\\\*Present\\\\?\\\\*\\\\*\\\\s*Yes[^\\\\n]*?\\\\*\\\\*Value:\\\\*\\\\*\\\\s*\\`([^\\\\\\`]+)\\``, 'is');\n      const match = section.match(regex);\n      if (match && match[1]) {\n        headerStatus[header].present = true;\n        headerStatus[header].value = match[1].trim();\n      }\n    }\n  }\n\n  return headerStatus;\n}\n\nfunction hasUnsafeInline(value) {\n  return value && value.includes('unsafe-inline');\n}\n\nfunction determineGrade(headerStatus) {\n  const critical = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options'\n  ];\n  const important = ['Referrer-Policy', 'Permissions-Policy'];\n  const additional = [\n    'X-XSS-Protection',\n    'Cross-Origin-Embedder-Policy',\n    'Cross-Origin-Opener-Policy',\n    'X-Permitted-Cross-Domain-Policies'\n  ];\n\n  let criticalCount = 0;\n  let importantCount = 0;\n  let hasCSPIssue = false;\n\n  for (const h of critical) {\n    if (headerStatus[h]?.present) {\n      criticalCount++;\n      if (h === 'Content-Security-Policy' && hasUnsafeInline(headerStatus[h].value)) {\n        hasCSPIssue = true;\n      }\n    }\n  }\n\n  for (const h of important) {\n    if (headerStatus[h]?.present) importantCount++;\n  }\n\n  if (criticalCount === critical.length) {\n    if (importantCount === important.length) return hasCSPIssue ? 'A-' : 'A+';\n    if (importantCount >= 1) return hasCSPIssue ? 'B+' : 'A-';\n    return hasCSPIssue ? 'B' : 'B+';\n  } else if (criticalCount >= critical.length - 1) {\n    return importantCount >= 1 ? 'B' : 'C+';\n  } else if (criticalCount >= 2) {\n    return 'C';\n  } else if (criticalCount >= 1) {\n    return 'D';\n  } else {\n    return 'F';\n  }\n}\n\nfunction formatHeadersForDisplay(headerStatus) {\n  const present = Object.keys(headerStatus).filter(h => headerStatus[h].present);\n  return present.length > 0 ? present.join(', ') : 'No security headers detected';\n}\n\nfunction processSecurityHeaders(items) {\n  try {\n    const json = items[0].json || items[0];\n\n    // ⛏️ Try to grab from originalHeaders if available\n    const rawHeaders =\n      json?.originalHeaders ||\n      $('Extract Headers for Debug')?.first()?.json?.originalHeaders ||\n      json?.headers ||\n      {};\n\n    const configOutput = json.configOutput || json.output?.[0] || '';\n    const vulnOutput = json.vulnOutput || json.output?.[1] || '';\n\n    const headerStatus = extractSecurityHeaders(rawHeaders, configOutput);\n    const presentHeaders = formatHeadersForDisplay(headerStatus);\n    const grade = determineGrade(headerStatus);\n\n    const timestamp = new Date().toLocaleString('en-US', {\n      year: 'numeric',\n      month: 'long',\n      day: 'numeric',\n      hour: '2-digit',\n      minute: '2-digit'\n    });\n\n    const url =\n      json?.formValues?.url ||\n      json?.['Landing Page Url'] ||\n      $('Landing Page Url')?.first()?.json?.['Landing Page Url'] ||\n      json?.Landing_Page_Url ||\n      json?.landingPageUrl ||\n      json?.url ||\n      'https://example.com';\n\n    return [\n      {\n        json: {\n          ...json,\n          auditData: {\n            url,\n            timestamp,\n            grade,\n            criticalCount:\n              headerStatus['Content-Security-Policy'].present &&\n              hasUnsafeInline(headerStatus['Content-Security-Policy'].value)\n                ? 1\n                : 0,\n            warningCount: Object.keys(headerStatus).filter(\n              h =>\n                !headerStatus[h].present &&\n                !['Strict-Transport-Security', 'Content-Security-Policy'].includes(h)\n            ).length,\n            presentHeaders,\n            configOutput,\n            vulnOutput,\n            headerStatus,\n            originalHeaders: rawHeaders\n          }\n        }\n      }\n    ];\n  } catch (err) {\n    return [{ json: { ...items[0].json, error: err.message } }];\n  }\n}\n\nreturn processSecurityHeaders(items);\n"},"typeVersion":2},{"id":"ced29b26-474c-4d62-808a-3284103c9d60","name":"Send Security Report","type":"n8n-nodes-base.gmail","position":[1580,580],"webhookId":"2979e4dc-1689-447e-8cd4-eb907b4eedf4","parameters":{"sendTo":"=example@here.com","message":"={{ $json.emailHtml }}","options":{},"subject":"=Website Security Audit - {{ $json.auditData.url }}"},"credentials":{"gmailOAuth2":{"id":"9CEpbF4jIWb2OETv","name":"Gmail account"}},"typeVersion":2.1},{"id":"918c0fc4-2f02-4594-bfc9-e36035f2d802","name":"Sticky Note - Setup Instructions","type":"n8n-nodes-base.stickyNote","position":[-820,400],"parameters":{"width":500,"height":440,"content":"## Quick Setup Guide\n\n1. **Add OpenAI API Credentials**\n   - Go to Settings → Credentials → New → OpenAI API\n   - Enter your API key from platform.openai.com\n\n2. **Add Gmail Credentials**\n   - Go to Settings → Credentials → New → Gmail OAuth2 API\n   - Complete the OAuth setup process\n\n3. **Update Email Configuration**\n   - Open the 'Send Security Report' node\n   - Change the recipient email address from the default\n\n4. **Activate and Deploy Workflow**\n   - Click 'Active' toggle in the top right\n   - Copy the form URL to share with others or use yourself"},"typeVersion":1},{"id":"6e31b9b8-ae02-4da4-a75e-5d784b210c64","name":"Sticky Note - OpenAI Analysis","type":"n8n-nodes-base.stickyNote","position":[300,120],"parameters":{"color":3,"width":420,"height":240,"content":"## OpenAI Security Analysis\n\n- Add your OpenAI credentials (required)\n- Using GPT-4o models provides more detailed security analysis\n- Analyzes for XSS, information disclosure, CSRF, and more\n- Each agent scans different aspects of website security\n- Consider upgrading to GPT-4o (not mini) for production use"},"typeVersion":1},{"id":"590b1f1c-024d-4002-a8eb-d9dc81528f89","name":"Sticky Note - Email Configuration","type":"n8n-nodes-base.stickyNote","position":[1480,220],"parameters":{"color":3,"width":360,"height":200,"content":"## Send Security Report\n\n- Connects securely to Gmail for sending detailed reports\n- Report is sent as HTML formatted email\n- Subject line includes the scanned URL\n- Requires Gmail OAuth credentials to be set up"},"typeVersion":1},{"id":"dc6223f8-a98c-497a-97c9-af39e80e6d66","name":"Sticky Note - Audit Process","type":"n8n-nodes-base.stickyNote","position":[-200,780],"parameters":{"color":2,"width":420,"height":300,"content":"## Security Audit Process\n\n- This workflow performs two parallel security analyses\n- Top path: Checks headers, cookies, and security configurations\n- Bottom path: Analyzes HTML/JavaScript for client-side vulnerabilities\n- Results are merged and formatted into a comprehensive report\n- Analysis is non-invasive and only examines client-side content"},"typeVersion":1},{"id":"cbda16d4-f1f4-491c-b38c-43d7544e129b","name":"Sticky Note - How To Use","type":"n8n-nodes-base.stickyNote","position":[-240,240],"parameters":{"color":4,"width":400,"height":280,"content":"## How To Use This Workflow\n\n1. **Deploy the workflow** and activate it\n2. **Access the form** via the provided URL\n3. **Enter any website URL** to scan (must include http:// or https://)\n4. **Submit the form** to trigger the analysis\n5. **Check your email** for the detailed security report\n6. **Share the results** with your development team to implement fixes"},"typeVersion":1},{"id":"4859416f-4de3-43ea-9461-3ead8a38db6e","name":"Sticky Note - Report Formatting","type":"n8n-nodes-base.stickyNote","position":[1160,220],"parameters":{"color":5,"width":300,"height":280,"content":"## Report Formatting\n\n- Creates beautiful, professional HTML email report\n- Visual grade indicator (A-F) based on findings\n- Includes count of critical issues and warnings\n- Color-coded sections for easy readability\n- Mobile-friendly responsive design"},"typeVersion":1},{"id":"a02db4c7-2cad-41ff-b5ad-e1b19604a699","name":"Sticky Note - Results Processing","type":"n8n-nodes-base.stickyNote","position":[840,240],"parameters":{"width":300,"height":240,"content":"## Results Processing\n\n- Analyzes AI output to determine security grade\n- Counts critical issues and warnings\n- Extracts present security headers\n- Prepares data for the email report template\n- Generates timestamp for the report"},"typeVersion":1},{"id":"41b834c8-62f7-47e7-9d9d-e0e1244faecb","name":"Extract Headers for Debug","type":"n8n-nodes-base.code","position":[200,460],"parameters":{"jsCode":"// Format headers into a readable string\nlet formattedHeaders = '';\nif (items[0].json.headers) {\n  for (const key in items[0].json.headers) {\n    formattedHeaders += `${key}: ${items[0].json.headers[key]}\\n`;\n  }\n}\n\n// Return both the original data and the formatted headers\nreturn [{\n  json: {\n    ...items[0].json,\n    formattedHeaders: formattedHeaders,\n    originalHeaders: items[0].json.headers // Keep the original headers too\n  }\n}];"},"typeVersion":2},{"id":"0b76b396-fc96-41fc-a095-30971dd88271","name":"convert to HTML","type":"n8n-nodes-base.code","position":[1400,580],"parameters":{"jsCode":"// Create a direct HTML template with improved styling\nconst auditData = items[0].json.auditData;\n\nfunction formatConfigurationIssues() {\n  if (!auditData.configOutput || auditData.configOutput.trim() === '') {\n    return '<p>No specific configuration issues detected.</p>';\n  }\n\n  try {\n    const config = auditData.configOutput.trim();\n    let html = '';\n    const renderedKeys = new Set();\n\n    const renderBlock = (title, description, impact, recommendation) => `\n      <div style=\"border-left: 4px solid #3498DB; padding: 10px; margin-bottom: 15px;\">\n        <div style=\"font-weight: bold; color: #3498DB;\">${title}</div>\n        ${description ? `<div style=\"margin-top: 5px;\">${description}</div>` : ''}\n        ${impact ? `<div style=\"margin-top: 5px; font-style: italic; color: #7F8C8D;\">Impact: ${impact}</div>` : ''}\n        ${recommendation ? `<div style=\"margin-top: 5px;\"><strong>Recommendation:</strong></div>\n          <pre style=\"background-color: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; font-family: monospace;\">${recommendation}</pre>` : ''}\n      </div>`;\n\n    const sections = config.split(/(?=^###\\s+)/gm).filter(Boolean);\n\n    for (const section of sections) {\n      const sectionTitleMatch = section.match(/^###\\s+(.*)/);\n      const sectionTitle = sectionTitleMatch?.[1]?.trim() || 'Unnamed Section';\n      const sectionKey = sectionTitle.toLowerCase();\n\n      // Skip \"no issues found\" sections\n      if (/no issues? (found|were found)/i.test(section)) continue;\n\n      const lines = section.split(/\\n+/).filter(line => line.trim() !== '');\n\n      let currentTitle = '';\n      let description = '';\n      let impact = '';\n      let recommendation = '';\n\n      for (let i = 0; i < lines.length; i++) {\n        const line = lines[i].trim();\n\n        // Start of a new numbered or bolded issue\n        const numberedTitle = line.match(/^\\d+\\.\\s+\\*\\*(.*?)\\*\\*/);\n        const bulletTitle = line.match(/^\\*\\*(.*?)\\*\\*/);\n\n        if (numberedTitle || (!currentTitle && bulletTitle)) {\n          // Flush last block\n          if (currentTitle && !renderedKeys.has(`${sectionKey}::${currentTitle.toLowerCase()}`)) {\n            html += renderBlock(currentTitle, description, impact, recommendation);\n            renderedKeys.add(`${sectionKey}::${currentTitle.toLowerCase()}`);\n          }\n\n          currentTitle = (numberedTitle || bulletTitle)[1].trim();\n          description = '';\n          impact = '';\n          recommendation = '';\n          continue;\n        }\n\n        const valueMatch = line.match(/- \\*\\*Value:\\*\\*\\s*`?(.*?)`?$/i);\n        const presentMatch = line.match(/- \\*\\*Present\\?\\*\\*.*?(Yes|No)/i);\n        const descMatch = line.match(/- \\*\\*Description:\\*\\*\\s*(.*)/i);\n        const impactMatch = line.match(/- \\*\\*(?:Impact|Security Implication|Potential Impact):\\*\\*\\s*(.*)/i);\n        const recMatch = line.match(/```(?:\\w*)?\\n([\\s\\S]*?)```/i);\n\n        if (descMatch) {\n          description = descMatch[1].trim();\n        } else if (valueMatch || presentMatch) {\n          const present = presentMatch?.[1]?.trim() || 'Unknown';\n          const value = valueMatch?.[1]?.trim() || '[Not provided]';\n          description = `This header is ${present.toLowerCase()}. Value: ${value}.`;\n        }\n\n        if (impactMatch) {\n          impact = impactMatch[1].trim();\n        }\n\n        if (recMatch) {\n          recommendation = recMatch[1].trim();\n        }\n      }\n\n      // Final block in section\n      if (currentTitle && !renderedKeys.has(`${sectionKey}::${currentTitle.toLowerCase()}`)) {\n        html += renderBlock(currentTitle, description, impact, recommendation);\n        renderedKeys.add(`${sectionKey}::${currentTitle.toLowerCase()}`);\n      }\n    }\n\n    return html || '<p>No configuration issues detected.</p>';\n  } catch (e) {\n    console.error('Error in formatConfigurationIssues:', e);\n    return `<p>Error processing configuration issues: ${e.message}</p>`;\n  }\n}\n\n\n\n// Create header badge HTML\nfunction createHeaderBadge(headerName, isWarning = false) {\n  const isPresent = auditData.headerStatus && \n                   auditData.headerStatus[headerName] && \n                   auditData.headerStatus[headerName].present;\n  \n  const color = isWarning && isPresent ? \"#F39C12\" : (isPresent ? \"#27AE60\" : \"#E74C3C\");\n  const icon = isPresent ? \"✓\" : \"✗\";\n  \n  return `<span style=\"display: inline-block; margin: 2px; padding: 4px 8px; background-color: ${color}; color: white; border-radius: 4px; font-size: 12px;\">${icon} ${headerName}</span>`;\n}\n\n// Format warnings section\nfunction formatWarningsSection() {\n  if (!auditData.warningCount || auditData.warningCount === 0 || !auditData.headerStatus) {\n    return '<p>No warnings detected.</p>';\n  }\n\n  const csp = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'content-security-policy');\n  const hsts = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'strict-transport-security');\n  const xss = Object.entries(auditData.headerStatus).find(([k]) => k.toLowerCase() === 'x-xss-protection');\n\n  let warnings = '';\n\n  if (csp && csp[1].value && csp[1].value.includes('unsafe-inline')) {\n    warnings += `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">Content-Security-Policy: unsafe-inline</strong>\n          <p>The use of 'unsafe-inline' allows potentially malicious scripts to execute.</p>\n        </div>\n      </div>`;\n  }\n\n  if (hsts && hsts[1].value) {\n    const match = hsts[1].value.match(/max-age=(\\d+)/);\n    const age = match ? parseInt(match[1]) : 0;\n    if (age < 2592000) {\n      warnings += `\n        <div style=\"margin-top: 15px;\">\n          <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n            <strong style=\"color: #F39C12;\">Strict-Transport-Security</strong>\n            <p>max-age is too low (${age}). Should be at least 2592000 (30 days).</p>\n          </div>\n        </div>`;\n    }\n  }\n\n  if (xss && !xss[1].present) {\n    warnings += `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">Missing X-XSS-Protection</strong>\n          <p>This header enables the browser's XSS filter. Lack of it increases XSS risks.</p>\n        </div>\n      </div>`;\n  }\n\n  if (!warnings) {\n    warnings = `\n      <div style=\"margin-top: 15px;\">\n        <div style=\"border-left: 4px solid #F39C12; padding: 10px;\">\n          <strong style=\"color: #F39C12;\">${auditData.warningCount} warnings detected</strong>\n          <p>See the Configuration Issues section below for more info.</p>\n        </div>\n      </div>`;\n  }\n\n  return warnings;\n}\n\nfunction formatLongValue(value) {\n  if (!value || typeof value !== 'string') return '[empty]';\n\n  // Convert URLs into clickable links\n  value = value.replace(/(https?:\\/\\/[^\\s]+)/g, '<a href=\"$1\" style=\"color: #3498DB; text-decoration: none;\" target=\"_blank\">$1</a>');\n\n  // Add line breaks after commas or semicolons for readability\n  if (value.length > 100) {\n    value = value.replace(/([,;])\\s*/g, '$1<br>');\n  }\n\n  return value;\n}\n\nfunction formatDetailedRawHeaders() {\n  const allHeaders = [];\n  const seen = new Set();\n\n  const addHeader = (name, value) => {\n    const key = name.toLowerCase();\n    if (seen.has(key)) return;\n    seen.add(key);\n\n    const status = Object.entries(auditData.headerStatus || {}).find(\n      ([k]) => k.toLowerCase() === name.toLowerCase()\n    );\n    const present = status ? status[1].present : !!value;\n\n    allHeaders.push({\n      name: name.trim(),\n      present,\n      value: value || '[empty]'\n    });\n  };\n\n  Object.entries(auditData.originalHeaders || {}).forEach(([key, value]) => {\n    if (key) addHeader(key, value);\n  });\n\n  const securityHeaders = [\n    'content-security-policy',\n    'strict-transport-security',\n    'x-content-type-options',\n    'x-frame-options',\n    'referrer-policy',\n    'permissions-policy',\n    'x-xss-protection'\n  ];\n\n  const isWarningHeader = (name, value) => {\n    const lower = name.toLowerCase();\n    if (lower === 'strict-transport-security') {\n      const match = value.match(/max-age=(\\d+)/);\n      return match && parseInt(match[1]) < 2592000;\n    }\n    if (lower === 'content-security-policy') return value.includes(\"'unsafe-inline'\");\n    return false;\n  };\n\n  const tableRows = allHeaders.map(header => {\n    const isSecurity = securityHeaders.includes(header.name.toLowerCase());\n    const warning = isSecurity && isWarningHeader(header.name, header.value);\n    const missing = isSecurity && !header.present;\n\n    let bgColor = '#F8F9FA';\n    let textColor = '#333';\n\n    if (isSecurity) {\n      if (missing) {\n        bgColor = '#FFEBEE';\n        textColor = '#C62828';\n      } else if (warning) {\n        bgColor = '#FFF9C4';\n        textColor = '#F57F17';\n      } else {\n        bgColor = '#E8F5E9';\n        textColor = '#2E7D32';\n      }\n    }\n\n    return `\n      <tr style=\"background-color: ${bgColor}; color: ${textColor};\">\n        <td title=\"${isSecurity ? (missing ? 'Missing' : (warning ? 'Needs review' : 'Secure')) : 'Informational'}\" style=\"padding: 8px; font-weight: bold;\">${header.name}</td>\n        <td style=\"padding: 8px; text-align: center;\">${header.present ? 'present' : 'absent'}</td>\n        <td style=\"padding: 8px; word-break: break-word; font-family: monospace;\">${formatLongValue(header.value)}</td>\n      </tr>`;\n  }).join('');\n\n  return `\n    <table style=\"width: 100%; border-collapse: collapse; margin-top: 10px;\">\n      <thead>\n        <tr style=\"background-color: #E0E0E0;\">\n          <th style=\"padding: 10px;\">Header</th>\n          <th style=\"padding: 10px;\">Status</th>\n          <th style=\"padding: 10px;\">Value</th>\n        </tr>\n      </thead>\n      <tbody>\n        ${tableRows}\n      </tbody>\n    </table>`;\n}\n\n// Format additional information section\nfunction formatAdditionalInfo() {\n  const headers = [\n    {\n      name: 'access-control-allow-origin',\n      description: 'This is a very lax CORS policy. Such a policy should only be used on a public CDN.'\n    },\n    {\n      name: 'strict-transport-security',\n      description: 'HTTP Strict Transport Security is an excellent feature to support on your site and strengthens your implementation of TLS by getting the User Agent to enforce the use of HTTPS.'\n    },\n    {\n      name: 'content-security-policy',\n      description: 'Content Security Policy is an effective measure to protect your site from XSS attacks. By whitelisting sources of approved content, you can prevent the browser from loading malicious assets. Analyse this policy in more detail. You can sign up for a free account on Report URI to collect reports about problems on your site.'\n    },\n    {\n      name: 'permissions-policy',\n      description: 'Permissions Policy is a new header that allows a site to control which features and APIs can be used in the browser.'\n    },\n    {\n      name: 'referrer-policy',\n      description: 'Referrer Policy is a new header that allows a site to control how much information the browser includes with navigations away from a document and should be set by all sites.'\n    },\n    {\n      name: 'x-content-type-options',\n      description: 'X-Content-Type-Options stops a browser from trying to MIME-sniff the content type and forces it to stick with the declared content-type. The only valid value for this header is \"X-Content-Type-Options: nosniff\".'\n    },\n    {\n      name: 'x-frame-options',\n      description: 'X-Frame-Options tells the browser whether you want to allow your site to be framed or not. By preventing a browser from framing your site you can defend against attacks like clickjacking.'\n    },\n    {\n      name: 'report-to',\n      description: 'Report-To enables the Reporting API. This allows a website to collect reports from the browser about various errors that may occur. You can sign up for a free account on Report URI to collect these reports.'\n    },\n    {\n      name: 'nel',\n      description: 'Network Error Logging is a new header that instructs the browser to send reports during various network or application errors. You can sign up for a free account on Report URI to collect these reports.'\n    },\n    {\n      name: 'server',\n      description: 'Server value has been changed. Typically you will see values like \"Microsoft-IIS/8.0\" or \"nginx 1.7.2\".'\n    }\n  ];\n  \n  let rows = '';\n  \n  for (const header of headers) {\n    const isSecurityHeader = ['content-security-policy', 'strict-transport-security', 'x-content-type-options', 'x-frame-options', 'referrer-policy', 'permissions-policy'].includes(header.name);\n    const headerColor = isSecurityHeader ? '#27AE60' : '#3498DB';\n    \n    rows += `\n      <tr>\n        <td style=\"padding: 8px; border-bottom: 1px solid #eee; color: ${headerColor}; font-weight: bold;\">${header.name}</td>\n        <td style=\"padding: 8px; border-bottom: 1px solid #eee;\">${header.description}</td>\n      </tr>\n    `;\n  }\n  \n  return `\n    <table style=\"width: 100%; border-collapse: collapse; margin-top: 10px;\">\n      <tbody>\n        ${rows}\n      </tbody>\n    </table>\n  `;\n}\n\nfunction formatSecurityGrade() {\n  const gradeColors = {\n    'A+': '#27AE60',\n    'A': '#27AE60',\n    'A-': '#27AE60',\n    'B+': '#3498DB',\n    'B': '#3498DB',\n    'B-': '#3498DB',\n    'C+': '#F39C12',\n    'C': '#F39C12',\n    'C-': '#F39C12',\n    'D+': '#E74C3C',\n    'D': '#E74C3C',\n    'D-': '#E74C3C',\n    'F': '#E74C3C'\n  };\n  \n  return `<div class=\"grade\" style=\"font-size: 64px; font-weight: bold; width: 100px; height: 100px; line-height: 100px; text-align: center; background-color: ${gradeColors[auditData.grade] || '#E74C3C'}; color: white; border-radius: 5px; margin: 0 auto;\">${auditData.grade}</div>`;\n}\n\nfunction formatCriticalVulnerabilities() {\n  if (!auditData.vulnOutput || auditData.vulnOutput.trim() === '') {\n    return '<p>No vulnerabilities detected.</p>';\n  }\n\n  try {\n    const vuln = auditData.vulnOutput.trim();\n    let html = '';\n    const renderedTitles = new Set();\n\n    // Match sections like ## Category (e.g., ## Critical Vulnerabilities)\n    const categories = vuln.split(/(?=^##\\s+)/gm).filter(Boolean);\n\n    for (const categoryBlock of categories) {\n      const categoryMatch = categoryBlock.match(/^##\\s+(.*)/);\n      const categoryTitle = categoryMatch?.[1]?.trim() || 'Uncategorized';\n\n      // Find numbered items: 1. **Title**\n      const vulns = categoryBlock.split(/(?=^\\d+\\.\\s+\\*\\*)/gm).filter(Boolean);\n\n      for (const vulnBlock of vulns) {\n        const titleMatch = vulnBlock.match(/^\\d+\\.\\s+\\*\\*(.*?)\\*\\*/);\n        const title = titleMatch?.[1]?.trim() || 'Unnamed Vulnerability';\n        const key = `${categoryTitle}::${title}`.toLowerCase();\n        if (renderedTitles.has(key)) continue;\n\n        const descriptionMatch = vulnBlock.match(/\\*\\*Description\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n        const impactMatch = vulnBlock.match(/\\*\\*(?:Impact|Potential Impact)\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n        const recommendationMatch = vulnBlock.match(/\\*\\*(?:Recommendation|Mitigation|Fix)\\*\\*:?\\s*([\\s\\S]*?)(?=\\n\\*\\*|\\n$)/i);\n\n        const description = descriptionMatch?.[1]?.trim() || '';\n        const impact = impactMatch?.[1]?.trim() || '';\n        const recommendation = recommendationMatch?.[1]?.trim() || '';\n\n        if (description || impact || recommendation) {\n          html += `\n            <div style=\"border-left: 4px solid #E74C3C; padding: 10px; margin-bottom: 15px;\">\n              <div style=\"font-weight: bold; color: #E74C3C;\">${title}</div>\n              ${description ? `<div style=\"margin-top: 5px;\">${description}</div>` : ''}\n              ${impact ? `<div style=\"margin-top: 5px; font-style: italic; color: #7F8C8D;\">Impact: ${impact}</div>` : ''}\n              ${recommendation ? `<div style=\"margin-top: 5px;\"><strong>Recommendation:</strong> ${recommendation}</div>` : ''}\n            </div>`;\n          renderedTitles.add(key);\n        }\n      }\n    }\n\n    return html || '<p>No vulnerabilities parsed from output.</p>';\n  } catch (e) {\n    console.error('Error in formatCriticalVulnerabilities:', e);\n    return `<p>Error processing vulnerabilities: ${e.message}</p>`;\n  }\n}\n\n\n// Generate all security header badges\nfunction generateAllHeaderBadges() {\n  // Only include the necessary security headers\n  const securityHeaders = [\n    'Content-Security-Policy',\n    'Strict-Transport-Security',\n    'X-Content-Type-Options',\n    'X-Frame-Options',\n    'Referrer-Policy',\n    'Permissions-Policy'\n  ];\n  \n  let badges = '';\n  securityHeaders.forEach(header => {\n                      \n    const isWarning = header === 'Strict-Transport-Security' &&\n                  auditData.headerStatus?.[header]?.value &&\n                  parseInt(auditData.headerStatus[header].value.match(/max-age=(\\d+)/)?.[1] || 0) < 2592000;\n    \n    badges += createHeaderBadge(header, isWarning);\n  });\n  \n  return badges;\n}\n\n<!-- Modify the HTML to directly access auditData.originalHeaders or allHeaders -->\nconst html = `<!DOCTYPE html>\n<html>\n<head>\n    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <title>Website Security Audit Report</title>\n    <style>\n        body { font-family: Arial, sans-serif; margin: 0; padding: 0; background-color: #f9f9f9; }\n        .container { max-width: 950px; margin: 0 auto; }\n        .header { background-color: #2c3e50; color: white; padding: 25px 20px; text-align: center; }\n        .header h1 { color: white; font-size: 28px; margin: 0; text-shadow: 1px 1px 2px rgba(0,0,0,0.5); }\n        .content { padding: 20px; }\n        .summary-box { background-color: #EBF5FB; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .warning-box { background-color: #FEF5E7; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .headers-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; }\n        .findings-box { background-color: white; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .raw-headers-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .additional-info-box { background-color: #F5F7FA; padding: 15px; margin-bottom: 20px; border-radius: 5px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .details-table { width: 100%; border-collapse: collapse; }\n        .details-table th { text-align: left; padding: 8px; background-color: #f2f2f2; }\n        .details-table td { padding: 8px; border-bottom: 1px solid #eee; }\n        .header-badges { margin-top: 10px; }\n        h1, h2, h3 { color: #2c3e50; }\n        .critical-item { border-left: 4px solid #E74C3C; padding: 10px; margin-bottom: 15px; }\n        .critical-title { font-weight: bold; color: #E74C3C; }\n        .config-item { border-left: 4px solid #3498DB; padding: 10px; margin-bottom: 15px; }\n        .config-title { font-weight: bold; color: #3498DB; }\n        pre { background-color: #f8f9fa; padding: 10px; border-radius: 5px; overflow-x: auto; font-family: monospace; margin-top: 5px; }\n    </style>\n</head>\n<body>\n    <div class=\"container\">\n        <!-- Report Header -->\n        <div class=\"header\">\n            <h1 style=\"color: white; text-shadow: 1px 1px 2px rgba(0,0,0,0.5);\">Website Security Audit Report</h1>\n        </div>\n        \n        <div class=\"content\">\n            <!-- Security Report Summary -->\n            <div class=\"summary-box\">\n                <h2>Security Report Summary</h2>\n                <table style=\"width: 100%;\">\n                    <tr>\n                        <td style=\"width: 120px;\" valign=\"top\">\n                            ${formatSecurityGrade()}\n                        </td>\n                        <td valign=\"top\">\n                            <table style=\"width: 100%;\">\n                                <tr>\n                                    <td><strong>Site:</strong></td>\n                                    <td><a href=\"${auditData.url}\" style=\"color: #3498db;\">${auditData.url}</a></td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Report Time:</strong></td>\n                                    <td>${auditData.timestamp}</td>\n                                </tr>\n                                <tr>\n                                    <td valign=\"top\"><strong>Headers:</strong></td>\n                                    <td>\n                                        <div class=\"header-badges\">\n                                            ${generateAllHeaderBadges()}\n                                        </div>\n                                    </td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Critical Issues:</strong></td>\n                                    <td>${auditData.criticalCount || 0}</td>\n                                </tr>\n                                <tr>\n                                    <td><strong>Warnings:</strong></td>\n                                    <td>${auditData.warningCount || 0}</td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                </table>\n            </div>\n\n            <!-- Warnings Section -->\n            <div class=\"warning-box\">\n                <h2>Warnings</h2>\n                ${formatWarningsSection()}\n            </div>\n\n            <!-- Raw Headers Section -->\n            <div class=\"raw-headers-box\">\n                <h2>Raw Headers</h2>\n                ${formatDetailedRawHeaders()}\n            </div>\n\n            <!-- Security Findings -->\n            <div class=\"findings-box\">\n                <h2>Security Findings</h2>\n                \n                <!-- Vulnerabilities -->\n                <h3>Vulnerabilities</h3>\n                ${formatCriticalVulnerabilities()}\n                \n                <!-- Configuration Issues -->\n                <h3>Configuration Issues</h3>\n                ${formatConfigurationIssues()}\n            </div>\n            \n            <div class=\"additional-info-box\">\n              <h2>Additional Information</h2>\n              ${formatAdditionalInfo()}\n            </div>\n            \n            <!-- Implementation Guide -->\n            <div class=\"findings-box\">\n                <h2>Implementation Guide</h2>\n                <p>This report highlights security issues detected through client-side analysis. For a comprehensive security assessment, consider engaging a professional penetration tester.</p>\n                \n                <div style=\"background-color: #eafaf1; padding: 15px; margin-top: 15px; border-left: 4px solid #2ecc71; border-radius: 3px;\">\n                    <p><strong>To implement the fixes above:</strong></p>\n                    <ol style=\"padding-left: 20px; margin-top: 10px;\">\n                        <li>Work with your development team to address each issue in order of criticality</li>\n                        <li>Retest after implementing each fix</li>\n                        <li>Consider implementing a web application firewall for additional protection</li>\n                    </ol>\n                </div>\n            </div>\n            \n            <!-- Footer -->\n            <div style=\"text-align: center; padding: 20px; font-size: 12px; color: #777;\">\n                <p>This report was automatically generated and represents an automated assessment of publicly accessible aspects of your website. For a more comprehensive security assessment, consider engaging with a professional security consultant.</p>\n                <p>&copy; 2025 Website Security Scanner | Generated on ${auditData.timestamp}</p>\n            </div>\n        </div>\n    </div>\n</body>\n</html>`;\n\nreturn [{\n  json: {\n    ...items[0].json,\n    emailHtml: html\n  }\n}];"},"typeVersion":2}],"connections":{"Scrape Website":{"main":[[{"node":"Security Vulnerabilities Audit","type":"main","index":0},{"node":"Extract Headers for Debug","type":"main","index":0}]]},"convert to HTML":{"main":[[{"node":"Send Security Report","type":"main","index":0}]]},"Landing Page Url":{"main":[[{"node":"Scrape Website","type":"main","index":0}]]},"Process Audit Results":{"main":[[{"node":"convert to HTML","type":"main","index":0}]]},"Merge Security Results":{"main":[[{"node":"Aggregate Audit Results","type":"main","index":0}]]},"Aggregate Audit Results":{"main":[[{"node":"Process Audit Results","type":"main","index":0}]]},"OpenAI Content Analysis":{"ai_languageModel":[[{"node":"Security Vulnerabilities Audit","type":"ai_languageModel","index":0}]]},"OpenAI Headers Analysis":{"ai_languageModel":[[{"node":"Security Configuration Audit","type":"ai_languageModel","index":0}]]},"Extract Headers for Debug":{"main":[[{"node":"Security Configuration Audit","type":"main","index":0}]]},"Security Configuration Audit":{"main":[[{"node":"Merge Security Results","type":"main","index":0}]]},"Security Vulnerabilities Audit":{"main":[[{"node":"Merge Security Results","type":"main","index":1}]]}}}


name: Automate Blog Content Creation with GPT-4, Perplexity & WordPress
author_name: Dr. Firas
author_username: drfiras
categories: []
created_at: 2025-03-26T21:04:55.087Z
updated_at: 2025-03-26T21:04:55.087Z
url: https://n8n.io/workflows/3336
scraped_at: 2025-07-06 21:16:30
description:
  Who Is This For

  This workflow is ideal for content creators, solo founders, marketers, and AI enthusiasts who want to automate the full process of blog content creation.  
  It is especially useful for professionals in tech, AI, and automation who publish frequently and need SEO-ready content fast.

  What Problem Does This Workflow Solve

  Creating SEO-optimized blog content is time-consuming and requires consistency.  
  Manually researching trending topics slows down the content pipeline.  
  Formatting, publishing, and promoting across multiple platforms takes effort.  
  This workflow automates the entire process from research to publication.

  What This Workflow Does

  Research: Uses Perplexity AI to gather up-to-date content ideas via form input.  
  Content Generation: GPT-4 creates a short, SEO-optimized article (max 20 lines) with H1, H2 structure and meta-description.  
  Publishing: Automatically posts the content to WordPress.  
  Email Notification: Sends the article title and URL via Gmail.  
  Slack Notification: Notifies a specified Slack channel when the article is live.  
  Database Logging: Saves the article details to a Notion database.

  Setup Guide

  Prerequisites

  WordPress account with API access  
  OpenAI API Key  
  Perplexity API Key  
  Slack Bot Token  
  Notion integration (Database ID)  
  Gmail API credentials (optional)  
  Community Node Required: This workflow uses n8n-nodes-mcp, which only works on self-hosted instances of n8n.  
    &gt; To install: Go to Settings &gt; Community Nodes &gt; Install n8n-nodes-mcp

  Steps

  Import the workflow into your n8n instance  
  Install the required community node (n8n-nodes-mcp)  
  Set up API credentials for OpenAI, Perplexity, WordPress, Slack, Gmail, and Notion  
  Customize the form trigger with your preferred prompt  
  Run a test using a sample topic

  How to Customize This Workflow

  Modify the research prompt to match your niche or industry  
  Adjust GPT-4 settings for tone, structure, or content length  
  Customize Notion fields (e.g., add tags, categories, or labels)  
  Add logic for generating or assigning featured images automatically

nodes_used:
  ["n8n-nodes-base.httpRequest","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"id":"L1UcBZ9UJvN9gnSb","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"💥🛠️Automate Blog Content Creation with GPT-4, Perplexity & WordPress","tags":[],"nodes":[{"id":"b86a4b08-6fb6-4ebc-8ddb-f1cd0e4b1492","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[0,0],"parameters":{"color":4,"width":460,"height":300,"content":"## Perplexity Section\n🌐 Calls Perplexity API to get fresh research based on a form input.\n\n\n"},"typeVersion":1},{"id":"16509f9d-ce54-4dab-b3ff-24760b0bde09","name":"Perplexity Research","type":"n8n-nodes-base.httpRequest","position":[80,100],"parameters":{"url":"https://api.perplexity.ai/chat/completions","method":"POST","options":{},"jsonBody":"={\n  \"model\": \"sonar-pro\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"Act as a professional news researcher who is capable of finding detailed summaries about a news topic from highly reputable sources.\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \" Research the following topic and return everything you can find about: '{{ $json['Topic or Question'] }}'.\"\n    }\n  ]\n}\n","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"DB99xYLrmwZl7Sqf","name":"Header Auth account"}},"typeVersion":4.2},{"id":"500b2464-88b1-44f5-bcc4-12c0acdc5773","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[560,0],"webhookId":"b132ff74-2807-4cbf-b5b7-a62a207161d3","parameters":{"options":{}},"typeVersion":1.1},{"id":"aec9523b-245a-48ff-a860-3239b869f676","name":"Slack-List","type":"n8n-nodes-mcp.mcpClientTool","position":[1500,400],"parameters":{},"credentials":{"mcpClientApi":{"id":"mC6b1h1p0lFikSzU","name":"slack"}},"typeVersion":1},{"id":"1ecdcfed-c5d4-4ddc-aeb1-e760d295e5bc","name":"Copywriting AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[1020,100],"parameters":{"text":"=You are an expert in SEO content writing.\n\nYour mission is to create, publish, and notify about a search engine optimized article for a blog focused on artificial intelligence. Follow the steps below: {{ $('Format Research Output').item.json.research }}\n\n1. **Write an SEO-optimized article with a maximum of 20 lines** based on the provided information:\n   - Structure the article with a catchy **H1 title**, one or two **H2 subtitles**, and a professional yet accessible tone.\n   - Extract and include relevant keywords from the data.\n   - Optimize for readability: short sentences, clear paragraphs, and a CTA if relevant.\n   - Do not exceed 20 lines of content.\n\n2. **Publish the article on WordPress**, including:\n   - The **title** as the article's headline\n   - The **SEO content** as the body\n\n3. **Send an email** to my address : {{ $json.emailAddress }} containing:\n   - The article's title\n   - The **URL** of the published article on WordPress\n\n4. **Retrieve the list of available Slack tools first** using “Slack Tools”.\n   - Then, send a notification on Slack that the article has been published, including:\n     - The article title\n     - The article link\n     - Slack channel ID: {{ $json.slackChannelId }}\n\n5. **Retrieve the list of available Notion tools first** using “Notion Tools”.\n   Then, **add a new entry to my Notion database** (ID: {{ $json.notionDatabaseId }}) with the following fields:\n   - The 'Name' column is of type 'title'  → {{ $('Start with Research Query Submission').item.json['Topic or Question'] }}\n   The 'Subject' column is of type 'rich_text' → [the article's headline]\n   - The 'Content'column is of type 'rich_text' → [The SEO content]\n   - The 'URL' column is of type 'URL': → [The article link]\n   - The 'Status' column is of type 'select' → Select: `publish`\n\nImportant: Ensure that each step is successfully completed **before proceeding to the next**.\n","options":{},"promptType":"define"},"typeVersion":1.7},{"id":"aaab95dd-7fd2-411e-ba05-fa84568c0d56","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[480,-180],"parameters":{"width":1300,"height":820,"content":"## My Copywriting AI Agent\n✍️ Transforms live research into SEO-optimized blog articles using GPT-4, then automatically publishes to WordPress, sends notifications via Gmail & Slack, and logs everything to Notion. This is your full-stack content assistant — from prompt to post, hands-free.\n**mcp-notion-server** : [Guide](https://github.com/suekou/mcp-notion-server)\n**mcp-slack-server** : [Guide](https://github.com/modelcontextprotocol/servers/tree/main/src/slack)"},"typeVersion":1},{"id":"d3cbf58c-7c14-4695-8331-1750daf21d0d","name":"Format Research Output","type":"n8n-nodes-base.set","position":[280,100],"parameters":{"options":{},"assignments":{"assignments":[{"id":"23b8e8c4-9191-415a-9661-1b60d413528a","name":"research","type":"string","value":"={{ $json.choices[0].message.content.replaceAll(\"[1]\", \" - source: \" +$json.citations[0]).replaceAll(\"[2]\",\" - source:\" +$json.citations[1]).replaceAll(\"[3]\",\" - source: \" +$json.citations[2]).replaceAll(\"[4]\",\" - source: \"+$json.citations[3]).replaceAll(\"[5]\",\" - source: \"+$json.citations[4]).replaceAll(\"[6]\",\" - source: \"+$json.citations[5]).replaceAll(\"[7]\",\" - source: \"+$json.citations[6]).replaceAll(\"[8]\",\" - source: \"+$json.citations[7]).replaceAll(\"[9]\",\" - source: \"+$json.citations[8]).replaceAll(\"[10]\",\" - source: \"+$json.citations[9]) }}"}]}},"typeVersion":3.4},{"id":"cd073bb3-3b6a-4910-9de4-bef66fc00a1f","name":"Publish Article to WordPress","type":"n8n-nodes-base.wordpressTool","position":[840,400],"parameters":{"title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', ``, 'string') }}","additionalFields":{"status":"publish","content":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', ``, 'string') }}"}},"credentials":{"wordpressApi":{"id":"KIuXvzjOEnOsHKQE","name":"Wordpress account"}},"typeVersion":1},{"id":"6940575a-d504-4276-8964-c41f26418f3c","name":"Send Email Notification","type":"n8n-nodes-base.gmailTool","position":[1360,400],"webhookId":"b68c6af8-46e6-4ed9-ae72-445e9cb7ab88","parameters":{"sendTo":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('To', ``, 'string') }}","message":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message', ``, 'string') }}","options":{},"subject":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Subject', ``, 'string') }}"},"credentials":{"gmailOAuth2":{"id":"rKxQHWZ2F5XLJmwF","name":"Gmail account"}},"typeVersion":2.1},{"id":"da3c994c-60d5-41ef-9cf9-52daa77dc980","name":"Notify Slack Channel","type":"n8n-nodes-mcp.mcpClientTool","position":[1640,400],"parameters":{"toolName":"={{ $fromAI(\"tool\", \"the tool selected\")  }}","operation":"executeTool","toolParameters":"={{ $fromAI('Tool_Parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"mC6b1h1p0lFikSzU","name":"slack"}},"typeVersion":1},{"id":"9d36b649-f5e6-442c-bcab-53f0ca0dc2c2","name":"Generate SEO Blog Content (GPT-4o)","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[600,400],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"7a034005-68a3-40fa-bb94-cfdfab717cfc","name":"Start with Research Query Submission","type":"n8n-nodes-base.formTrigger","position":[-180,100],"webhookId":"a29cbcd3-9d11-4f7c-9aad-14681c356c53","parameters":{"options":{},"formTitle":"AutoBlog Creator","formFields":{"values":[{"fieldType":"textarea","fieldLabel":"Topic or Question","placeholder":"=How is GPT-4 transforming content creation in 2025?","requiredField":true}]},"formDescription":"From research to article — no writing required"},"typeVersion":2.2},{"id":"8cbad4aa-1802-4275-bbc4-c4d17673cd23","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[0,-180],"parameters":{"color":3,"width":460,"height":140,"content":"## Intro Sticky \n🔁 **This workflow automates the full cycle of SEO blog content creation** — from live topic research using Perplexity to blog publishing on WordPress, Slack/Gmail notifications, and Notion logging."},"typeVersion":1},{"id":"93e258e4-baa2-4af2-ba12-0f1727150e19","name":"Edit Workflow Variables","type":"n8n-nodes-base.set","position":[120,460],"parameters":{"options":{},"assignments":{"assignments":[{"id":"c06b2d24-1fd7-40f0-aee5-b5d6553e289e","name":"emailAddress","type":"string","value":""},{"id":"451aad67-5190-4eab-a982-56092734bb07","name":"slackChannelId","type":"string","value":""},{"id":"8a294900-f367-47a2-b260-344b133dc2ff","name":"notionDatabaseId","type":"string","value":""}]}},"typeVersion":3.4,"alwaysOutputData":true},{"id":"88cb2c49-be54-4df9-81ff-d709bde839e1","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[0,340],"parameters":{"color":6,"width":460,"height":300,"content":"## Workflow Configuration Panel\n🛠️ **Set your variables here** (email, Slack, Notion, OpenAI model)"},"typeVersion":1},{"id":"5075e00d-f1e9-4db2-85c1-d4d851f57abf","name":"Notion-List","type":"n8n-nodes-mcp.mcpClientTool","position":[1000,400],"parameters":{},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1},{"id":"edf2d95b-b04d-40f9-9b8d-b53dd5912bab","name":"Insert Article in Notion","type":"n8n-nodes-mcp.mcpClientTool","position":[1180,400],"parameters":{"toolName":"={{ $fromAI(\"tool\", \"the tool selected\")  }}","operation":"executeTool","toolParameters":"={{ $fromAI('tool_parameters', ``, 'json') }}"},"credentials":{"mcpClientApi":{"id":"QQbMEB7i2XAAWTSc","name":"Notion"}},"typeVersion":1}],"active":true,"settings":{"executionOrder":"v1"},"versionId":"553f26d7-2dcf-4900-871e-b3aa25a68ffa","connections":{"Slack-List":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Notion-List":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Perplexity Research":{"main":[[{"node":"Format Research Output","type":"main","index":0}]]},"Notify Slack Channel":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Format Research Output":{"main":[[{"node":"Edit Workflow Variables","type":"main","index":0}]]},"Edit Workflow Variables":{"main":[[{"node":"Copywriting AI Agent","type":"main","index":0}]]},"Send Email Notification":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Insert Article in Notion":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"When chat message received":{"main":[[{"node":"Copywriting AI Agent","type":"main","index":0}]]},"Publish Article to WordPress":{"ai_tool":[[{"node":"Copywriting AI Agent","type":"ai_tool","index":0}]]},"Generate SEO Blog Content (GPT-4o)":{"ai_languageModel":[[{"node":"Copywriting AI Agent","type":"ai_languageModel","index":0}]]},"Start with Research Query Submission":{"main":[[{"node":"Perplexity Research","type":"main","index":0}]]}}}


name: Telegram AI Bot-to-Human Handoff for Sales Calls
author_name: Jimleuk
author_username: jimleuk
categories: []
created_at: 2025-03-29T15:23:05.743Z
updated_at: 2025-03-29T15:23:05.743Z
url: https://n8n.io/workflows/3350
scraped_at: 2025-07-06 21:16:30
description:
  This n8n template demonstrates an approach to perform bot-to-human handoff using Human-in-the-loop functionality as a switch.

  In this experiment, we play with the idea of states we want our agent to be in which controls it's interacton with the user.
  First state** - the agent is onboarding the user by collecting their details for a sales inquiry. After which, they are handed-off / transferred to a human to continue the call.
  Second state** - the agent is essentially "deactivated" as further messages to the bot will not reach it. Instead, a canned response is given to the user. The human agent must "reactivate" the bot by completing the human-in-the-loop form and give a summary of their conversation with the user.
  Third state** - the agent is "reactivated" with context of the human-to-user conversation and is set to provide after sales assistance. An tool is made available to the agent to again delegate back to the human agent when requested.

  How it works
  This template uses telegram to handle the interaction between the user and the agent.
  Each user message is checked for a session state to ensure it is guided to the right stage of the conversation. For this, we can use Redis as a simple key-value store.
  When no state is set, the user is directed through an onboarding step to attain their details. Once complete, the agent will "transfer" the user to a human agent - technically, all this involves is an update to the session state and a message to another chat forwarding the user's details.
  During this "human" state, the agent cannot reply to the user and must wait until the human "transfers" the conversation back. The human can do this by replying to "human-in-the-loop" message with a summary of their conversation with the user. This session state now changes to "bot" and the context is implanted in the agent's memory so that the agent can respond to future questions.
  At this stage of the conversation, the agent is now expected to handle and help the user with after-sales questions. The user can at anytime request transfer back to the human agent, repeating the previous steps as necessary.

  How to use
  Plan your user journey! Here is a very basic example of a sales inquiry with at most 3 states. More thought should be developed when many more states are involved.
  You may want to better log and manage session states so no user is left in limbo. Try connecting the user and sessions to your CRM.
  Note, the Onboarding agent and After-Sales agent have separate chat memories. When adding more agents, it is recommend to continue having separate chat memories to help focus between states.

  Requirements
  Telegram for chatbot & interface
  Redis for session store and chat memory
  OpenAI for AI agent

  Customising this workflow
  Not using Telegram? This template works with Whatsapp and other services with equivalent functionality.

nodes_used:
  ["n8n-nodes-base.redis","n8n-nodes-base.telegram","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryRedisChat","@n8n/n8n-nodes-langchain.toolWorkflow","@n8n/n8n-nodes-langchain.memoryManager","@n8n/n8n-nodes-langchain.informationExtractor"]

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"5d6a5a45-8aa8-4c34-aa10-5dd85f05de9d","name":"Human Handoff using Send and Wait","type":"n8n-nodes-base.telegram","position":[1580,1040],"webhookId":"d2bbc82f-0509-470a-af4d-9d92cfed4d5f","parameters":{"chatId":"=<human chat id>","message":"=chatId: {{ $('Handoff Subworkflow').first().json.chatId }}\nsessionId: {{ $('Handoff Subworkflow').first().json.sessionId }}\nuser: {{ $('Handoff Subworkflow').first().json.username }} ({{ $('Handoff Subworkflow').item.json.userId }})\n\nSummary:\n{{ $('Handoff Subworkflow').item.json.summary }}\n\n---\nThis user has now been handed off to a human.\nClick the button to return user to bot.","options":{},"operation":"sendAndWait","responseType":"freeText"},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"5d2f73ff-b233-4456-b34d-d5a5454dabda","name":"Set Interaction to Bot","type":"n8n-nodes-base.redis","position":[1780,1040],"parameters":{"key":"=handoff_{{ $('Handoff Subworkflow').first().json.sessionId }}_state","value":"bot","keyType":"string","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"f799e213-f3ed-4479-aade-7a7c38eb5792","name":"Set Interaction to Human","type":"n8n-nodes-base.redis","position":[1380,1040],"parameters":{"key":"=handoff_{{ $json.sessionId }}_state","value":"=human","keyType":"string","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"059c9b8c-ba50-4bdd-8969-6f5f35bba304","name":"Get Interaction State","type":"n8n-nodes-base.redis","position":[-800,820],"parameters":{"key":"=handoff_{{ $json.message.chat.id }}_state","options":{},"operation":"get","propertyName":"data"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"8afd48ff-478d-4092-ac88-fb2e435ded00","name":"Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-280,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"19c5ef66-410d-47fd-9b2a-19776c53a681","name":"Memory","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[-160,640],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat","sessionIdType":"customKey"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.4},{"id":"814e464d-a2e0-4ae1-83d1-df3732d3b430","name":"Handoff Subworkflow","type":"n8n-nodes-base.executeWorkflowTrigger","position":[980,1040],"parameters":{"workflowInputs":{"values":[{"name":"chatId"},{"name":"sessionId"},{"name":"userId"},{"name":"username"},{"name":"summary"}]}},"typeVersion":1.1},{"id":"53c311ca-b7ad-4705-97c9-f6438a6c6b4e","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-1000,820],"webhookId":"e905dd99-eefc-48ff-a62d-c7078e9bb216","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.1},{"id":"ea54c9f7-8ebc-4146-a4ec-6d05957f340d","name":"Send Response","type":"n8n-nodes-base.telegram","position":[1400,340],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=Thank you. I've now transferred you to a human agent who will reach out to you. Once complete, you can come back to this chat to finish the process.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"7f895e2a-7aee-40be-a8b7-b2b0ff469b2d","name":"Switch Interaction","type":"n8n-nodes-base.switch","position":[-620,820],"parameters":{"rules":{"values":[{"outputKey":"Human","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6bc61072-f7cf-4a6d-af81-36abede59d47","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.data }}","rightValue":"human"}]},"renameOutput":true},{"outputKey":"Bot","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"6882db64-b522-4895-8949-d98d87b53b49","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data }}","rightValue":"bot"}]},"renameOutput":true}]},"options":{"fallbackOutput":"extra","renameFallbackOutput":"Onboarding"}},"typeVersion":3.2},{"id":"df203358-e6c7-4014-8e2b-ef934e331215","name":"Information Extractor","type":"@n8n/n8n-nodes-langchain.informationExtractor","position":[440,460],"parameters":{"text":"={{\n$json.data\n  .reverse()\n  .slice(0, 5)\n  .map(item => item.parseJson())\n  .map(item => `${item.type}: ${item.data.content}`)\n  .join('\\n')\n}}","options":{"systemPromptTemplate":"Analyse the conversation history and extract the required customer details. If not found, leave blank."},"attributes":{"attributes":[{"name":"firstname","required":true,"description":"first name of customer"},{"name":"lastname","required":true,"description":"last name of customer"},{"name":"address_and_postcode","required":true,"description":"address and postcode of customer"},{"name":"reason_for_call","required":true,"description":"a summary of the reason for the call"}]}},"typeVersion":1},{"id":"35bc11d2-6024-425b-ac67-a61ff26b9478","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[420,640],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"20d71c5f-6e84-4b45-b324-0706ecd3a681","name":"With Defaults","type":"n8n-nodes-base.code","position":[760,460],"parameters":{"mode":"runOnceForEachItem","jsCode":"return {\n  \"firstname\": \"\",\n  \"lastname\": \"\",\n  \"address_and_postcode\": \"\",\n  \"reason_for_call\": \"\",\n  ...$input.item.json.output,\n}"},"typeVersion":2},{"id":"76344f79-1afa-4fd9-9c01-ca3818f62f37","name":"Has All Criteria?","type":"n8n-nodes-base.if","position":[920,460],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"96d4a43f-aa0f-486a-b692-0105196d099a","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ Object.values($json).every(val => Boolean(val)) }}","rightValue":""}]}},"typeVersion":2.2},{"id":"f76c1032-036b-46ad-91da-023d5af931fd","name":"Onboarding Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-240,460],"parameters":{"text":"={{ $('Telegram Trigger').first().json.message.text }}","options":{"systemMessage":"=You are a prescreen assistant whose task is to get the following details from a customer before handing them over to a human agent.\n* first name\n* last name\n* address and postcode\n* reason for calling - capture exact wording if possible.\n\nOnce all data is gathered, hand the user off to a human agent."},"promptType":"define"},"typeVersion":1.8},{"id":"0a5b19a5-9c19-436c-b1d3-23d962efd23e","name":"Get Onboarding Chat History","type":"n8n-nodes-base.redis","position":[280,460],"parameters":{"key":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat","options":{},"operation":"get","propertyName":"data"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"4f247eb3-78f0-4ec1-8713-1373da07b5f3","name":"After Sales Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[340,1000],"parameters":{"text":"={{ $('Telegram Trigger').item.json.message.text }}","options":{"systemMessage":"You are an aftersales agent helping the user answer questions about their recent purchase."},"promptType":"define"},"typeVersion":1.8},{"id":"bce26253-f7da-49e8-952b-52e14eb4f9b5","name":"Memory1","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[420,1180],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.4},{"id":"51c4549b-559c-400d-9951-dde0953ade4c","name":"Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[300,1180],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"63b8d9e8-7af2-4103-a365-ca5471bd7b36","name":"Handoff Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[540,1180],"parameters":{"name":"handoff_to_human","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Call this tool to handoff or defer to a human agent at the request of the customer. Ensure a summary of the reason for the handoff is obtained first.","workflowInputs":{"value":{"chatId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}","userId":"={{ $('Telegram Trigger').first().json.message.from.id.toString() }}","summary":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('summary', `Reason for human hand-off`, 'string') }}","username":"={{ $('Telegram Trigger').first().json.message.from.username }}","sessionId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}"},"schema":[{"id":"chatId","type":"string","display":true,"removed":false,"required":false,"displayName":"chatId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"userId","type":"string","display":true,"removed":false,"required":false,"displayName":"userId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"username","type":"string","display":true,"removed":false,"required":false,"displayName":"username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"summary","type":"string","display":true,"removed":false,"required":false,"displayName":"summary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2},{"id":"9a2b9077-0ead-4f2c-9e83-05ee341ff697","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1080,580],"parameters":{"color":7,"width":660,"height":460,"content":"## 1. Check Interaction State For Incoming Message\n[Learn more about the telegram trigger](https://docs.n8n.io/integrations/builtin/trigger-nodes/n8n-nodes-base.telegramtrigger/)\n\nThis is an example of a state-based agent - the technique commonly known as a finite-state machine. This is a great way to really control the flow and direction of the conversation where there are requirements to collect data or perform steps in sequence. To manage the session state, we can use Redis and the session key will be the user's number."},"typeVersion":1},{"id":"ccca9a5c-595a-4c58-9316-933a8234ab91","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-380,260],"parameters":{"color":7,"width":560,"height":520,"content":"## 2. Onboarding Agent to Validate Customers\n[Read more about Agents](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.agent)\n\nThis agent unlike the common multi-tasking examples out there, is only tasked to handle the user's onboarding. In this way, we trade convenience for clutter but ensure the agent is less likely to stray from the desired path."},"typeVersion":1},{"id":"2d859430-1326-4cbc-a5cc-3af0d091e5c0","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[200,260],"parameters":{"color":7,"width":880,"height":520,"content":"## 3. Extract Customer Details from Conversation\n[Learn more about the Information Extractor](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor)\n\nTo collect the user's details in a structured format, we can analyse the current conversation and extract the data with the Information Extractor node. This allows the conversation to remain free-form and avoids asking a question for each field. We use a code node to check if all details are captured."},"typeVersion":1},{"id":"754f0859-8af7-4a15-8e46-c9ad62b55bf3","name":"Handoff Subworkflow1","type":"n8n-nodes-base.executeWorkflow","position":[1220,340],"parameters":{"mode":"each","options":{"waitForSubWorkflow":false},"workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"workflowInputs":{"value":{"chatId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}","userId":"={{ $('Telegram Trigger').first().json.message.from.id.toString() }}","summary":"=name: {{ $json.firstname }} {{ $json.lastname }}\naddress: {{ $json.address_and_postcode }}\nsummary: {{ $json.reason_for_call }}","username":"={{ $('Telegram Trigger').first().json.message.from.username }}","sessionId":"={{ $('Telegram Trigger').first().json.message.chat.id.toString() }}"},"schema":[{"id":"chatId","type":"string","display":true,"required":false,"displayName":"chatId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"userId","type":"string","display":true,"required":false,"displayName":"userId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"username","type":"string","display":true,"required":false,"displayName":"username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"summary","type":"string","display":true,"required":false,"displayName":"summary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":true}},"typeVersion":1.2},{"id":"6f92128f-14dc-4b0a-b098-3d9535ac11e3","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1100,140],"parameters":{"color":7,"width":800,"height":640,"content":"## 4. Human Handoff when Criteria Met\n[Learn more about subworkflows](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow)\n\nHere, we initiate the hand-off which calls our hand-off subworkflow. Subworkflows can be a great way to run actions concurrently and without blocking the reply to the user. At this point, the session state would be set to \"human\" which means the human agent should take over."},"typeVersion":1},{"id":"14500c4f-da43-460f-bf4d-80d0a2f4537b","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-380,800],"parameters":{"color":7,"width":520,"height":440,"content":"## 5. Defer to Human\n\nWhen session state is \"human\", no further user messages can reach the agent. This is to ensure there isn't a parallel conversation happening which may confuse the human and agent."},"typeVersion":1},{"id":"4d74d479-8525-4b64-8291-e2b3058edeaa","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[160,800],"parameters":{"color":7,"width":720,"height":520,"content":"## 6. Interaction Switched Back to Bot\n[Read more about the Customer Workflow Tool](https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.toolworkflow/)\n\nWhen the session state is \"bot\", it signals the human agent has \"transferred\" the user back to the bot and so can continue processing their messages. A Custom Workflow Tool is used to retrigger the hand-off process whenever the user requests for it."},"typeVersion":1},{"id":"a1c064d9-cc74-475d-b233-9deb4dfa81d7","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[920,820],"parameters":{"color":7,"width":1580,"height":560,"content":"## 7. Interaction Subworkflow\n[Learn more about n8n's human-in-the-loop feature](https://docs.n8n.io/advanced-ai/examples/human-fallback/)\n\nThe hand-off implementation here involves a \"human-in-the-loop\" feature of n8n - a feature which \"pauses\" an execution whilst running until a reply or action is sent back by the human. Sounds complicated but good to note that n8n handles this interaction seemlessly! Here, we're using it to allow the human agent to reliquish control of the conversation back to the AI agent. Additionally, the human agent's feedback is captured and added to the agent's memory to better assist the user afterwards."},"typeVersion":1},{"id":"33684768-2f21-4f30-9e56-934171b215fc","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1580,-260],"parameters":{"width":440,"height":1320,"content":"## Try it out\n### This n8n template demonstrates an approach to perform bot-to-human handoff using Human-in-the-loop functionality as a switch.\n\nIn this experiment, we play with the idea of states we want our agent to be in which controls it's interacton with the user.\n* **First state** - the agent is onboarding the user by collecting their details for a sales inquiry. After which, they are handed-off / transferred to a human to continue the call.\n* **Second state** - the agent is essentially \"deactivated\" as further messages to the bot will not reach it. Instead, a canned response is given to the user. The human agent must \"reactivate\" the bot by completing the human-in-the-loop form and give a summary of their conversation with the user.\n* **Third state** - the agent is \"reactivated\" with context of the human-to-user conversation and is set to provide after sales assistance. An tool is made available to the agent to again delegate back to the human agent when requested.\n\n### How it works\n* This template uses telegram to handle the interaction between the user and the agent.\n* Each user message is checked for a session state to ensure it is guided to the right stage of the conversation. For this, we can use Redis as a simple key-value store.\n* When no state is set, the user is directed through an onboarding step to attain their details. Once complete, the agent will \"transfer\" the user to a human agent - technically, all this involves is an update to the session state and a message to another chat forwarding the user's details.\n* During this \"human\" state, the agent cannot reply to the user and must wait until the human \"transfers\" the conversation back. The human can do this by replying to \"human-in-the-loop\" message with a summary of their conversation with the user. This session state now changes to \"bot\" and the context is implanted in the agent's memory so that the agent can respond to future questions.\n* At this stage of the conversation, the agent is now expected to handle and help the user with after-sales questions. The user can at anytime request transfer back to the human agent, repeating the previous steps as necessary.\n\n#### How to use\n* Plan your user journey! Here is a very basic example of a sales inquiry with at most 3 states. More thought should be developed when many more states are involved.\n* You may want to better log and manage session states so no user is left in limbo. Try connecting the user and sessions to your CRM.\n* Note, the Onboarding agent and After-Sales agent have separate chat memories. When adding more agents, it is recommend to continue having separate chat memories to help focus between states.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!"},"typeVersion":1},{"id":"187ca5ef-c804-4aca-8ad9-3c4b11676fbf","name":"Send Response2","type":"n8n-nodes-base.telegram","position":[2320,1040],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=Hello again! I'm now ready to answer any remaining questions you may have.","chatId":"={{ $('Handoff Subworkflow').first().json.chatId }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"ab036106-84f2-4cf7-a5ad-7706a9e5ea0a","name":"Memory2","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[1980,1200],"parameters":{"sessionKey":"=handoff_{{ $('Handoff Subworkflow').first().json.chatId }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.5},{"id":"9d9d1aee-5632-499c-968d-63a555cc58d8","name":"Update Agent Memory","type":"@n8n/n8n-nodes-langchain.memoryManager","position":[1980,1040],"parameters":{"mode":"insert","messages":{"messageValues":[{"type":"ai","message":"=Report from human agent says \"{{ $('Human Handoff using Send and Wait').first().json.data.text }}\"","hideFromUI":true},{"type":"ai","message":"Hello again! I'm now ready to answer any remaining questions you may have."}]}},"typeVersion":1.1},{"id":"8da2fefa-e51f-4258-8ded-e0f20db87641","name":"Send Response3","type":"n8n-nodes-base.telegram","position":[680,1000],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"f027afe0-0fd2-47a2-a0f8-f0d78f8fbc18","name":"Get Canned Response","type":"n8n-nodes-base.telegram","position":[-180,1000],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=This conversation has been handed-off to a human agent who will be in contact soon if not done so already. I cannot respond to your query until the human agent transfers you back to me.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"a1ada0c7-779e-44bc-bdbd-1d5285bedf3c","name":"Notify user","type":"n8n-nodes-base.telegram","position":[1180,1040],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"=You have now been transferred to a human. Unfortunately, I will not be able to respond until the human agent transfers you back to me.","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2},{"id":"31287a38-e7a7-4518-9f54-6e6c9b2486fe","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[1520,1020],"parameters":{"width":220,"height":320,"content":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### Add Human Chat ID\nThis is needed to notify the human agent."},"typeVersion":1},{"id":"a58a82b9-2c37-4137-9b3e-17479c78a2d2","name":"Memory3","type":"@n8n/n8n-nodes-langchain.memoryRedisChat","position":[1580,500],"parameters":{"sessionKey":"=handoff_{{ $('Telegram Trigger').first().json.message.chat.id }}_chat2","sessionIdType":"customKey","contextWindowLength":30},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1.5},{"id":"4d3d5b46-6e82-4b97-9e5f-76f02ff79ce5","name":"Update Agent Memory1","type":"@n8n/n8n-nodes-langchain.memoryManager","position":[1580,340],"parameters":{"mode":"insert","messages":{"messageValues":[{"type":"ai","message":"=The person I'm speaking to has the following details:\nfirstname: {{ $('Handoff Subworkflow1').first().json.firstname }}\nlastname: {{ $('Handoff Subworkflow1').first().json.firstname }}\nreason for call: {{ $('Handoff Subworkflow1').first().json.reason_for_call }}","hideFromUI":true}]}},"typeVersion":1.1},{"id":"ced46068-440b-46b4-aa51-b5bb9d59a004","name":"Continue Conversation","type":"n8n-nodes-base.telegram","position":[1220,580],"webhookId":"55ecb0ba-72c8-4f16-a6c8-0c0bb8582554","parameters":{"text":"={{ $('Onboarding Agent').first().json.output }}","chatId":"={{ $('Telegram Trigger').first().json.message.chat.id }}","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"XVBXGXSsaCjU2DOS","name":"jimleuk_handoff_bot"}},"typeVersion":1.2}],"connections":{"Model":{"ai_languageModel":[[{"node":"Onboarding Agent","type":"ai_languageModel","index":0}]]},"Memory":{"ai_memory":[[{"node":"Onboarding Agent","type":"ai_memory","index":0}]]},"Model1":{"ai_languageModel":[[{"node":"After Sales Agent","type":"ai_languageModel","index":0}]]},"Memory1":{"ai_memory":[[{"node":"After Sales Agent","type":"ai_memory","index":0}]]},"Memory2":{"ai_memory":[[{"node":"Update Agent Memory","type":"ai_memory","index":0}]]},"Memory3":{"ai_memory":[[{"node":"Update Agent Memory1","type":"ai_memory","index":0}]]},"Notify user":{"main":[[{"node":"Set Interaction to Human","type":"main","index":0}]]},"Handoff Tool":{"ai_tool":[[{"node":"After Sales Agent","type":"ai_tool","index":0}]]},"Send Response":{"main":[[{"node":"Update Agent Memory1","type":"main","index":0}]]},"With Defaults":{"main":[[{"node":"Has All Criteria?","type":"main","index":0}]]},"Onboarding Agent":{"main":[[{"node":"Get Onboarding Chat History","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Get Interaction State","type":"main","index":0}]]},"After Sales Agent":{"main":[[{"node":"Send Response3","type":"main","index":0}]]},"Has All Criteria?":{"main":[[{"node":"Handoff Subworkflow1","type":"main","index":0}],[{"node":"Continue Conversation","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Information Extractor","type":"ai_languageModel","index":0}]]},"Switch Interaction":{"main":[[{"node":"Get Canned Response","type":"main","index":0}],[{"node":"After Sales Agent","type":"main","index":0}],[{"node":"Onboarding Agent","type":"main","index":0}]]},"Handoff Subworkflow":{"main":[[{"node":"Notify user","type":"main","index":0}]]},"Update Agent Memory":{"main":[[{"node":"Send Response2","type":"main","index":0}]]},"Handoff Subworkflow1":{"main":[[{"node":"Send Response","type":"main","index":0}]]},"Get Interaction State":{"main":[[{"node":"Switch Interaction","type":"main","index":0}]]},"Information Extractor":{"main":[[{"node":"With Defaults","type":"main","index":0}]]},"Set Interaction to Bot":{"main":[[{"node":"Update Agent Memory","type":"main","index":0}]]},"Set Interaction to Human":{"main":[[{"node":"Human Handoff using Send and Wait","type":"main","index":0}]]},"Get Onboarding Chat History":{"main":[[{"node":"Information Extractor","type":"main","index":0}]]},"Human Handoff using Send and Wait":{"main":[[{"node":"Set Interaction to Bot","type":"main","index":0}]]}}}


name: Automate Product Training & Customer Support via WhatsApp, GPT-4 & Google Sheets
author_name: Dr. Firas
author_username: drfiras
categories: []
created_at: 2025-03-30T16:46:52.017Z
updated_at: 2025-03-30T16:46:52.017Z
url: https://n8n.io/workflows/3379
scraped_at: 2025-07-06 21:16:30
description:
  WhatsApp AI Agent: Auto-Train Product Data & Handle Customer Support

  Who Is This For

  This workflow is ideal for eCommerce founders, product managers, customer support teams, and automation builders who rely on WhatsApp to manage product information and interact with clients.

  It’s perfect for businesses that want to automate product data entry and support responses directly from WhatsApp messages using GPT-4 and Google Sheets.

  What Problem Does This Workflow Solve

  Manual Product Data Entry**: Collecting and organizing product data from links is tedious and error-prone.  
  Slow Customer Response Times**: Responding to client questions manually leads to delays and inconsistent support.  
  No Logging System for Issues**: Without automation, support issues often go undocumented, making it harder to learn and improve.

  What This Workflow Does

  Step 1 – Incoming Message Detection
  Listens for incoming messages via WhatsApp.
  If the message starts with train:, it routes to the product training process.
  Otherwise, it routes to the customer support assistant.

  Step 2 – Product Data Training
  Extracts URL** from the message using a regex script.
  Fetches HTML content** from the URL.
  Cleans HTML data** to extract readable product description.
  Saves raw data** (URL + description) into Google Sheets.
  Uses GPT-4** to enhance product data:  
    → Name, price (one-time or subscription), topic, and FAQs.  
  Updates the product row** in Google Sheets with structured information.

  Step 3 – Customer Support Flow
  Analyzes user messages with GPT-4 to understand the request or issue.
  Looks up relevant product info in Google Sheets.
  Detects potential problems (e.g. payment, login, delivery).
  Suggests an appropriate solution.
  Logs the problem, solution, and category to the Customer Issues sheet.
  Sends a response back to the client via WhatsApp.

  Step 4 – Client Response
  Sends the AI-generated response to the client via WhatsApp.
  Keeps the communication fast, clear, and professional.

  Setup Guide

  Prerequisites

  WhatsApp Business API access**
  OpenAI API Key**
  Google Account** with Google Sheets access
  A hosted instance of n8n (Cloud or self-hosted)

  Setup Steps

  Import the Workflow into your n8n instance.
  Connect your credentials for WhatsApp, OpenAI, and Google Sheets.
  Customize Google Sheet IDs and names as needed.
  Test by sending a train: message or a regular customer message to WhatsApp.
  Activate the workflow to make it live.

  How to Customize This Workflow

  Edit AI prompts** to reflect your product type, language style, or tone.
  Change the trigger keyword** (e.g. from train: to add: or anything else).
  Add integrations** like Notion, Airtable, or CRM tools.
  Expand the Sheets structure** with more product fields (e.g. stock status, image link).
  Add notifications** to Slack or email after product updates or issue logging.

  📄 Documentation: Notion Guide

  Need help customizing?
  Contact me for consulting and support : Linkedin / Youtube

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.whatsApp","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow"]

workflow_json:
  {"id":"GvlLeSOUPfar0DQS","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"Automate Product Data Collection & Customer Support via WhatsApp + GPT-4 + Google Sheets","tags":[],"nodes":[{"id":"370611ee-2725-4ee4-a73a-68d4eaabfe3a","name":"WhatsApp Business Cloud","type":"n8n-nodes-base.whatsApp","position":[1020,220],"webhookId":"ef261fd4-e3b8-42e9-a0e2-2c3c44b6b15e","parameters":{"textBody":"={{ $json.output }}","operation":"send","phoneNumberId":"574583382412256","additionalFields":{},"recipientPhoneNumber":"+212722542056"},"credentials":{"whatsAppApi":{"id":"TzeEzaeiZOOqcLOZ","name":"WhatsApp account"}},"typeVersion":1},{"id":"30520fe8-a423-4942-85b2-9e8776b45939","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-740,-20],"parameters":{"width":400,"height":440,"content":"## 🟡 STEP 1 – Incoming WhatsApp Message\nListens for new WhatsApp messages.\nIf the message starts with train:, it triggers the product training flow.\nOtherwise, it goes to the customer support flow.\n**WhatsApp Business Cloud node** : [Here](https://www.notion.so/automatisation/WHATSAPP-WORKFLOW-1c63d6550fd980559679e7535938a68d?pvs=4#1c63d6550fd980f9a2a5e25a3654da82)"},"typeVersion":1},{"id":"d3259e0e-5368-407d-8ac6-993784c939c9","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-300,280],"parameters":{"color":6,"width":1180,"height":420,"content":"## 🔵 STEP 3 – Customer Support Flow\nTriggered when the message **does NOT start with `train:`**.\n\n1. **AI Analyzes the Message**  \n   Understands the customer's question or problem.\n\n2. **Fetch Product Data if Needed**  \n   Reads relevant product info from Google Sheets.\n\n3. **Detect Issues Automatically**  \n   Identifies if the user is facing a specific issue.\n\n4. **Suggest Solutions**  \n   Proposes a helpful, clear response to solve the issue.\n\n5. **Log Customer Problems**  \n   Saves the problem, suggested solution, and category.\n\n6. **Respond to the User**  \n   Sends a professional and helpful WhatsApp reply."},"typeVersion":1},{"id":"455ce4ab-6d14-4d4e-8ff8-04612cf532b9","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-300,-400],"parameters":{"color":3,"width":1180,"height":660,"content":"## 🔴 STEP 2 – Product Data Training (Triggered by train:)\nTriggered when the message starts with `train:`.\n**OpenAI API keys** : [Here](https://platform.openai.com/api-keys)\n\n\n\n\n\n\n\n\n\n\n\n\n1. **Extract URL from Message**  \n   Uses regex to detect and extract the product link.\n\n2. **Fetch HTML Content**  \n   Sends an HTTP request to retrieve the full page content.\n\n3. **Clean HTML Data**  \n   Strips HTML tags, scripts, and formats the text.\n\n4. **Save Raw Product Info**  \n   Appends the cleaned content and URL into Google Sheets.\n\n5. **AI: Enhance Product Details**  \n   - Extracts Product Name  \n   - Detects Price (subscription or one-time)  \n   - Identifies Product Topic  \n   - Generates FAQs\n\n6. **Update Product Sheet**  \n   Enriches the row in Sheets with structured product data.\n"},"typeVersion":1},{"id":"15251a04-a139-4a71-9e96-d5ecd9c2e66c","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[920,-20],"parameters":{"color":4,"width":320,"height":440,"content":"## 🟢 STEP 4 – Client Response\nFinal step of the flow.\n\n- Sends the AI-generated response back to the customer via WhatsApp.\n- Ensures the message is clear, helpful, and personalized."},"typeVersion":1},{"id":"f028f5a3-fed3-4f90-89cc-2af211da7362","name":"Incoming Message Trigger","type":"n8n-nodes-base.whatsAppTrigger","position":[-700,220],"webhookId":"48ce9bac-c7ea-4cb7-a40a-b010ea5ac743","parameters":{"options":{},"updates":["messages"]},"credentials":{"whatsAppTriggerApi":{"id":"zYvcHcxGBNdN9Ptf","name":"WhatsApp OAuth account"}},"typeVersion":1},{"id":"54edaa0c-005e-4810-a2fa-76fbcc009b2b","name":"Check If Training","type":"n8n-nodes-base.switch","position":[-520,220],"parameters":{"rules":{"values":[{"outputKey":"train","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9865cb5b-33da-490c-afc3-186457d5b564","operator":{"type":"string","operation":"startsWith"},"leftValue":"={{ $json.messages[0].text.body }}","rightValue":"train:"}]},"renameOutput":true},{"outputKey":"text","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5a9a1fee-b408-469f-a08c-e8d690fc9792","operator":{"type":"string","operation":"notStartsWith"},"leftValue":"={{ $json.messages[0].text.body }}","rightValue":"train:"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"b4187b28-efd9-46cb-8d1c-23d89d3f6125","name":"Extract URL from Text","type":"n8n-nodes-base.code","position":[-260,-320],"parameters":{"jsCode":"// Récupérer le texte à analyser depuis l'input\nconst texteExemple = $input.first().json.messages[0].text.body;\n\n// Expression régulière modifiée pour capturer les URL avec ou sans protocole\nconst regex = /((?:https?:\\/\\/)?(?:www\\.)?[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}(?:\\/\\S*)?)/g;\n\n// Extraction des URL à partir du texte\nconst matches = texteExemple.match(regex) || [];\n\n// Si des URL ont été trouvées, on les mappe en objets\nif (matches.length > 0) {\n    const output = matches.map(url => ({ url }));\n    return output;\n} else {\n    // Si aucune URL n'est trouvée, on retourne les items d'entrée pour que le workflow continue\n    return $input.all();\n}\n"},"typeVersion":2},{"id":"dbbcc8cf-2544-4de1-bcfd-6292d96a1017","name":"Fetch HTML Page","type":"n8n-nodes-base.httpRequest","position":[-100,-320],"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{"responseFormat":"text"}}}},"typeVersion":4.2},{"id":"91e711d0-26c0-41dd-a9c5-28100f0f44f6","name":"Clean HTML Content","type":"n8n-nodes-base.code","position":[60,-320],"parameters":{"jsCode":"// Exemple : récupération du contenu HTML depuis le premier item\n// Si vous avez un champ nommé \"html\" dans un noeud précédent.\nconst htmlContent = $input.first().json.html;\n\n// Fonction de nettoyage du HTML\nfunction nettoyerHTML(input) {\n  if (typeof input !== 'string') {\n    throw new Error(\"Expected HTML content as a string.\");\n  }\n  let cleanedText = input;\n\n  // 1. Retirer les liens <a> et leur contenu\n  cleanedText = cleanedText.replace(/<a[^>]*>.*?<\\/a>/gs, '');\n\n  // 2. Retirer <script>, <style>, commentaires, etc.\n  cleanedText = cleanedText.replace(/<script[^>]*>.*?<\\/script>/gs, '');\n  cleanedText = cleanedText.replace(/<style[^>]*>.*?<\\/style>/gs, '');\n  cleanedText = cleanedText.replace(/<!--[\\s\\S]*?-->/g, '');\n\n  // 3. Insérer des retours à la ligne pour certaines balises\n  cleanedText = cleanedText.replace(/<h[1-6][^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/h[1-6]>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<p[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/p>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<ul[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/ul>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<ol[^>]*>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<\\/ol>/gi, '\\n');\n  cleanedText = cleanedText.replace(/<li[^>]*>/gi, '- ');\n  cleanedText = cleanedText.replace(/<\\/li>/gi, '\\n');\n\n  // 4. Supprimer toutes les balises HTML restantes\n  cleanedText = cleanedText.replace(/<[^>]+>/g, '');\n\n  // 5. Supprimer (ou ajuster) les caractères spéciaux\n  cleanedText = cleanedText.replace(/[^\\w\\sÀ-ÖØ-öø-ÿ]+/g, '');\n\n  // 6. Normaliser les espaces multiples et trim\n  cleanedText = cleanedText.replace(/\\s+/g, ' ').trim();\n\n  return cleanedText;\n}\n\n// Nettoyage\nconst result = nettoyerHTML($input.first().json.data);\n\n// Retour d'un tableau contenant l'objet final\nreturn [\n  {\n    json: {\n      cleanedText: result\n    }\n  }\n];\n"},"typeVersion":2},{"id":"7e457450-42ef-417e-b5f9-3248c9c7c2ae","name":"Save Raw Product Info","type":"n8n-nodes-base.googleSheets","position":[240,-320],"parameters":{"columns":{"value":{"Product Link":"={{ $('Extract URL from Text').item.json.url }}","Product Description":"={{ $json.cleanedText }}"},"schema":[{"id":"Product Link","type":"string","display":true,"required":false,"displayName":"Product Link","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Name","type":"string","display":true,"required":false,"displayName":"Product Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Price","type":"string","display":true,"required":false,"displayName":"Product Price","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Description","type":"string","display":true,"required":false,"displayName":"Product Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Topic","type":"string","display":true,"required":false,"displayName":"Product Topic","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"d3dfa439-4056-4ce9-b874-100500967de6","name":"OpenAI Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[320,-40],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"10217317-f6dd-4890-b05d-197d3d2adb79","name":"Short-Term Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[500,-40],"parameters":{"sessionKey":"={{ $('Incoming Message Trigger').item.json.messages[0].id }}","sessionIdType":"customKey","contextWindowLength":50},"typeVersion":1.3},{"id":"58ce0f46-fabc-4b6e-97d7-857dc6f1e568","name":"Update Product Sheet","type":"n8n-nodes-base.googleSheetsTool","position":[680,-40],"parameters":{"columns":{"value":{"F&Q":"={{ $fromAI(\"product_faq\", \"these are the most common questions users might have about the product, including answers if available\") }}\n","Product Link":"={{ $fromAI(\"product_url\",\"this is the website link of the product\") }}","Product Name":"={{ $fromAI(\"product_name\",\"this is the name of the product\") }}","Product Price":"={{ $fromAI(\"product_price\",\"this is the price of the product\") }}","Product Topic":"={{ $fromAI(\"product_topic\",\"this is the topic of the product that specifies what it is for, who it is for and what the key benefits are\") }}"},"schema":[{"id":"Product Link","type":"string","display":true,"removed":false,"required":false,"displayName":"Product Link","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Name","type":"string","display":true,"required":false,"displayName":"Product Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Price","type":"string","display":true,"required":false,"displayName":"Product Price","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Topic","type":"string","display":true,"required":false,"displayName":"Product Topic","defaultMatch":false,"canBeUsedToMatch":true},{"id":"F&Q","type":"string","display":true,"removed":false,"required":false,"displayName":"F&Q","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Product Link"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"020714ae-5668-4fa5-8ba8-f1e476a8060e","name":"AI Agent -  Customer Support Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[380,300],"parameters":{"text":"={{ $json.messages[0].text.body }}","options":{"systemMessage":"You are a helpful and intelligent customer support assistant.\n\nYou have access to a Google Sheets tool that allows you to read any content from a specific sheet to gather necessary information.\nNever mention to the user that you accessed Google Sheets to retrieve any data.\n\nYour main responsibilities:\n\nUnderstand the user’s request or issue.\n\nIf the user is asking about a product, retrieve the relevant product name, price, and details as needed.\n\nDetermine whether the product price is a subscription or a one-time payment, based on the description.\n\nIf you detect that the user is facing a problem:\n\nIdentify and describe the problem clearly.\n\nPropose a practical and helpful solution.\n\nLog this interaction by adding a new row to the Google Sheet with the following columns:\n\nProblem\n\nSuggested Solution\n\nCategory (e.g., payment, login, access, delivery, technical issue, etc.)\n\nBe professional, concise, and empathetic in your responses.\nAlways aim to resolve the issue or provide the next best action."},"promptType":"define"},"typeVersion":1.7},{"id":"53e49985-e1b9-48fd-9ea8-3352a63484e0","name":"AI Agent - Enhance Product Details","type":"@n8n/n8n-nodes-langchain.agent","position":[420,-320],"parameters":{"text":"=My product description :  {{ $json['Product Description'] }}\n\nMy product link : {{ $json['Product Link'] }}","options":{"systemMessage":"You are a helpful and intelligent assistant.\n\nYou receive the text content of a product page.\n\nYour tasks are:\n\nExtract the product name.\n\nExtract the product price, and determine whether it is a subscription or a one-time payment.\n\nIdentify the product topic.\n\nExtract the most frequently asked questions (FAQs) related to the product.\n\nYou have access to a Google Sheets tool that allows you to update specific columns and cells.\n\nAlways add the following data to the same row as the product URL in the Google Sheet:\n\nProduct Name\n\nProduct Price (with subscription/one-time label)\n\nProduct Topic\n\nFAQs\n\nBe accurate, structured, and consistent when filling in the sheet.\nDo not mention Google Sheets in your responses."},"promptType":"define"},"typeVersion":1.8},{"id":"194136b5-872a-492b-882b-d26a2890cbcf","name":"OpenAI Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[220,560],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"efc89a9b-3141-4735-adaf-7b9e2b6879ed","name":"Conversation Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[400,560],"parameters":{"sessionKey":"={{ $json.messages[0].id }}","sessionIdType":"customKey","contextWindowLength":50},"typeVersion":1.3},{"id":"d1a21094-0237-4b17-818c-3af7760b405f","name":"Read Product Sheet","type":"n8n-nodes-base.googleSheetsTool","position":[560,560],"parameters":{"options":{"dataLocationOnSheet":{"values":{"readRowsUntil":"firstEmptyRow","rangeDefinition":"detectAutomatically"}}},"sheetName":{"__rl":true,"mode":"list","value":689245338,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=689245338","cachedResultName":"Products"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"2c2dcf9b-5578-4bd4-85b6-27621927a0a0","name":"Log Customer Issues","type":"n8n-nodes-base.googleSheetsTool","position":[740,560],"parameters":{"columns":{"value":{"Category":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Category', ``, 'string') }}","Solution":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Solution', ``, 'string') }}","Support Problem":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Support_Problem', ``, 'string') }}"},"schema":[{"id":"Support Problem","type":"string","display":true,"required":false,"displayName":"Support Problem","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Solution","type":"string","display":true,"required":false,"displayName":"Solution","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Category","type":"string","display":true,"required":false,"displayName":"Category","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":1725207764,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit#gid=1725207764","cachedResultName":"Customer Issues"},"documentId":{"__rl":true,"mode":"list","value":"1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1wa41S888Ya3sqEkBdzYiDq-5FOu_V30BOe-toX_78xQ/edit?usp=drivesdk","cachedResultName":"Product Sales - AI Agent WhatsApp"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"2e8ea310-e164-4d5d-ae0b-ade129b07a4a","connections":{"OpenAI Model":{"ai_languageModel":[[{"node":"AI Agent - Enhance Product Details","type":"ai_languageModel","index":0}]]},"OpenAI Model1":{"ai_languageModel":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_languageModel","index":0}]]},"Fetch HTML Page":{"main":[[{"node":"Clean HTML Content","type":"main","index":0}]]},"Check If Training":{"main":[[{"node":"Extract URL from Text","type":"main","index":0}],[{"node":"AI Agent -  Customer Support Agent","type":"main","index":0}]]},"Short-Term Memory":{"ai_memory":[[{"node":"AI Agent - Enhance Product Details","type":"ai_memory","index":0}]]},"Clean HTML Content":{"main":[[{"node":"Save Raw Product Info","type":"main","index":0}]]},"Read Product Sheet":{"ai_tool":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_tool","index":0}]]},"Conversation Memory":{"ai_memory":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_memory","index":0}]]},"Log Customer Issues":{"ai_tool":[[{"node":"AI Agent -  Customer Support Agent","type":"ai_tool","index":0}]]},"Update Product Sheet":{"ai_tool":[[{"node":"AI Agent - Enhance Product Details","type":"ai_tool","index":0}]]},"Extract URL from Text":{"main":[[{"node":"Fetch HTML Page","type":"main","index":0}]]},"Save Raw Product Info":{"main":[[{"node":"AI Agent - Enhance Product Details","type":"main","index":0}]]},"WhatsApp Business Cloud":{"main":[[]]},"Incoming Message Trigger":{"main":[[{"node":"Check If Training","type":"main","index":0}]]},"AI Agent -  Customer Support Agent":{"main":[[{"node":"WhatsApp Business Cloud","type":"main","index":0}]]},"AI Agent - Enhance Product Details":{"main":[[{"node":"WhatsApp Business Cloud","type":"main","index":0}]]}}}


name: Create and Join Call Sessions with Plivo and UltraVox AI Voice Assistant
author_name: Yohita
author_username: yohita
nodes_used: ["n8n-nodes-base.httpRequest"]
categories: []
created_at: 2025-04-01T04:12:57.053Z
updated_at: 2025-04-01T04:12:57.053Z
url: https://n8n.io/workflows/3392
scraped_at: 2025-07-06 21:16:30
description:
  This workflow template creates an audio stream session on UltraVox compatible with Plivo and sends it to Plivo.

  How It Works : 
  Plivo initiates a call and requests the Answer URL.

  The workflow responds with Plivo XML to join the session.

  Note:
  Ensure you update the UltraVox API Key in the credentials.
  Update System Prompt based on your requirements.

   Check Youtube Video

workflow_json:
  {"id":"pCfyeWKAejNPSLzR","meta":{"instanceId":"ee166f9597772c64f4891dd646950680c707583a2618ef40fa7d4420fbb25c8c"},"name":"Call Sessions with Plivo and UltraVox AI Voice Assistant","tags":[],"nodes":[{"id":"179732eb-eace-4d8c-a1eb-15443b94a493","name":"Webhook","type":"n8n-nodes-base.webhook","position":[-380,-40],"webhookId":"40fa0470-c3c1-4bf2-a91b-7cad92bd71db","parameters":{"path":"40fa0470-c3c1-4bf2-a91b-7cad92bd71db","options":{"allowedOrigins":"*"},"responseMode":"responseNode"},"typeVersion":2},{"id":"4b62488a-1cb4-444a-b309-ede8dcbe8a58","name":"UltraVox API","type":"n8n-nodes-base.httpRequest","position":[-160,-40],"parameters":{"url":"https://api.ultravox.ai/api/calls","method":"POST","options":{},"jsonBody":"{\n  \"voice\":\"c2c5cce4-72ec-4d8b-8cdb-f8a0f6610bd1\",\n  \"medium\":{\"plivo\":{}\n  },\n  \"systemPrompt\":\"You are a female voice assistant for Gurukrupa Physiotherapy Clinic, a physiotherapy center located at Beed, Maharashtra. The clinic hours are: Monday to Saturday: 10 AM ti 2 PM and 5 PM – 9 PM Sunday is Closed Gurukrupa Physiotherapy Clinic provides expert physiotherapy services to help patients recover from back pain, joint pain, paralysis, sports injuries, and post-surgical rehab. Your job is to answer questions about the clinic and book appointments. If someone wants to book an appointment, gather these details: Ask for their full name. Ask for the reason for their visit (e.g., back pain, injury, rehab). Request their preferred date and time. Confirm all details before finalizing the appointment. Be friendly, warm, and slightly witty! Keep responses short and conversational—like a real chat. Use casual phrases like Gotcha!, Alrighty!, and No worries!. Keep the tone trustworthy, professional, and caring—this is healthcare, after all! Start with Greeting : உங்கள் Gurukrupa Physiotherapy Clinic-க்கு வரவேற்கிறோம்! நான் உங்களுக்கு உதவ இங்கே இருக்கிறேன்.\"\n}","sendBody":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"cWN2t8OEljwhetjn","name":"UltraVox API Key"}},"typeVersion":4.2},{"id":"9c031c9a-564d-41e5-a391-db4d6127d2e5","name":"Respond to Webhook","type":"n8n-nodes-base.respondToWebhook","position":[200,-40],"parameters":{"options":{"responseCode":200,"responseHeaders":{"entries":[{"name":"Content-Type","value":"text/xml"}]}},"respondWith":"text","responseBody":"=<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Response>\n<Stream keepCallAlive=\"true\" bidirectional=\"true\" contentType=\"audio/x-l16;rate=16000\">{{ $json.joinUrl }}</Stream>\n</Response>\n"},"typeVersion":1.1},{"id":"fb9d431e-b772-4e20-9b2c-55fd1f6d1f84","name":"Join URL","type":"n8n-nodes-base.set","position":[40,-40],"parameters":{"options":{},"assignments":{"assignments":[{"id":"d46d8697-e784-44fb-a4bb-e1a5811a746d","name":"joinUrl","type":"string","value":"={{ $json.joinUrl }}"}]}},"typeVersion":3.4},{"id":"f9fb4f49-e268-461b-ab2e-31eeb8478196","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-420,-240],"parameters":{"width":860,"content":"## Create and Join Call Sessions with Plivo and UltraVox AI Voice Assistant\nAdd Your UltraVox key in UltraVox Credentials.\nCheck youtube Video for Detailed Instructions : https://www.youtube.com/watch?v=Acbs3ouc4FQ "},"typeVersion":1}],"active":true,"settings":{"executionOrder":"v1"},"versionId":"ab237196-1509-4f55-8bf5-0c4aaa12a52e","connections":{"Webhook":{"main":[[{"node":"UltraVox API","type":"main","index":0}]]},"Join URL":{"main":[[{"node":"Respond to Webhook","type":"main","index":0}]]},"UltraVox API":{"main":[[{"node":"Join URL","type":"main","index":0}]]},"Respond to Webhook":{"main":[[]]}}}


name: Google Calendar Reminder System with GPT-4o and Telegram
author_name: Davide
author_username: n3witalia
categories: []
created_at: 2025-04-01T07:27:50.382Z
updated_at: 2025-04-01T07:27:50.382Z
url: https://n8n.io/workflows/3393
scraped_at: 2025-07-06 21:16:30
description:
  How many times have you missed a meeting or forgotten an appointment because a calendar reminder got lost in the noise? Traditional notifications are often dry, easy to ignore, or scattered across different apps—leaving you scrambling at the last minute.

  This smart Google Calendar workflow fixes that by sending you a clear, friendly reminder exactly 1 hour before your event starts—delivered through Telegram as if a personal assistant were looking out for you. Powered by AI, it transforms cold calendar alerts into warm, conversational nudges you won't ignore.

  Why This Works Better:  
  ✅ No More Overlooked Alerts – Consolidates reminders into one clear, accessible place (Telegram), so you never miss them.  
  ✅ Friendly & Engaging – AI transforms robotic calendar entries into natural, human-like reminders that are harder to ignore.  
  ✅ Works Everywhere – Whether you're on your phone, laptop, or tablet, you’ll get the same clear notification, no matter the platform.  

  How It Works
  Scheduled Trigger: The workflow starts with a Schedule Trigger node that runs every minute to check for upcoming events.
  Google Calendar Check: The "Get upcoming event" node queries Google Calendar for events starting within the next hour (between timeMin and timeMax).
  Duplicate Prevention: The "Already sent?" node ensures reminders are not sent multiple times for the same event by filtering out duplicates.
  AI-Powered Reminder: The "Secretary Agent" node, powered by GPT-4, crafts a friendly and professional reminder message. It includes event details like name, description, location, start/end time, and creator, formatted in a conversational tone.
  Telegram Notification: The final "Send reminder" node delivers the reminder via Telegram, ensuring the user receives it in a clear and accessible format.
  Set Up Steps
  Configure Schedule Trigger: Set the interval (e.g., every minute) to check for events.
  Connect Google Calendar: Link your Google Calendar account and specify the calendar to monitor.
  Set Up AI Agent: Customize the "Secretary Agent" with the provided system message to ensure reminders are warm, professional, and detailed.
  Link Telegram: Add your Telegram credentials and specify the CHAT_ID where reminders will be sent.
  Activate Workflow: Ensure the workflow is active and set to the correct timezone (e.g., Europe/Rome).
  Why It’s Useful
  Never Miss an Event**: Traditional calendar reminders can be easy to overlook, especially when scattered across platforms. This workflow consolidates reminders into a single, accessible channel (Telegram).
  Clear and Friendly**: The AI agent transforms generic calendar alerts into personalized, conversational reminders, making them harder to ignore.
  Cross-Platform Accessibility**: By delivering reminders via Telegram, users receive them in a consistent format, regardless of the device or platform they’re using. No more missed events due to unclear notifications!
  Need help customizing?  
  Contact me for consulting and support or add me on Linkedin.

nodes_used:
  ["n8n-nodes-base.telegram","n8n-nodes-base.googleCalendar","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi"]

workflow_json:
  {"id":"SvYHgLmzosuLAe4A","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462","templateCredsSetupCompleted":true},"name":"Google Calendar Event Reminder","tags":[],"nodes":[{"id":"dff5d952-23cb-4822-9aec-0dcae3de568a","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","disabled":true,"position":[-40,300],"parameters":{"rule":{"interval":[{"field":"minutes","minutesInterval":1}]}},"typeVersion":1.2},{"id":"a6de9944-1dd7-430e-a1d9-100710ddfa9c","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[700,500],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"CDX6QM4gLYanh0P4","name":"OpenAi account"}},"typeVersion":1.2},{"id":"6d2208a6-6000-4b6b-a82c-e346b7885409","name":"Get upcoming event","type":"n8n-nodes-base.googleCalendar","position":[240,300],"parameters":{"limit":5,"options":{},"timeMax":"={{ $now.plus({ hour: 1, minute:1 }) }}","timeMin":"={{ $now.plus({ hour: 1 }) }}","calendar":{"__rl":true,"mode":"list","value":"davide.boizza@gmail.com","cachedResultName":"davide.boizza@gmail.com"},"operation":"getAll"},"credentials":{"googleCalendarOAuth2Api":{"id":"8RFK3u13g2PJEGa9","name":"Google Calendar account"}},"typeVersion":1.3},{"id":"e6f6e744-60b0-4b22-93bc-f3ffcfac71f6","name":"Already sent?","type":"n8n-nodes-base.removeDuplicates","position":[480,300],"parameters":{"options":{},"operation":"removeItemsSeenInPreviousExecutions","dedupeValue":"={{ $json.id }}"},"typeVersion":2},{"id":"882d08f5-790a-40bb-bda5-60744d587633","name":"Secretary Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[720,300],"parameters":{"text":"=These are the details of the event/appointment:\n\nEvent Name: {{ $('Get upcoming event').item.json.summary }}\nDescription: {{ $('Get upcoming event').item.json.description }}\nLocation: {{ $('Get upcoming event').item.json.location }}\nStart: {{ $('Get upcoming event').item.json.start.dateTime }}\nEnd: {{ $('Get upcoming event').item.json.end.dateTime }}\nCreated by: {{ $('Get upcoming event').item.json.creator.email }}","options":{"systemMessage":"=## Core Identity\nYou are a professional and friendly virtual secretary, dedicated to reminder appointments with efficiency and a warm personal touch.\n\n## Communication Style\n- Communicate in a conversational, approachable manner\n- Maintain a balance between professional competence and friendly rapport\n- Use a tone that is informal yet precise\n- Inject occasional light humor and personality into interactions\n\n## Key Responsibilities\n1. Calendar Management\n   - Provide timely reminders and scheduling updates\n\n2. Communication Approach\n   - Respond promptly and clearly\n   - Maintain confidentiality and discretion\n\n## Interaction Guidelines\n- Use a friendly, conversational tone\n- Just describe the details of the event without asking questions\n\n## Tone and Language\n- Warm and approachable\n- Professional but not overly formal\n- Direct and clear in communication\n- Use simple, straightforward language\n- Show genuine care and attentiveness\n\nRemember: Your primary goal is to make the user's life easier, more organized, and less stressful through efficient and friendly administrative support."},"promptType":"define","hasOutputParser":true},"typeVersion":1.8},{"id":"82509a0f-9086-423e-8928-f882e59333b8","name":"Send reminder","type":"n8n-nodes-base.telegram","position":[1100,300],"webhookId":"dbb6a96e-db3b-4827-9455-a91007b89616","parameters":{"text":"={{ $json.output }}","chatId":"CHAT_ID","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"0hSq9VwaiJifiscT","name":"Telegram account"}},"typeVersion":1.2},{"id":"d08dd565-4718-4fbc-af7c-7a2e042c96f8","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-40,-140],"parameters":{"color":3,"width":620,"content":"## Google Calendar Event Reminder\nThis smart **Google Calendar** workflow fixes that by sending you a clear, friendly reminder exactly **1 hour before your event starts**—delivered through **Telegram** as if a personal assistant were looking out for you. Powered by **AI**, it transforms cold calendar alerts into warm, conversational nudges you won't ignore."},"typeVersion":1},{"id":"7a9379ca-f301-40b9-ae90-742663bbcdf2","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-40,40],"parameters":{"width":620,"height":140,"content":"## STEP 1\n- In the \"Get upcoming event\" node enter how much time before the event starts you want to be notified. It is currently set to 1 hour\n- In the Telegram node replace CHAT_ID with that of your personal Bot"},"typeVersion":1},{"id":"d7852912-6501-4a1b-8928-6eb890e4aea8","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[420,240],"parameters":{"width":220,"height":200,"content":"Prevent multiple reminders for the same event"},"typeVersion":1}],"active":false,"settings":{"timezone":"Europe/Rome","callerPolicy":"workflowsFromSameOwner","executionOrder":"v1"},"versionId":"d0dd74db-e96c-4a09-a8d1-6fb193b6e015","connections":{"Already sent?":{"main":[[{"node":"Secretary Agent","type":"main","index":0}]]},"Secretary Agent":{"main":[[{"node":"Send reminder","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Get upcoming event","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Secretary Agent","type":"ai_languageModel","index":0}]]},"Get upcoming event":{"main":[[{"node":"Already sent?","type":"main","index":0}]]}}}


name: Parse Incoming Invoices From Outlook using AI Document Understanding
author_name: Jimleuk
author_username: jimleuk
categories: []
created_at: 2025-04-01T09:17:11.659Z
updated_at: 2025-04-01T09:17:11.659Z
url: https://n8n.io/workflows/3396
scraped_at: 2025-07-06 21:16:30
description:
  This n8n template monitors an Outlook mailbox for invoices, automatically parses/extracts data from them and then uploads the output to an Excel Workbook.

  One of my top workflow requests, this template can save many hours of manual labour for you or your finance/accounts team.

  How it works
  A scheduled trigger is set to fetch recent Outlook messages to the Accounts receivable mailbox.
  Each message is analysed to determine whether or not it from a supplier and is issuing/contains an invoice.
  For each valid message, the attachments are downloaded and non-invoice documents are filtered out via AI Vision classification.
  Invoices are then processed through a AI vision model again to extract the details.
  The extracted data can then be used for reconciliation or otherwise. For this demonstration, we'll just append the row to an Excel sheet for now.

  How to use
  Ensure your Microsoft365 credential points to the correct mailbox. If a shared folder is used, toggle "shared folder" option to "on" and for the principal ID, use the email address.
  If you receive lots of other types of messages such as replies and forwards, you may want to implement additional checks to prevent processing invoices twice. The "remove duplicates" node can help with this.

  Requirements
  Outlook for Mailbox
  Google Gemini for Document Understanding and Invoice Extraction
  Excel for Data Storage

  Customising this workflow
  Note the assumption for this template is that all invoices will come as a PDF attachment. In real life, this is rarely the case! Adding in document conversion to cover all invoice formats.
  Human feedback is also an important factor in AI workflows. Try tagging emails as a way to notify team members that the invoice was processed.

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.microsoftExcel","n8n-nodes-base.microsoftOutlook","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.lmChatGoogleGemini","@n8n/n8n-nodes-langchain.textClassifier"]

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"78bb4afe-ccc6-4b5e-90ba-50253f761f14","name":"Split Attachments","type":"n8n-nodes-base.code","position":[-80,140],"parameters":{"jsCode":"let results = [];\n\nfor (const item of $input.all()) {\n    for (key of Object.keys(item.binary)) {\n        results.push({\n            json: {\n                fileName: item.binary[key].fileName\n            },\n            binary: {\n                data: item.binary[key],\n            }\n        });\n    }\n}\n\nreturn results;"},"typeVersion":2},{"id":"48a79e8c-27c2-4cdb-a6f7-241158c10962","name":"Download Attachments","type":"n8n-nodes-base.microsoftOutlook","position":[-260,140],"webhookId":"2eb57df9-1579-4af2-a30e-f412b268aba2","parameters":{"options":{"downloadAttachments":true},"messageId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"operation":"get"},"credentials":{"microsoftOutlookOAuth2Api":{"id":"EWg6sbhPKcM5y3Mr","name":"Microsoft Outlook account"}},"typeVersion":2},{"id":"7dda1618-dfa7-4325-b5ff-7935602a3043","name":"Parse Output","type":"n8n-nodes-base.set","position":[680,400],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{\n{\n  invoice: $json.candidates[0].content.parts[0].text.parseJson(),\n  email: {\n    ...$('Message Ref').first().json,\n    body: null\n  }\n}\n}}"},"typeVersion":3.4},{"id":"4d45cf33-5a14-4fe4-9485-38de901113aa","name":"For Each Message","type":"n8n-nodes-base.splitInBatches","position":[-640,140],"parameters":{"options":{}},"typeVersion":3},{"id":"b5c70065-3ed8-4024-9a10-247810c062a4","name":"Message Ref","type":"n8n-nodes-base.noOp","position":[-440,140],"parameters":{},"typeVersion":1},{"id":"cafcf919-25c3-46bd-8dd3-8cc0201c93cb","name":"Message Classifier","type":"@n8n/n8n-nodes-langchain.textClassifier","position":[-1160,140],"parameters":{"options":{"fallback":"other"},"inputText":"=from: {{ $json.from.emailAddress.address }} <{{ $json.from.emailAddress.address }}>\nsubject: {{ $json.subject }}\n<message>\n{{ $json.markdown.split('\\n**From**')[0].trim() }}\n</message>","categories":{"categories":[{"category":"invoice","description":"Message is an invoice is being issued"}]}},"typeVersion":1},{"id":"f97f9b24-828b-4dd8-a0e8-b7ab670403a8","name":"Extract from File","type":"n8n-nodes-base.extractFromFile","position":[-440,340],"parameters":{"options":{},"operation":"binaryToPropery"},"typeVersion":1},{"id":"99d49549-af7c-46aa-b321-2b9955333812","name":"Markdown","type":"n8n-nodes-base.markdown","position":[-1340,140],"parameters":{"html":"={{ $json.body.content }}","options":{},"destinationKey":"markdown"},"typeVersion":1},{"id":"18455ee7-e87b-433c-baef-28444358e486","name":"Empty Response","type":"n8n-nodes-base.set","position":[680,600],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{\n{\n  invoice: null,\n  email: {\n    ...$('Message Ref').first().json,\n    body: null\n  }\n}\n}}"},"typeVersion":3.4},{"id":"d0b4bab2-5955-4d05-8e4f-4a23fac98c45","name":"Wait","type":"n8n-nodes-base.wait","position":[880,600],"webhookId":"6dae0a77-74f4-4d85-a58b-e55c44fbea58","parameters":{"amount":1},"typeVersion":1.1},{"id":"2600020d-9751-44df-abcd-48026c21f592","name":"Filter Invoices","type":"n8n-nodes-base.filter","position":[-80,340],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"5240de52-3b02-4151-8c2b-b0522582700e","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{\n(function(output) {\n  return output.is_invoice && output.is_issued_to_company;\n})(\n  $json.candidates[0].content.parts[0].text.parseJson()\n)\n}}","rightValue":""}]}},"typeVersion":2.2,"alwaysOutputData":true},{"id":"b31d359e-d949-4d56-b32e-c49b35124ff7","name":"Has Invoice?","type":"n8n-nodes-base.if","position":[280,400],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"57f433cd-5861-434f-80f2-ce28d7c22c26","operator":{"type":"object","operation":"notEmpty","singleValue":true},"leftValue":"={{ $input.first().json }}","rightValue":""}]}},"typeVersion":2.2},{"id":"857e2282-d7f7-438b-be87-a1c36986cfc0","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-1820,120],"parameters":{"rule":{"interval":[{"field":"hours"}]}},"typeVersion":1.2},{"id":"7292a6cc-3b59-4d9b-b87d-3ba55bbc0c67","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-780,-120],"parameters":{"color":7,"width":950,"height":680,"content":"## 2. Classify If Attachment is Invoice\n[Learn more about the Outlook node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.microsoftoutlook)\n\nFor each qualifying message, we will need to know which of the attachments contained are actual invoice documents. To do this, we can use Google Gemini's docuemnt understanding capabilities to validate this test. We're using Gemini specifically in this case because at time of writing, Gemini is the only one of the few LLM providers that are currently accepting PDF documents. If you're not using Gemini, you may need to convert the PDF document to an image first - [check out an example of this here](https://n8n.io/workflows/2421-transcribing-bank-statements-to-markdown-using-gemini-vision-ai/)."},"typeVersion":1},{"id":"ed35c1dc-625d-4ffb-b186-fad514f6df81","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[200,180],"parameters":{"color":7,"width":850,"height":580,"content":"## 3. Extract Invoice Details\n[Learn more about the HTTP Request node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.httprequest/)\n\nWith our invoice PDFs ready to go, we'll again use the Gemini API to extract the required details from them. I'm using the HTTP request node because unfortunately, Gemini works best for data extraction when using the API's \"generationConfig\" parameter which isn't supported in n8n's native AI nodes. The output is then merged with the original email to keep the reference between them."},"typeVersion":1},{"id":"42a9036c-8040-41a7-9366-658ba3e31c70","name":"Get Recent Messages","type":"n8n-nodes-base.microsoftOutlook","position":[-1540,140],"webhookId":"e3957f65-145c-4c0d-ac66-31342a1bc888","parameters":{"fields":["body","categories","conversationId","from","hasAttachments","internetMessageId","sender","subject","toRecipients","receivedDateTime","webLink"],"output":"fields","options":{},"filtersUI":{"values":{"filters":{"receivedAfter":"={{ $now.minus({ \"hour\": 1 }).toISO() }}","hasAttachments":true,"foldersToInclude":["AAMkAGZkNmEzOTVhLTk3NDQtNGQzNi1hNDY2LTE2MWFlMzUyNTczMgAuAAAAAAA27qsaXv92QoGqcRnqoMpSAQDhSgSaDoa3Sp4gzAabpsdOAAAAAAEMAAA="]}}},"operation":"getAll","returnAll":true},"credentials":{"microsoftOutlookOAuth2Api":{"id":"EWg6sbhPKcM5y3Mr","name":"Microsoft Outlook account"}},"typeVersion":2},{"id":"86838ba4-0d57-4571-983f-c17005f39333","name":"Model","type":"@n8n/n8n-nodes-langchain.lmChatGoogleGemini","position":[-1080,280],"parameters":{"options":{},"modelName":"models/gemini-2.0-flash"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"typeVersion":1},{"id":"8ecb7298-3512-40fe-b2bc-70fb4ed5965d","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1620,-120],"parameters":{"color":7,"width":810,"height":560,"content":"## 1. Check for Invoice Emails\n[Learn more about the text classifier node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.text-classifier/)\n\nThe Outlook node fetches all inbox messages within the last hour and classifies each message prior to downloading the attachments. This is a really good early check to reduce the comsumption of resources. In this use-case, using AI for contextual reasoning regarding the intent of the email can be much more powerful than simple keyword matching. The latter is more prone to matching false positives.\n*Note: we're not using the Outlook Trigger node because it doesn't allow setting for dateTime filters.*"},"typeVersion":1},{"id":"a3c28ab3-ecab-46fd-86bb-62bf8a222f37","name":"Microsoft Excel 365","type":"n8n-nodes-base.microsoftExcel","position":[420,-40],"parameters":{"options":{},"fieldsUi":{"values":[{}]},"resource":"worksheet","workbook":{"__rl":true,"mode":"id","value":"ABCDEFGHIJ"},"operation":"append","worksheet":{"__rl":true,"mode":"id","value":"{00000000-0001-0000-0000-000000000000}"}},"credentials":{"microsoftExcelOAuth2Api":{"id":"56tIUYYVARBe9gfX","name":"Microsoft Excel account"}},"typeVersion":2.1},{"id":"69f2a975-ab91-4cbc-be72-633c4601bf6f","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[200,-220],"parameters":{"color":7,"width":530,"height":380,"content":"## 4. Upload to Excel Workbook\n[Read more about the Excel node](https://docs.n8n.io/integrations/builtin/app-nodes/n8n-nodes-base.microsoftexcel/)\n\nFinally to capture the data, we can map these to an Excel workflow which can be reviewed by a human before it enters the accounting system."},"typeVersion":1},{"id":"68f7c7f3-5ddd-4291-adb3-78f3a297fd8e","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-2120,-660],"parameters":{"width":480,"height":960,"content":"## Try it out\n### This n8n template monitors an Outlook mailbox for invoices, automatically parses/extracts data from them and then uploads the output to an Excel Workbook.\n\nOne of my top workflow requests, this template can save in order of 100s of hours of manual labour for you or your finance team.\n\n### How it works\n* A scheduled trigger is set to fetch recent Outlook messages to the Accounts receivable mailbox.\n* Each message is analysed to determine whether or not it from a supplier and is issuing/contains an invoice.\n* For each valid message, the attachments are downloaded and non-invoice documents are filtered out via AI Vision classification.\n* Invoices are then processed through a AI vision model again to extract the details.\n* The extracted data can then be used for reconciliation or otherwise. For this demonstration, we'll just append the row to an Excel sheet for now.\n\n### How to use\n* Ensure your Microsoft365 credential points to the correct mailbox. If a shared folder is used, toggle \"shared folder\" option to \"on\" and for the principal ID, use the email address.\n* If you receive lots of other types of messages such as replies and forwards, you may want to implement additional checks to prevent processing invoices twice. The \"remove duplicates\" node can help with this.\n\n### Need Help?\nJoin the [Discord](https://discord.com/invite/XPKeKXeB7d) or ask in the [Forum](https://community.n8n.io/)!\n\nHappy Hacking!"},"typeVersion":1},{"id":"a55323b4-2079-4a7c-8ba2-f20ef0930b55","name":"Invoice Classifier With Gemini 2.0","type":"n8n-nodes-base.httpRequest","position":[-260,340],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent","method":"POST","options":{},"jsonBody":"={{\n{\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"inline_data\": {\n            \"mime_type\": $('Split Attachments').item.binary.data.mimeType,\n            \"data\": $json.data\n          }\n        },\n        {\n          \"text\": `You are an accounts receivable agent who is helping to identify if the document is an invoice, the invoice's supplier is not our company and the invoice is issued to our company.`\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"response_mime_type\": \"application/json\",\n    \"response_schema\": {\n      \"type\": \"OBJECT\",\n      \"required\": [\n        \"is_invoice\",\n        \"is_issued_to_company\"\n      ],\n      \"properties\": {\n        \"is_invoice\": { \"type\": \"boolean\" },\n        \"is_issued_to_company\": { \"type\": \"boolean\" }\n      }\n    }\n  }\n}\n}}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"executeOnce":false,"retryOnFail":false,"typeVersion":4.2},{"id":"f696737d-cddf-411b-a427-cc72bd68d248","name":"File-Based OCR with Gemini 2.0","type":"n8n-nodes-base.httpRequest","onError":"continueErrorOutput","position":[480,400],"parameters":{"url":"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent","method":"POST","options":{},"jsonBody":"={{\n{\n  \"contents\": [\n    {\n      \"parts\": [\n        {\n          \"inline_data\": {\n            \"mime_type\": $('Split Attachments').item.binary.data.mimeType,\n            \"data\": $('Extract from File').item.json.data\n          }\n        },\n        {\n          \"text\": `You are an accounts receivable agent who is helping to extract information from a supplier's invoice issued to our company.`\n        }\n      ]\n    }\n  ],\n  \"generationConfig\": {\n    \"response_mime_type\": \"application/json\",\n    \"response_schema\": {\n      \"type\": \"OBJECT\",\n      \"required\": [\n        \"invoice_number\",\n        \"invoice_date\",\n        \"invoice_amount\",\n        \"invoice_due_date\",\n        \"supplier_name\",\n        \"supplier_address\",\n        \"supplier_telephone\",\n        \"supplier_email\",\n        \"booking_number\",\n        \"booking_date\",\n        \"booking_name\",\n        \"guest_name\",\n        \"guest_quantity\",\n        \"services\"\n      ],\n      \"properties\": {\n        \"invoice_number\": { \"type\": \"string\" },\n        \"invoice_date\": { \"type\": \"string\", \"nullable\": true },\n        \"invoice_amount\": { \"type\": \"number\", \"nullable\": true },\n        \"invoice_due_date\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_name\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_address\": { \"type\": \"string\", \"nullable\": true },\n        \"recipient_company_number\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_name\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_address\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_telephone\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_email\": { \"type\": \"string\", \"nullable\": true },\n        \"supplier_company_number\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_number\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_date\": { \"type\": \"string\", \"nullable\": true },\n        \"booking_name\": { \"type\": \"string\", \"nullable\": true },\n        \"guest_name\": { \"type\": \"string\", \"nullable\": true },\n        \"guest_quantity\": { \"type\": \"number\", \"nullable\": true },\n        \"services\": {\n          \"type\": \"array\",\n          \"items\": {\n            \"type\": \"object\",\n            \"required\": [],\n            \"properties\": {\n              \"name\": { \"type\": \"string\" },\n              \"date\": { \"type\": \"string\", \"nullable\": true },\n              \"description\": { \"type\": \"string\", \"nullable\": true },\n              \"quantity\": { \"type\": \"number\", \"nullable\": true },\n              \"total\": { \"type\": \"number\" }\n            }\n          }\n        }\n      }\n    }\n  }\n}\n}}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googlePalmApi"},"credentials":{"googlePalmApi":{"id":"dSxo6ns5wn658r8N","name":"Google Gemini(PaLM) Api account"}},"executeOnce":false,"retryOnFail":false,"typeVersion":4.2},{"id":"1d76c0c8-a03b-4f0c-b76d-53369ab5d6e8","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[760,-220],"parameters":{"color":5,"width":400,"height":140,"content":"### Where Next? It's Up to You!\nThis template is deliberately cut short to demonstrate the build but should be easily modified to upload directly to an accounting system or even extended for other tasks such as invoice reconciliation and more."},"typeVersion":1}],"connections":{"Wait":{"main":[[{"node":"For Each Message","type":"main","index":0}]]},"Model":{"ai_languageModel":[[{"node":"Message Classifier","type":"ai_languageModel","index":0}]]},"Markdown":{"main":[[{"node":"Message Classifier","type":"main","index":0}]]},"Message Ref":{"main":[[{"node":"Download Attachments","type":"main","index":0}]]},"Has Invoice?":{"main":[[{"node":"File-Based OCR with Gemini 2.0","type":"main","index":0}],[{"node":"Empty Response","type":"main","index":0}]]},"Parse Output":{"main":[[{"node":"Wait","type":"main","index":0}]]},"Empty Response":{"main":[[{"node":"Wait","type":"main","index":0}]]},"Filter Invoices":{"main":[[{"node":"Has Invoice?","type":"main","index":0}]]},"For Each Message":{"main":[[{"node":"Microsoft Excel 365","type":"main","index":0}],[{"node":"Message Ref","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Get Recent Messages","type":"main","index":0}]]},"Extract from File":{"main":[[{"node":"Invoice Classifier With Gemini 2.0","type":"main","index":0}]]},"Split Attachments":{"main":[[{"node":"Extract from File","type":"main","index":0}]]},"Message Classifier":{"main":[[{"node":"For Each Message","type":"main","index":0}],[]]},"Get Recent Messages":{"main":[[{"node":"Markdown","type":"main","index":0}]]},"Download Attachments":{"main":[[{"node":"Split Attachments","type":"main","index":0}]]},"File-Based OCR with Gemini 2.0":{"main":[[{"node":"Parse Output","type":"main","index":0}],[{"node":"Empty Response","type":"main","index":0}]]},"Invoice Classifier With Gemini 2.0":{"main":[[{"node":"Filter Invoices","type":"main","index":0}],[]]}}}


name: Analyze Crypto Markets with the AI-Powered CoinMarketCap Data Analyst
author_name: Don Jayamaha Jr
author_username: don-the-gem-dealer
categories: []
created_at: 2025-04-03T13:53:03.108Z
updated_at: 2025-04-03T13:53:03.108Z
url: https://n8n.io/workflows/3425
scraped_at: 2025-07-06 21:16:30
description:
  Meet your AI-powered crypto data analyst—fully integrated with CoinMarketCap APIs.  

  This workflow acts as the supervisor agent for a multi-agent architecture built in n8n, connecting three powerful sub-agents to extract real-time insights from centralized and decentralized markets. It’s the ultimate tool for crypto traders, analysts, developers, and researchers who need strategic multi-source intelligence—all through Telegram.

  This workflow requires 3 sub-agent templates to function correctly. See below.

  🔌 Required Sub-Workflows (Install First)

  CoinMarketCap Crypto Agent Tool  
     → Token prices, metadata, conversions, listings

  CoinMarketCap Exchange & Community Agent Tool  
     → Exchange info, token holdings, Fear & Greed index

  CoinMarketCap DEXScan Agent Tool  
     → DEX trading pairs, liquidity, OHLCV data

   Download all from my Creator Profile:  
   https://n8n.io/creators/don-the-gem-dealer/

  What Makes This Workflow Special?

  This is not just another API wrapper—it’s an intelligent routing agent powered by GPT-4o-mini, capable of:

  Understanding complex user queries  
  Choosing the appropriate tool workflow  
  Structuring the API request  
  Executing sub-workflows  
  Formatting the output  
  Returning insights via Telegram

  It connects three domains of market data:
  Cryptocurrencies (CEX)**
  Exchanges & Sentiment**
  DEX trading data**

  🔍 What You Can Do  

  💰 Token Intelligence
  Get token metadata, price, volume, supply
  Compare rankings and conversions

  🏦 Exchange Insights
  View assets held by exchanges
  Track the CMC 100 Index and Fear & Greed Score

  🌐 DEX Market Analysis
  Analyze pair quotes, historical OHLCV, live trades
  Discover the top DEXs by volume across blockchains

  ✅ Example Questions to Ask
  “What’s the market cap of Ethereum today?”  
  “Show liquidity and volume for SOL/USDT on Solana”  
  “Get token holdings for Binance”  
  “Compare BTC price on Uniswap vs Binance”  
  “What’s the Fear & Greed index right now?”

  🛠️ Setup Instructions

  Create Telegram Bot  
     Use @BotFather to get your bot token.

  Get CoinMarketCap API Key  
     Apply here: https://coinmarketcap.com/api/

  Install Sub-Agent Templates  
     Required:
       Crypto Agent Tool  
       Exchange & Community Tool  
       DEXScan Tool

  Configure Credentials in n8n  
     Add both Telegram and CoinMarketCap keys as HTTP Header Auth.

  Deploy & Test  
     Ask your Telegram bot: “Top 10 tokens by 24h volume” or “Convert 5 ETH to USD”

  Workflow Architecture

  AI Brain**: GPT-4o-mini  
  Memory**: Windowed buffer memory via sessionId  
  Tool Agents**:  
     toolWorkflow() → routes requests to the appropriate sub-agent  
     Executes real-time API queries and returns structured output

  Included Sticky Notes  
  System Overview**  
  Error Handling Guide (200, 400, 401, 429, 500)**  
  Step-by-Step Usage Instructions**  
  Prompt Examples + API Docs**  
  Legal & Licensing Notes**

  Your crypto insights—smarter, faster, and all in one Telegram message.

nodes_used:
  ["n8n-nodes-base.telegram","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.toolWorkflow"]

workflow_json:
  {"id":"mE7Zvhv1lOd4Q3xY","meta":{"instanceId":"a5283507e1917a33cc3ae615b2e7d5ad2c1e50955e6f831272ddd5ab816f3fb6"},"name":"CoinMarketCap_AI_Data_Analyst_Agent","tags":[],"nodes":[{"id":"1eab0bd5-8f9c-4bc4-92b7-50779baa505c","name":"Telegram Send Message","type":"n8n-nodes-base.telegram","position":[1180,0],"webhookId":"0eeae020-ed6f-4900-ae38-d646d893171d","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Telegram Input').item.json.message.chat.id }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"R3vpGq0SURbvEw2Z","name":"Telegram account"}},"typeVersion":1},{"id":"fd89fa7e-c4e1-4559-a0cc-42beaeccefb4","name":"Adds SessionId","type":"n8n-nodes-base.set","position":[280,0],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b5c25cd4-226b-4778-863f-79b13b4a5202","name":"sessionId","type":"string","value":"={{ $json.message.chat.id }}"}]},"includeOtherFields":true},"typeVersion":3.4},{"id":"aea9adc8-8215-4459-9bf0-5a6b6364ffcc","name":"CoinMarketCap AI Data Analyst Agent","type":"@n8n/n8n-nodes-langchain.agent","notes":"{{ $json.sessionId }}","position":[660,0],"parameters":{"text":"={{ $json.message.text }}","options":{"systemMessage":"You are the **CoinMarketCap AI Data Analyst**, a powerful, multi-source crypto intelligence system that integrates three specialized agents:  \n- **CoinMarketCap Crypto Agent**  \n- **CoinMarketCap Exchange & Community Agent**  \n- **CoinMarketCap DEXScan Agent**\n\nYour job is to provide accurate, real-time, and strategic insights into the cryptocurrency landscape across centralized and decentralized platforms.\n\n---\n\n### 🛠️ Tools and Agent Capabilities\n\nYou have access to a suite of **live CoinMarketCap APIs** organized by sub-agents. Each tool is mapped to an endpoint and validated for parameter safety to avoid 400 errors.\n\n---\n\n#### 🔹 1. CoinMarketCap Crypto Agent\n\n**Focus:** Cryptocurrency-level data, listings, quotes, and conversions.\n\n**Tools:**\n- `Crypto Map` – Get coin IDs, names, symbols  \n- `Crypto Info` – Metadata like whitepapers, socials  \n- `Crypto Listings` – Top market cap coins  \n- `Quotes Latest` – Live price, volume, market cap  \n- `Global Metrics` – Total market stats, BTC dominance  \n- `Price Conversion` – Convert one asset to another  \n\n✅ Use for:  \n“Top 10 coins by market cap,” “Convert 5 ETH to USD,” “BTC volume today,” “Whitepaper for SOL”\n\n---\n\n#### 🔹 2. CoinMarketCap Exchange & Community Agent\n\n**Focus:** Exchange intel, community sentiment, and market behavior.\n\n**Tools:**\n- `Exchange Map` – Discover exchanges and get IDs  \n- `Exchange Info` – Metadata like launch date, country, links  \n- `Exchange Assets` – Exchange token holdings & wallets  \n- `CMC 100 Index` – Latest CMC 100 index constituents  \n- `Fear and Greed Index` – Market sentiment tracker  \n\n✅ Use for:  \n“Which tokens does Binance hold?” “Current crypto sentiment” “Top 100 CMC coins”\n\n---\n\n#### 🔹 3. CoinMarketCap DEXScan Agent\n\n**Focus:** Decentralized trading data (spot pairs, pools, liquidity, OHLCV, trades).\n\n**Tools:**\n- `DEX Metadata` – Info for any DEX (logo, date, description)  \n- `DEX Networks List` – All blockchain networks  \n- `DEX Listings Quotes` – DEXs with live trading stats  \n- `DEX Pair Quotes Latest` – Live price/liquidity for spot pairs  \n- `DEX OHLCV Historical` – Historical OHLCV (e.g., 1h, 1d)  \n- `DEX OHLCV Latest` – Real-time OHLCV for current UTC day  \n- `DEX Trades Latest` – Up to 100 recent trades  \n- `DEX Spot Pairs Latest` – All active spot pairs with filters  \n\n✅ Use for:  \n“Price history of USDT/ETH on Uniswap,” “Show DEXs with highest volume,” “Get liquidity of token pair,” “Security scan for PancakeSwap pools”\n\n---\n\n### ⚙️ Multi-Agent Coordination (Advanced Multi-Query Reasoning)\n\nYou are empowered with **advanced multi-query analysis** capabilities:\n- Chain data between agents (e.g., map → quote → historical chart)\n- Use outputs from one tool as inputs for another\n- Automatically fetch required IDs (e.g., exchange ID, contract address) before making a final API call\n- Combine centralized (CEX) and decentralized (DEX) insights into one unified response\n- Filter and compare across timeframes, assets, exchanges, and networks\n\n---\n\n### ⚠️ Validation & Error Prevention Guidelines\n\nTo prevent 400 Bad Request errors:\n- Always include at least **one required field** per endpoint  \n- Use **valid slugs, symbols, or CoinMarketCap IDs**  \n- Don’t use `convert` and `convert_id` together  \n- Use **comma-separated lists** for multi-inputs (if allowed)  \n- Use documented `aux`, `sort`, `interval` fields only  \n- Handle pagination via `scroll_id` or `start/limit` properly  \n\nIf output is too large:\n> ⚠️ “The requested data exceeds the model’s context limit. Please reduce the scope using filters, limits, or sort.”\n\n---\n\n### ✅ Example Tasks You Can Perform\n- “Get liquidity and 24h volume for ETH/USDC on Polygon”\n- “Compare BTC price on Binance vs Uniswap”\n- “Show top 5 DEXs by volume and their top pairs”\n- “Analyze historical price of SHIBA on Ethereum over last 7 days”\n- “Get CoinMarketCap’s sentiment index and top index coins”\n- “List active spot pairs on Arbitrum with volume > $1M and return price, liquidity, and last 24h % change”\n\n---\n\nYou are a **real-time, multi-source AI analyst** purpose-built to extract deep insights from CoinMarketCap’s centralized and decentralized datasets. Use your agents intelligently, validate your queries, and return precise, structured results.\n\nLet’s analyze the crypto world. 🌍📊🧠\n"},"promptType":"define"},"typeVersion":1.7},{"id":"955f82c6-ce76-4d56-9714-4926a4936cbf","name":"CoinMarketCap Agent Brain","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[420,280],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yUizd8t0sD5wMYVG","name":"OpenAi account"}},"typeVersion":1.2},{"id":"2c253e1f-5a34-4334-8a8a-98c1e9e937cd","name":"CoinMarketCap Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[580,280],"parameters":{},"typeVersion":1.3},{"id":"0878a84b-14a3-4f8e-b94d-339b1c759f4d","name":"CoinMarketCap Crypto Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[740,280],"parameters":{"name":"CoinMarketCap_Crypto_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"R4EuB1gx1IpMXCJM","cachedResultName":"JayaFamily Assistant — CoinMarketCap_Crypto_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true},{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"4a6e4ae9-5ba5-48ab-8198-a7cd8c84b0ee","name":"CoinMarketCap Exchange and Community Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[900,280],"parameters":{"name":"CoinMarketCap_Exchange_and_Community_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"kbJb4VMD3SZlcS2u","cachedResultName":"JayaFamily Assistant — CoinMarketCap_Exchange_and_Community_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"77ffefe3-9671-4155-baed-d782035b6079","name":"CoinMarketCap DEXScan Agent Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[1080,280],"parameters":{"name":"CoinMarketCap_DEXScan_Agent_Tool","workflowId":{"__rl":true,"mode":"list","value":"ImiznkEUWCkKbg1w","cachedResultName":"JayaFamily Assistant — CoinMarketCap_DEXScan_Agent_Tool"},"workflowInputs":{"value":{"message":"={{ $fromAI(\"message\",\"Populate this with a relevant message to this subagent\")}}","sessionId":"={{ $json.sessionId }}"},"schema":[{"id":"sessionId","type":"string","display":true,"removed":false,"required":false,"displayName":"sessionId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"message","type":"string","display":true,"removed":false,"required":false,"displayName":"message","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"d3fc4697-478b-4e6e-8d42-8138ec614748","name":"Telegram Input","type":"n8n-nodes-base.telegramTrigger","position":[-220,0],"webhookId":"b33d2025-01c2-4386-b677-206a87a1856b","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"R3vpGq0SURbvEw2Z","name":"Telegram account"}},"typeVersion":1.1},{"id":"d1108256-43c3-403f-bb7d-181c6de62f2a","name":"CMC Multi-Agent Guide","type":"n8n-nodes-base.stickyNote","position":[-1600,-1600],"parameters":{"width":1180,"height":1960,"content":"# 📊 CoinMarketCap AI Analyst Agent (n8n Workflow)\n\n## 🧠 Multi-Agent System Overview\nThis is the **primary supervisor agent** for the **CoinMarketCap AI Analyst Workflow**, designed using **modular AI agent architecture** in **n8n**.\n\n⚠️ **This workflow requires 3 external tool workflows to function properly.** You must download, install, and connect the following:\n\n### 🔌 Required Sub-Agent Tools:\n1. **CoinMarketCap_Crypto_Agent_Tool** – Handles cryptocurrency quotes, listings, conversions\n2. **CoinMarketCap_Exchange_and_Community_Agent_Tool** – Handles exchanges, trending tokens, Fear & Greed Index\n3. **CoinMarketCap_DEXScan_Agent_Tool** – Handles decentralized liquidity, pair quotes, OHLCV analysis\n\nOnce installed, these agents enable advanced capabilities:\n\n### ✅ Key AI Functions:\n- Analyze market caps, volumes, supply metrics across coins\n- Track new listings and top gainers/losers\n- Evaluate trading pairs and liquidity in CEX and DEX markets\n- Retrieve sentiment indicators and trending discussions\n\n---\n\n## 🧠 Node Structure Summary\n\n### **1️⃣ Analyst Brain**\n- **Model**: GPT-4o Mini\n- **Function**: Understands user queries, delegates tasks to agents\n\n### **2️⃣ Memory Buffer**\n- Stores session state and context between prompts\n\n### **3️⃣ Tool Triggers**\n- **toolWorkflow()** function calls: \n   - `CoinMarketCap_Crypto_Agent_Tool`\n   - `CoinMarketCap_Exchange_and_Community_Agent_Tool`\n   - `CoinMarketCap_DEXScan_Agent_Tool`\n\n---\n\n## ⚠️ Notes:\n- 📎 Make sure API credentials are installed and valid for each agent\n- 📍 Each tool runs independently but feeds results to the supervisor for synthesis\n- 🧩 Use `message` and `sessionId` parameters consistently in every sub-agent call\n\n# 📊 CoinMarketCap AI Analyst Agent Tools (n8n Workflow) Guide\n\n## 🚀 Workflow Overview\nThe **CoinMarketCap AI Analyst Agent** is a modular AI-powered system built on **n8n** to deliver **real-time crypto market insights**. It connects directly to CoinMarketCap APIs across three specialized agents:\n\n- **Cryptocurrency Agent** – Market listings, quotes, conversions, and token info.\n- **Exchange & Community Agent** – Trending topics, exchange performance, and sentiment.\n- **DEXScan Agent** – Liquidity, trading volume, and OHLC data on decentralized markets.\n\n### 🎯 **Key Capabilities**:\n- Fetch latest token listings and rank movements\n- Track real-time price quotes and convert values between currencies\n- Compare metrics like market cap, volume, and dominance\n- Monitor exchange market pairs and volume\n- Analyze community sentiment and Fear & Greed Index\n- Visualize DEX liquidity and historical trading trends\n\n---\n\n## 🔗 Node Architecture Summary\n\n### **1️⃣ AI Analyst Brain**\n- **Type**: GPT-4o Mini\n- **Function**: Interprets prompts and queries, routes requests to proper sub-agent.\n\n### **2️⃣ Session Memory**\n- **Type**: Memory Buffer\n- **Function**: Maintains query context during conversation.\n\n### **3️⃣ Tool Agents**\n- **Type**: Tool Workflow\n- Cryptocurrency / Exchange / DEXScan agent endpoints trigger APIs with mapped params.\n\n"},"typeVersion":1},{"id":"5800cdc3-7d4b-4385-8401-b5913a43a28d","name":"CMC Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1260,-1600],"parameters":{"color":3,"width":680,"height":600,"content":"## ⚠️ Error Handling Guide\n\n| **Error Code** | **Meaning** |\n|---------------|------------|\n| `200` | Success |\n| `400` | Bad Request (invalid query/params) |\n| `401` | Unauthorized (missing or invalid API key) |\n| `429` | Rate Limit Exceeded |\n| `500` | CoinMarketCap server error |\n\n### 🔍 Common Fixes\n- Ensure `symbol`, `slug`, or `id` match valid CoinMarketCap entries\n- Use correct `timestamp`, `network`, and pagination parameters\n- Rate-limit high-frequency queries to avoid 429 errors\n\n---\n\n## 🚀 Need Help?\nFor custom CoinMarketCap agent support, dashboards, or token data automation, connect:\n\n🌐 **Don Jayamaha — LinkedIn**  \n🔗 [http://linkedin.com/in/donjayamahajr](http://linkedin.com/in/donjayamahajr)\n\n© 2025 Treasurium Capital Limited Company. All rights reserved.\nThis AI workflow architecture, including logic, design, and prompt structures, is the intellectual property of Treasurium Capital Limited Company. Unauthorized reproduction, redistribution, or resale is prohibited under U.S. copyright law. Licensed use only.\n"},"typeVersion":1},{"id":"068e7732-d92e-4a1d-a4b5-c0ee6363f3fb","name":"CMC Sticky Note","type":"n8n-nodes-base.stickyNote","position":[0,-1600],"parameters":{"color":5,"width":900,"height":1500,"content":"## 📌 How to Use the Workflow\n\n### ✅ Step 1: Provide Inputs\n- Use token `symbol`, `slug`, or `ID`\n- Set timestamps (`before`, `after`) in **Unix format** for historical data\n- Use `chain`, `limit`, and `start` for pagination when needed\n\n### ✅ Step 2: Execute API Tools\n- The AI routes queries to sub-agents: **Cryptocurrency**, **Exchange**, or **DEXScan**\n\n### ✅ Step 3: Get Response & Output\n- Results can be output to Telegram, dashboards, or n8n HTTP Response nodes\n\n---\n\n## 🗣️ Example Questions to Ask the CMC AI Analyst\n\n### 💬 Market Intelligence\n- \"What are the top 5 tokens by trading volume right now?\"\n- \"Which coins gained the most in the last 24 hours?\"\n- \"What’s the total crypto market cap today?\"\n\n### 💬 Token Insights\n- \"What’s the price of SOL in USD?\"\n- \"How much is 1000 USDT in BTC?\"\n- \"Show me the description and whitepaper link for Dogecoin.\"\n\n### 💬 Exchange & Sentiment\n- \"What’s the Fear & Greed index today?\"\n- \"List exchanges with the highest asset holdings.\"\n- \"Give me info about Binance – when was it launched?\"\n\n### 💬 DEX Data\n- \"Show me the top DEX spot pairs on Ethereum.\"\n- \"What’s the OHLCV data for SOL-USDT on Solana over the last 7 days?\"\n- \"What trades just occurred on PancakeSwap?\"\n\n---\n\n## ⚠️ Example API Queries\n\n### 1️⃣ Get Top 5 Tokens by Volume\n```plaintext\nGET /v1/cryptocurrency/listings/latest?sort=volume_24h&limit=5\n```\n\n### 2️⃣ Convert 1000 USDT to BTC\n```plaintext\nGET /v1/tools/price-conversion?amount=1000&symbol=USDT&convert=BTC\n```\n\n### 3️⃣ Check Fear & Greed Index\n```plaintext\nGET /v3/fear-and-greed/latest\n```\n\n### 4️⃣ Get OHLCV of DEX Pair\n```plaintext\nGET /v4/dex/pairs/ohlcv/historical?network=solana&pair=SOL-USDT&interval=1d\n```\n\n---"},"typeVersion":1}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"ed2f29c5-293a-4796-8986-9c5f9980c6c6","connections":{"Adds SessionId":{"main":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"main","index":0}]]},"Telegram Input":{"main":[[{"node":"Adds SessionId","type":"main","index":0}]]},"CoinMarketCap Memory":{"ai_memory":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_memory","index":0}]]},"CoinMarketCap Agent Brain":{"ai_languageModel":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_languageModel","index":0}]]},"CoinMarketCap Crypto Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]},"CoinMarketCap DEXScan Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]},"CoinMarketCap AI Data Analyst Agent":{"main":[[{"node":"Telegram Send Message","type":"main","index":0}]]},"CoinMarketCap Exchange and Community Agent Tool":{"ai_tool":[[{"node":"CoinMarketCap AI Data Analyst Agent","type":"ai_tool","index":0}]]}}}


name: Automate Call Scheduling with Voice AI Receptionist using Vapi, Google Calendar & Airtable
author_name: SuperAgent
author_username: customaistudio
nodes_used: ["n8n-nodes-base.airtable","n8n-nodes-base.googleCalendar","n8n-nodes-base.code"]
categories: []
created_at: 2025-04-03T19:05:21.114Z
updated_at: 2025-04-03T19:05:21.114Z
url: https://n8n.io/workflows/3427
scraped_at: 2025-07-06 21:16:30
description:
  Who is this template for?

  This template is ideal for small businesses, agencies, and solo professionals who want to automate appointment scheduling and caller follow-up through a voice-based AI receptionist. If you’re using tools like Google Calendar, Airtable, and Vapi (Twilio), this setup is for you.

  What problem does this workflow solve?

  Manual call handling, appointment booking, and email coordination can be time-consuming and prone to errors. This workflow solves that by automating the receptionist role: answering calls, checking calendar availability, managing appointments, and storing call summaries—all without human intervention.

  What this workflow does

  This Agent Receptionist manages inbound voice calls and scheduling tasks using Vapi and Google Calendar. It checks availability, books or updates calendar events, sends email confirmations, and logs call details into Airtable. The workflow includes built-in logic for slot management, email triggers, and storing call transcripts. 

  Setup Instructions

  Duplicate Airtable Base: Use this Airtable base templateBASE LINK 

  Import Workflow: Load provided JSON into your n8n instance.

  Credentials: Connect your Google Calendar and Airtable credentials in n8n.

  Activate Workflow: Enable workflow to get live webhook URLs.

  Vapi Configuration:

  Paste provided system prompt into Vapi Assistant. 

  Link the appropriate webhook URLs from n8n (GetSlots, BookSlots, UpdateSlots, CancelSlots, and end-of-call report).



  Disclaimer

  Optimized for cloud-hosted n8n instances. Self-hosted users should verify webhook and credential setups.

workflow_json:
  {"meta":{"instanceId":"1954c8c806bedb8f0628725b26b786028ade16c78a82bc25deb9dd961e036832"},"nodes":[{"id":"36d0b0d4-b454-4a9b-8168-bcc7942a7cc7","name":"Input Arguments","type":"n8n-nodes-base.set","position":[520,740],"parameters":{"options":{},"assignments":{"assignments":[{"id":"ccabe9f4-7911-4488-a75b-7c5779fb2014","name":"timeZone","type":"string","value":"=America/Chicago"},{"id":"b802d976-78f5-4c00-8764-f8c49eaded29","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"02d58122-6a0f-4bdb-9914-6f50d2af6df4","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"c1249493-a1d7-4a91-9468-9e5c49430d2e","name":"body.message.toolCalls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"2d1e0d9a-4c70-488e-b430-b8137fd54970","name":"customer.number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.3},{"id":"2d8485ad-9007-4664-9182-7eda25fc96ee","name":"Format response","type":"n8n-nodes-base.itemLists","position":[2000,840],"parameters":{"include":"allFieldsExcept","options":{},"aggregate":"aggregateAllItemData","operation":"concatenateItems","fieldsToExclude":"sort","destinationFieldName":"response"},"typeVersion":3},{"id":"b23c75e0-3697-4137-a595-cf26fedaa898","name":"Sort","type":"n8n-nodes-base.itemLists","position":[1760,840],"parameters":{"options":{},"operation":"sort","sortFieldsUi":{"sortField":[{"fieldName":"sort"}]}},"typeVersion":3},{"id":"660e3d2f-a424-4e76-8c13-5b62b9f22202","name":"Available Start Times & Ranges","type":"n8n-nodes-base.code","position":[2240,840],"parameters":{"jsCode":"// Input data\nconst inputData = $input.all()[0].json.response;\n\n// Define workday hours in CST\nconst WORKDAY_START = \"09:00:00 CST\";\nconst WORKDAY_END = \"18:00:00 CST\";\nconst SLOT_DURATION = 30 * 60 * 1000; // 30 minutes in milliseconds\n\n// Helper to parse CST datetime strings\nconst parseCST = (datetime) => {\n  const parsedDate = new Date(datetime.replace(\" CST\", \"-06:00\"));\n  return isNaN(parsedDate) ? null : parsedDate;\n};\n\n// Function to generate 30-minute start times\nconst generateStartTimes = (start, end) => {\n  const startTimes = [];\n  let current = new Date(start);\n\n  while (current < end) {\n    startTimes.push(\n      current.toLocaleTimeString('en-US', {\n        timeZone: 'CST',\n        hour: '2-digit',\n        minute: '2-digit',\n      })\n    );\n    current = new Date(current.getTime() + SLOT_DURATION);\n  }\n\n  return startTimes;\n};\n\n// Function to find wide open ranges\nconst findWideOpenRanges = (startTimes) => {\n  if (startTimes.length < 3) return []; // Not enough slots for a wide open range\n\n  const ranges = [];\n  let rangeStart = null;\n  let consecutiveCount = 0;\n\n  for (let i = 0; i < startTimes.length - 1; i++) {\n    const currentTime = parseCST(`2000-01-01 ${startTimes[i]} CST`);\n    const nextTime = parseCST(`2000-01-01 ${startTimes[i + 1]} CST`);\n    const diff = nextTime - currentTime;\n\n    if (diff === SLOT_DURATION) {\n      consecutiveCount += 1;\n      if (rangeStart === null) rangeStart = startTimes[i];\n    } else {\n      if (consecutiveCount >= 2) {\n        ranges.push(`${rangeStart} to ${startTimes[i]}`);\n      }\n      rangeStart = null;\n      consecutiveCount = 0;\n    }\n  }\n\n  // Handle the final range\n  if (consecutiveCount >= 2) {\n    ranges.push(`${rangeStart} to ${startTimes[startTimes.length - 1]}`);\n  }\n\n  return ranges;\n};\n\n// Group meetings by date, ignoring invalid dates\nconst meetingsByDate = inputData.reduce((acc, meeting) => {\n  const start = parseCST(meeting.start);\n  const end = parseCST(meeting.end);\n\n  if (!start || !end) {\n    return acc; // Ignore invalid dates\n  }\n\n  const dateKey = start.toISOString().split('T')[0];\n\n  if (!acc[dateKey]) {\n    acc[dateKey] = [];\n  }\n\n  acc[dateKey].push({ start, end });\n  return acc;\n}, {});\n\n// Generate availability\nconst availability = Object.keys(meetingsByDate)\n  .filter((date) => {\n    // Exclude Saturdays (6) and Sundays (0)\n    const dayOfWeek = new Date(date).getUTCDay();\n    return dayOfWeek !== 0 && dayOfWeek !== 6;\n  })\n  .map((date) => {\n    const workdayStart = parseCST(`${date} ${WORKDAY_START}`);\n    const workdayEnd = parseCST(`${date} ${WORKDAY_END}`);\n\n    const dayMeetings = meetingsByDate[date].sort((a, b) => a.start - b.start);\n\n    let availableStartTimes = [];\n    let lastEnd = workdayStart;\n\n    for (const meeting of dayMeetings) {\n      if (meeting.start > lastEnd) {\n        availableStartTimes = availableStartTimes.concat(generateStartTimes(lastEnd, meeting.start));\n      }\n      lastEnd = meeting.end > lastEnd ? meeting.end : lastEnd;\n    }\n\n    if (lastEnd < workdayEnd) {\n      availableStartTimes = availableStartTimes.concat(generateStartTimes(lastEnd, workdayEnd));\n    }\n\n    const wideOpenRanges = findWideOpenRanges(availableStartTimes);\n\n    return {\n      date: new Date(date).toLocaleDateString('en-US', {\n        weekday: 'long',\n        year: 'numeric',\n        month: 'long',\n        day: 'numeric',\n      }),\n      availableStartTimes,\n      wideOpenRanges,\n    };\n  });\n\n// Format output as plaintext\nconst availableTimes = availability\n  .map(({ date, availableStartTimes, wideOpenRanges }) => {\n    const times = availableStartTimes.map((time) => `- ${time}`).join('\\n');\n    const ranges = wideOpenRanges.length\n      ? `Wide Open Ranges:\\n${wideOpenRanges.map((range) => `- ${range}`).join('\\n')}`\n      : \"Wide Open Ranges: None\";\n\n    return `### ${date}\\nAvailable Start Times:\\n${times}\\n\\n${ranges}`;\n  })\n  .join('\\n\\n');\n\n// Set the output\nreturn {\n  json: {\n    availableTimes,\n  },\n};\n"},"typeVersion":2},{"id":"f3110658-2f90-4b19-9874-7d6c4e108895","name":"Flatten Slots","type":"n8n-nodes-base.code","position":[2460,840],"parameters":{"mode":"runOnceForEachItem","jsCode":"const flattenSlots = (data) => {\n  // If data is missing or empty, return an empty array of slots\n  if (!data) {\n    return { slots: [] };\n  }\n\n  // data is an object whose keys are dates\n  // each date key has an array of slot objects\n  // we just need to flatten them all into one array\n  const flattened = Object.values(data).flat();  // merges all arrays from each date key\n\n  // Return a new object with a single 'slots' array\n  return { slots: flattened };\n};\n\n// Then assign the flattened slots back to $input.item.json.data\n$input.item.json.data = flattenSlots($input.item.json.data);\nreturn $input.item;\n"},"typeVersion":2},{"id":"5065439e-34e3-4eaf-8226-8ba7393a5cf3","name":"Enrich Date","type":"n8n-nodes-base.code","position":[2680,840],"parameters":{"mode":"runOnceForEachItem","jsCode":"function formatTimeSlot(dateString) {\n  // Format options for date/time with America/Chicago timezone\n  const options = {\n    timeZone: 'America/Chicago',\n    weekday: 'long',\n    month: 'long',\n    day: 'numeric',\n    hour: 'numeric',\n    minute: 'numeric',\n    hour12: true\n  };\n\n  // Create a formatter with timezone support\n  const dateFormatter = new Intl.DateTimeFormat('en-US', options);\n  \n  // Format the date/time string\n  return dateFormatter.format(new Date(dateString));\n}\n\n// Process each slot and add formatted time strings to the result\nconst slots = $input.item.json.data.slots;\nconst formattedSlots = slots.map(slot => formatTimeSlot(slot.start));\n\n// Attach formatted results to the output\n$input.item.json.data.slots = formattedSlots;\n\nreturn $input.item;\n"},"typeVersion":2},{"id":"d8ed3a92-697b-4718-b65f-5276c9a9bfaf","name":"Build Response Payload","type":"n8n-nodes-base.set","position":[2900,840],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments').item.json.body.message.toolCalls[0].id }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"={{ $json.availableTimes }}"}]}},"typeVersion":3.4},{"id":"a0697944-c5a6-4ca1-9948-8248940841b2","name":"Booking Payload","type":"n8n-nodes-base.set","position":[1980,1400],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"05bbc797-b781-489c-ab70-e234fe17eb62","name":"id","type":"number","value":"={{ $json.id }}"},{"id":"4bb68abf-18c8-4445-b446-21667abd95aa","name":"description","type":"string","value":"={{ $json.description }}"},{"id":"74a98b77-b9fe-40cc-84c8-fc7303c5cfa6","name":"startTime","type":"string","value":"={{ $json.start.dateTime }}"},{"id":"2934d6a7-9e6b-4038-891c-0b05ba18cb21","name":"endTime","type":"string","value":"={{ $json.end.dateTime }}"},{"id":"10f091c8-5e52-40dc-a294-87625be9af99","name":"status","type":"string","value":"={{ $json.status }}"},{"id":"cdc5e1ab-a29b-447f-8343-ff1c1b168717","name":"Timezone","type":"string","value":"={{ $json.end.timeZone }}"},{"id":"f5b6820c-ab4b-496c-9957-f86753243388","name":"attendees","type":"array","value":"={{ $json.attendees }}"},{"id":"b39a06a5-4fbf-4fdf-9d9a-a07dcb37d157","name":"hangoutLink","type":"string","value":"={{ $json.hangoutLink }}"},{"id":"345f49fc-93bc-48b8-9ced-326139a82119","name":"Title","type":"string","value":"={{ $json.summary }}"}]}},"typeVersion":3.4},{"id":"4f7b157c-f657-48fa-8bb5-a1e074b042eb","name":"Success Response","type":"n8n-nodes-base.set","position":[2200,1400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2c3894da-7bf7-4a35-95c0-d3d9199dd0ad","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"685c67c7-a30b-4bcc-b9ba-827c4b570548","name":"results[0].result","type":"string","value":"={{ $json.status }}"}]}},"typeVersion":3.3},{"id":"b7fe16e3-b625-4cb4-b971-9c26698af89b","name":"Add Friendly Error","type":"n8n-nodes-base.code","position":[1980,1760],"parameters":{"mode":"runOnceForEachItem","jsCode":"function replaceValue(value) {\n  if (error.message.include('no_available_users_found_error')) {\n    return \"This time slot is no longer available.\";\n  }\n  return value;\n}\n\n$input.item.json.message = replaceValue($input.item.json.error.description);\n\nreturn $input.item;"},"typeVersion":2},{"id":"b5bff0df-2bef-4c43-9fcf-91cadc68b7ca","name":"Error Response","type":"n8n-nodes-base.set","position":[2200,1760],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2c3894da-7bf7-4a35-95c0-d3d9199dd0ad","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"93e45166-de94-4fa5-9148-2b8d0e4b960c","name":"results[0].result","type":"string","value":"={{ $json.message || $json.status }}"}]}},"typeVersion":3.3},{"id":"fe62c0bc-2d73-4f14-8e76-02847ef4e14a","name":"Escape Json","type":"n8n-nodes-base.code","position":[1260,1580],"parameters":{"mode":"runOnceForEachItem","jsCode":"const escapeStringForJson = (str) => {\n    return str\n        .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n        .replace(/\"/g, '\\\\\"')    // Escape double quotes\n        .replace(/\\n/g, '\\\\n')   // Escape newlines\n        .replace(/\\r/g, '\\\\r')   // Escape carriage returns\n        .replace(/\\t/g, '\\\\t');  // Escape tabs\n};\n\n// Escape the notes field\n$input.item.json.notes = escapeStringForJson($input.item.json.notes);\n\nreturn $input.item;\n"},"typeVersion":2},{"id":"17927aa4-8f91-4134-b914-1160a724226f","name":"Has all information","type":"n8n-nodes-base.if","position":[940,1800],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"e0af7f69-0c89-4a02-a49f-dd5a90e31dff","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ ($json.email || \"\").isEmail() }}","rightValue":""}]}},"typeVersion":2.2},{"id":"6f0bb9e6-9d82-4cc6-a98f-4d00c47ed910","name":"Respond with Error","type":"n8n-nodes-base.respondToWebhook","position":[1480,1900],"parameters":{"options":{}},"typeVersion":1.1},{"id":"fdedba34-a374-405d-a86e-0b0a1759ede9","name":"Build Error Response Payload","type":"n8n-nodes-base.set","position":[1260,1900],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name and notes to call this tool"}]}},"typeVersion":3.4},{"id":"1e111f9d-bb43-4126-b7a2-3353e7c7c72f","name":"Build Error Response Payload2","type":"n8n-nodes-base.set","position":[1560,2840],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from updateslot tool').item.json.toolCallId || $json.Calls[0].id }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name , previous starttime & endtime and resceduled starttime to call this tool"}]}},"typeVersion":3.4},{"id":"d6cbad26-d974-4a11-b0fd-2a35bb555378","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[260,620],"parameters":{"color":4,"width":190,"height":80,"content":"# Get Slots"},"typeVersion":1},{"id":"bcccc8cb-2e9d-4f8b-9964-e4d656e794ed","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[740,920],"parameters":{"width":230,"height":80,"content":"## Check Availability\n"},"typeVersion":1},{"id":"30b34e37-ee7a-434c-ab4d-445df994459a","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[1320,520],"parameters":{"width":310,"height":80,"content":"## If time available Respond\n"},"typeVersion":1},{"id":"725a9b59-ea66-4326-a410-93a723157ced","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1280,1020],"parameters":{"width":190,"height":80,"content":"## Get All Events\n"},"typeVersion":1},{"id":"1f2bf4a3-8aeb-4a56-8bff-0bb370e12718","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[2140,1020],"parameters":{"width":350,"height":100,"content":"## Get Available Slots\n\nFormat the slots and Enrich the date and timings\n"},"typeVersion":1},{"id":"5909d88f-b9c6-4e62-b1e3-bdc1d05ad7aa","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[3280,1000],"parameters":{"width":230,"height":80,"content":"## Respond to Vapi"},"typeVersion":1},{"id":"f627c5b0-f3b6-4f95-a3a3-2c1b7e2860c7","name":"Sticky Note BookSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[380,1680],"parameters":{"color":5,"width":190,"height":80,"content":"# Book Slot"},"typeVersion":1},{"id":"9c3e8b9f-3fe3-4380-8cbc-413146d752b9","name":"Sticky Note BookSlot Check","type":"n8n-nodes-base.stickyNote","position":[880,1700],"parameters":{"width":230,"height":80,"content":"Checks if required booking info (email, name, etc.) is provided."},"typeVersion":1},{"id":"c723bbd0-5a04-4efb-ba67-59bc722b9d4e","name":"Sticky Note BookSlot Error","type":"n8n-nodes-base.stickyNote","position":[1440,2060],"parameters":{"width":190,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"a843e795-8046-4538-93e0-2de2e688c863","name":"Sticky Note BookSlot GCal","type":"n8n-nodes-base.stickyNote","position":[1660,1740],"parameters":{"width":190,"height":80,"content":"Books the appointment in Google Calendar."},"typeVersion":1},{"id":"a7627281-15fc-438a-b031-b00cbc4b9fa4","name":"Sticky Note BookSlot Error Handle","type":"n8n-nodes-base.stickyNote","position":[1920,1920],"parameters":{"width":230,"height":80,"content":"Handles potential booking errors (e.g., slot taken)."},"typeVersion":1},{"id":"71c0c722-b5df-47d7-97e6-3d23533a4a4e","name":"Sticky Note BookSlot Response","type":"n8n-nodes-base.stickyNote","position":[2420,1740],"parameters":{"width":210,"height":80,"content":"Sends confirmation/error back to Vapi."},"typeVersion":1},{"id":"4e598ebb-cfdb-432f-a01a-bb76d1d20f24","name":"Sticky Note BookSlot Airtable","type":"n8n-nodes-base.stickyNote","position":[3100,1740],"parameters":{"width":230,"height":80,"content":"Logs the confirmed booking details to Airtable."},"typeVersion":1},{"id":"cc085c75-d45f-4453-b78b-1b9b480fb02c","name":"Sticky Note CancelSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[440,3480],"parameters":{"color":3,"width":250,"height":80,"content":"# Cancel Slots"},"typeVersion":1},{"id":"9504b7e8-7964-4a0e-bfa4-32540c1fb895","name":"Sticky Note CancelSlot Check","type":"n8n-nodes-base.stickyNote","position":[960,3780],"parameters":{"width":230,"height":80,"content":"Checks if required info (email, name, start time) is provided."},"typeVersion":1},{"id":"3bb9d976-d922-4016-839c-22e8b1adcf35","name":"Sticky Note CancelSlot Error","type":"n8n-nodes-base.stickyNote","position":[1520,3940],"parameters":{"width":150,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"87442b3a-b8eb-43e6-b15d-0240a58bff79","name":"Sticky Note CancelSlot Search","type":"n8n-nodes-base.stickyNote","position":[1300,3440],"parameters":{"width":190,"height":100,"content":"Finds the appointment record in Airtable by phone number to get event ID."},"typeVersion":1},{"id":"4e0cec59-1acc-4604-80ce-09479c7a6652","name":"Sticky Note CancelSlot GCal Delete","type":"n8n-nodes-base.stickyNote","position":[1720,3720],"parameters":{"width":190,"height":80,"content":"Deletes the event from Google Calendar using event ID."},"typeVersion":1},{"id":"68e00556-93d2-45a8-9fee-deb1477ffff2","name":"Sticky Note CancelSlot Airtable Update","type":"n8n-nodes-base.stickyNote","position":[2060,3400],"parameters":{"width":190,"height":80,"content":"Updates Airtable record status to 'Canceled'."},"typeVersion":1},{"id":"5853b0f6-1e73-435e-aff8-5d9d8de53693","name":"Sticky Note CancelSlot Response","type":"n8n-nodes-base.stickyNote","position":[2380,3740],"parameters":{"width":190,"height":80,"content":"Sends cancellation confirmation/error back to Vapi."},"typeVersion":1},{"id":"660cdb51-84ac-434e-b7d8-f7b17ef7ef5b","name":"Sticky Note UpdateSlot Webhook","type":"n8n-nodes-base.stickyNote","position":[460,2600],"parameters":{"color":6,"width":250,"height":80,"content":"# Update Slots"},"typeVersion":1},{"id":"030e4bce-4b8b-42b7-8cf4-86b3a88f375b","name":"Sticky Note UpdateSlot Check","type":"n8n-nodes-base.stickyNote","position":[1000,2900],"parameters":{"width":230,"height":80,"content":"Checks if required info (email, name, old/new times) is provided."},"typeVersion":1},{"id":"02e9f8e3-7561-4ace-95a2-2b1807940f1a","name":"Sticky Note UpdateSlot Error","type":"n8n-nodes-base.stickyNote","position":[1500,3020],"parameters":{"width":190,"height":80,"content":"If info missing, sends error back."},"typeVersion":1},{"id":"4820cb6c-de15-4e9a-bca7-e3f172af6b80","name":"Sticky Note UpdateSlot Search","type":"n8n-nodes-base.stickyNote","position":[1580,2460],"parameters":{"width":190,"height":80,"content":"Finds original appointment in Airtable by old phone number"},"typeVersion":1},{"id":"5dd3075e-8e0b-4f76-8d21-39aa66d449da","name":"Sticky Note UpdateSlot GCal Update","type":"n8n-nodes-base.stickyNote","position":[1940,2720],"parameters":{"width":190,"height":80,"content":"Updates the event time in Google Calendar."},"typeVersion":1},{"id":"2e08b4f6-f279-4a9e-9bd3-d6a6283b45f4","name":"Sticky Note UpdateSlot Airtable Update","type":"n8n-nodes-base.stickyNote","position":[2240,2320],"parameters":{"width":170,"height":100,"content":"Updates Airtable record with new times & 'Updated' status."},"typeVersion":1},{"id":"d1369c19-401e-4ce2-a21e-0d5ae01af119","name":"Sticky Note UpdateSlot Response","type":"n8n-nodes-base.stickyNote","position":[2720,2460],"parameters":{"width":230,"height":80,"content":"Sends rescheduling confirmation/error back to Vapi."},"typeVersion":1},{"id":"ca064fbe-b175-443f-b8e8-70a2a7551ba9","name":"Sticky Note CallResults Webhook","type":"n8n-nodes-base.stickyNote","position":[440,4160],"parameters":{"color":2,"width":390,"height":120,"content":"# Call Result logs\nReceives call summary and recording details post-call."},"typeVersion":1},{"id":"4941246b-82d1-4f16-b7b8-e1fdb6e7c833","name":"Sticky Note CallResults Airtable","type":"n8n-nodes-base.stickyNote","position":[860,4460],"parameters":{"width":230,"height":80,"content":"Logs call transcript, recording URL, summary, cost, customer number to Airtable."},"typeVersion":1},{"id":"e5622e9e-9b0a-43b2-ab80-e3e33a4b0409","name":"Getslot_tool","type":"n8n-nodes-base.webhook","position":[260,740],"webhookId":"42afdbc1-afd0-4d65-a713-cf7a59062d6c","parameters":{"path":"getslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"e15781cf-5405-4f60-aa6d-ba19d1b7dabc","name":"Check Availability","type":"n8n-nodes-base.googleCalendar","position":[800,740],"parameters":{"options":{},"timeMax":"={{ $json.endtime.toDateTime() || $now.plus(1, 'hour').toISO() }}","timeMin":"={{ $json.starttime.toDateTime() }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"resource":"calendar"},"credentials":{},"typeVersion":1.3},{"id":"1e064283-2964-4eba-a893-e4270157c603","name":"Response","type":"n8n-nodes-base.respondToWebhook","position":[1540,640],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $('Getslot_tool').first().json.body.message.toolCalls[0].id }}\",\n            \"result\":\"available:{{ $json.available }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"498401cb-00e5-4fdd-b6a9-dd3e91376993","name":"Check if time is available or not","type":"n8n-nodes-base.if","position":[1020,740],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4a8741a2-a903-4fb7-b0a3-5c74c7eea6ca","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $json.available }}","rightValue":"="}]}},"typeVersion":2.2},{"id":"96e43c15-a332-4acf-af04-80dd989d5660","name":"Time available (true) & Call_id","type":"n8n-nodes-base.set","position":[1320,640],"parameters":{"options":{},"assignments":{"assignments":[{"id":"f582d965-af15-4ecf-8a8c-d8bf6c0d15c1","name":"body.message.toolCalls[0].id","type":"string","value":"={{ $('Input Arguments').item.json.body.message.toolCalls[0].id }}"},{"id":"834ee925-5c8d-4e46-aeee-f399dc1ff40c","name":"available","type":"boolean","value":"={{ $json.available }}"}]}},"typeVersion":3.4},{"id":"fb7ad8c6-9f78-4518-b955-60f3f7088cb9","name":"Get All Calendar Events","type":"n8n-nodes-base.googleCalendar","position":[1320,840],"parameters":{"options":{"orderBy":"startTime","timeMax":"={{ $now.plus(1, 'week').toISO() }}","timeMin":"={{ $now.toISO() }}","singleEvents":true},"calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"getAll","returnAll":true},"credentials":{},"typeVersion":1,"alwaysOutputData":true},{"id":"390599ee-ddeb-4628-af0b-36fbdd357cee","name":"Extract start, end and name","type":"n8n-nodes-base.set","position":[1540,840],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"1045b97f-c76f-450e-8f57-008602000848","name":"start","type":"string","value":"={{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.start.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"},{"id":"457e3a2b-d33e-4a65-b2da-d19ad9d754ac","name":"end","type":"string","value":"={{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.DATE_HUGE) }}, {{ DateTime.fromISO($json.end.dateTime).toLocaleString(DateTime.TIME_24_WITH_SHORT_OFFSET) }}"},{"id":"b6802452-557e-4568-af14-4574e8ecc013","name":"name","type":"string","value":"={{ $json.summary }}"},{"id":"799b656f-68b6-467c-88a1-217ff7c7801b","name":"sort","type":"string","value":"={{ $json.start.dateTime }}"}]}},"typeVersion":3.4},{"id":"2c9a73da-37b7-4abd-af5e-695036cd2c2b","name":"Convert into Json format for Vapi","type":"n8n-nodes-base.code","position":[3120,840],"parameters":{"jsCode":"// Get the input data for the first item\nconst inputData = $input.first().json;\nconsole.log(\"Input Data:\", inputData); // Log input for debugging\n\n// Access the message string from the correct path within the input structure.\n// The input comes from the \"Build Response Payload\" node, which structures data under 'results'.\n// Use optional chaining (?.) for safety in case the structure is not as expected.\nlet message = inputData.results?.[0]?.result;\n\n// Check if the message was found and is a string\nif (typeof message !== 'string') {\n    console.error(\"Could not find the message string at inputData.results[0].result or it's not a string. Input:\", inputData);\n    // Return an object with an empty message or an error indicator\n    return { message: \"\" }; // Or potentially throw an error: throw new Error(\"Input message not found or not a string\");\n}\n\n// Start cleaning the message string\n\n// 1. Replace the literal string \"\\\\n\" (backslash followed by n) with a space.\n// This handles the newline representation seen in the input screenshot.\nlet cleanedMessage = message.replace(/\\\\n/g, ' ');\n\n// 2. Remove spaces immediately surrounding colons (e.g., \"Times : \" becomes \"Times:\").\ncleanedMessage = cleanedMessage.replace(/\\s*:\\s*/g, ':');\n\n// 3. Replace sequences of multiple whitespace characters (including spaces from replaced \\n)\n// with a single space. Then, trim any leading or trailing whitespace from the result.\ncleanedMessage = cleanedMessage.replace(/\\s+/g, ' ').trim();\n\n// Create the final output JSON object containing the cleaned message.\nconst output = {\n    message: cleanedMessage\n};\n\n// Return the output object. This will be the output of the Code node.\nreturn output;"},"typeVersion":2},{"id":"e00cf72a-af6a-441b-9b76-81bd8096d3df","name":"Response to Vapi","type":"n8n-nodes-base.respondToWebhook","position":[3360,840],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $('Getslot_tool').first().json.body.message.toolCalls[0].id }}\",\n            \"result\":\"The original time is not available, here are available slots:{{ $json.message }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"facf3bf9-e05e-4953-a221-bf7f566a3b0f","name":"bookslots_tool","type":"n8n-nodes-base.webhook","position":[400,1800],"webhookId":"42afdbc1-afd0-4d65-a713-cf7a59062d6c","parameters":{"path":"bookslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"9266904b-300f-4c83-a518-4cd69b13de41","name":"Input Arguments from booking tools","type":"n8n-nodes-base.set","position":[720,1800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"eac930a3-ba65-4b0d-b236-aa167d7edb3f","name":"toolCallId","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"492186b8-e3a3-4ab9-87f4-45d8cbc38c13","name":"timeZone","type":"string","value":"=America/Chicago"},{"id":"12aeec42-9414-4d43-8837-1ff747f49305","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name || \"John Smith\" }}"},{"id":"36673f27-c026-4ad9-81da-ad11e71bbfb6","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"469ddc00-a399-47a5-8c55-97cd3adf4143","name":"language","type":"string","value":"en"},{"id":"b191cd98-f3f7-48b1-a2e0-2c9e248a4983","name":"notes","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.notes || \"\"}}"},{"id":"783cb161-65e4-4829-ac90-5c6c2c55585f","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"bfcdade9-14c8-4867-8a22-3865a2bcc116","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"26ca39ef-48f5-41ed-990e-40c2a26d6132","name":"Tittle","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Title }}"},{"id":"43575f7a-3873-4d74-90c5-4467c7779514","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.3},{"id":"b4bc5cee-d631-4aa8-a3ff-59a0b647d36a","name":"Convert time to CST America / Chicago","type":"n8n-nodes-base.code","position":[1480,1580],"parameters":{"jsCode":"// Get all input items\nconst items = $input.all();\n\n// Loop through each item\nfor (const item of items) {\n  // Get the values from the current item's JSON data\n  const startTimeUTC = item.json.starttime;\n  const endTimeUTC = item.json.endtime;\n  const targetTimeZone = item.json.timeZone; // e.g., \"America/Chicago\"\n\n  // Basic validation: ensure the necessary fields exist\n  if (!startTimeUTC || !endTimeUTC || !targetTimeZone) {\n    console.warn(`Skipping item due to missing time data or timezone. Item JSON: ${JSON.stringify(item.json)}`);\n    item.json.conversionError = \"Missing starttime, endtime, or timeZone\";\n    continue; // Move to the next item\n  }\n\n  try {\n    // --- Start Time Conversion ---\n    // Parse the original UTC ISO string using Luxon (NO $ prefix)\n    const startDt = luxon.DateTime.fromISO(startTimeUTC, { zone: 'utc' });\n\n    // Convert the DateTime object to the target timezone\n    const startDtTargetZone = startDt.setZone(targetTimeZone);\n\n    // Check if the conversion was valid\n    if (!startDtTargetZone.isValid) {\n      throw new Error(`Failed to convert start time. Reason: ${startDtTargetZone.invalidReason || 'Unknown'}`);\n    }\n\n    // Format the result back into an ISO string with the correct offset\n    item.json.starttime = startDtTargetZone.toISO();\n\n    // --- End Time Conversion ---\n    // Parse the original UTC ISO string using Luxon (NO $ prefix)\n    const endDt = luxon.DateTime.fromISO(endTimeUTC, { zone: 'utc' });\n\n    // Convert the DateTime object to the target timezone\n    const endDtTargetZone = endDt.setZone(targetTimeZone);\n\n     // Check if the conversion was valid\n    if (!endDtTargetZone.isValid) {\n      throw new Error(`Failed to convert end time. Reason: ${endDtTargetZone.invalidReason || 'Unknown'}`);\n    }\n\n    // Format the result back into an ISO string with the correct offset\n    item.json.endtime = endDtTargetZone.toISO();\n\n    // Optionally remove the error flag if conversion was successful this time\n    delete item.json.conversionError;\n\n  } catch (error) {\n    console.error(`Error converting time for item: ${JSON.stringify(item.json)}. Error: ${error.message}`);\n    // Add/update the error flag to the item's JSON\n    item.json.conversionError = error.message;\n  }\n}\n// Return the modified array of items\nreturn items;"},"typeVersion":2},{"id":"2c8b2884-14d3-4bd4-92d8-6e402ca3a8de","name":"Create Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1700,1580],"parameters":{"end":"={{ $json.endtime }}","start":"={{ $json.starttime }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"additionalFields":{"allday":"no","summary":"={{ $json.Tittle }}","showMeAs":"opaque","attendees":["={{ $json.email }}"],"description":"={{ $json.notes }}","conferenceDataUi":{"conferenceDataValues":{"conferenceSolution":"hangoutsMeet"}}}},"credentials":{},"typeVersion":1.3},{"id":"b8890ab2-9850-4608-996d-45c8a6d3a52e","name":"Respond to Vapi","type":"n8n-nodes-base.respondToWebhook","onError":"continueRegularOutput","position":[2480,1580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"available:{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1,"alwaysOutputData":true},{"id":"77f75f42-46bb-47f5-8a43-55543ae46f10","name":"If the booking is confirmed then true","type":"n8n-nodes-base.if","position":[2700,1580],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"932dd430-309b-4d3b-8bf6-768f84fd2dd2","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.results[0].result }}","rightValue":"=confirmed"}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"230ddb29-67f0-4486-a6f3-f4dd3dbbee42","name":"Information to be Saved in Airtable","type":"n8n-nodes-base.set","position":[2940,1560],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b103265d-86da-4256-994d-85a78f33f933","name":"startTime","type":"string","value":"={{ $('Booking Payload').item.json.startTime }}"},{"id":"a8e6e9c5-6ebb-48d8-951f-b007bed2421d","name":"endTime","type":"string","value":"={{ $('Booking Payload').item.json.endTime }}"},{"id":"d4bcb1d1-043a-4205-8488-0a67b4e7b582","name":"status","type":"string","value":"={{ $('Booking Payload').item.json.status }}"},{"id":"92ac8c99-ad94-4b3c-9c5e-ba032dac2255","name":"description","type":"string","value":"={{ $('Booking Payload').item.json.description }}"},{"id":"98c5653d-1e0e-4a6a-8630-17802d437593","name":"attendees[0].email","type":"string","value":"={{ $('Booking Payload').item.json.attendees[0].email }}"},{"id":"f94bdfc1-dc74-4675-ad29-19244fb21ebe","name":"attendees[0].responseStatus","type":"string","value":"={{ $('Booking Payload').item.json.attendees[0].responseStatus }}"},{"id":"12bd5ed5-4934-4c19-a9b9-54fe989eaa4f","name":"hangoutLink","type":"string","value":"={{ $('Booking Payload').item.json.hangoutLink }}"},{"id":"5b1f9356-7d62-4999-ae4e-86f3f20d72bf","name":"attendee.name","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"6e93805e-8754-4f92-870f-7b46525f3eb3","name":"call.id","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.call.id }}"},{"id":"f174e2be-3230-4fc9-970b-971aff6e9b8e","name":"assistant.name","type":"string","value":"={{ $('bookslots_tool').item.json.body.message.assistant.name }}"},{"id":"a4bc9d70-7d51-487f-b622-433e767ef71f","name":"event.id","type":"string","value":"={{ $('Create Event').item.json.id }}"},{"id":"9259b1d3-3658-4ab5-b434-364e6a84d145","name":"Title","type":"string","value":"={{ $('Booking Payload').item.json.Title }}"},{"id":"2102a7be-5d74-458f-bafd-21651e24adb1","name":"customer_number","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.customer_number}}"}]}},"typeVersion":3.4},{"id":"f6c7774d-a8c7-466a-ba77-401194fe6fb4","name":"Logs the confirmed booking details","type":"n8n-nodes-base.airtable","position":[3160,1560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"Name":"={{ $json.attendee.name }}","Email":"={{ $json.attendees[0].email }}","endtime":"={{ $json.endTime }}","eventId":"={{ $json.event.id }}","meetlink":"={{ $json.hangoutLink }}","starttime":"={{ $json.startTime }}","Voice Agent":"={{ [$json.assistant.name] }}","Phone Number":"={{ $json.customer_number }}","Booking Status":"={{ $json.status }}","CallRecordingId":"={{ [$json.call.id] }}","meetdescription":"={{ $json.Title }} {{ $json.description }}"},"schema":[{"id":"Email","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Email"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{"typecast":true},"operation":"create"},"credentials":{},"typeVersion":2.1},{"id":"154bee14-9281-4b92-8204-57c5436785ba","name":"Updateslots_tool","type":"n8n-nodes-base.webhook","position":[460,2720],"webhookId":"66b278fe-97d1-4413-b6dd-4288d8ec66b2","parameters":{"path":"updateslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"891fb4ec-3a82-4433-bebf-3f0616027e3d","name":"Input Arguments from updateslot tool","type":"n8n-nodes-base.set","position":[840,2720],"parameters":{"options":{},"assignments":{"assignments":[{"id":"6f6388ab-a233-4643-9b28-917ad6bdfe22","name":"Calls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"40888d2c-b99d-401d-a6b9-944ba41543c6","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"17be6cf6-8c48-4a4e-a0e8-b5b714f94242","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"d06fd547-39c1-457b-8422-393f140aead6","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"c224df67-ec82-40f3-9af2-3472731a57fa","name":"endtime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.endtime }}"},{"id":"b2fb0887-5545-409c-bba8-fae76a71f660","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"19efa4c6-25e0-4fe8-a00e-0b37f16b6de0","name":"Rescheduled_starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Rescheduled_starttime }}"},{"id":"ad47dfdb-66fa-478d-899f-1d9d202aac6f","name":"Rescheduled_endttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Rescheduled_endttime }}"},{"id":"6d1bf6c0-a4b4-41d4-826e-e7c73f920905","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"617a7742-299a-4c91-be82-cba598d1bb82","name":"Checks if required info is provided.","type":"n8n-nodes-base.if","position":[1060,2720],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"87304425-5f17-4637-8aa3-cd84b2f8d856","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.name }}","rightValue":""},{"id":"fdc6ffb0-f234-4869-8f5e-482c394ab860","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.email }}","rightValue":""},{"id":"7950d7bc-7416-48b6-8ec5-a635a9161013","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.Rescheduled_starttime }}","rightValue":"={{ $json.Rescheduledtime }}"},{"id":"aa54ee15-1273-48b0-863f-939597af04e6","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.Rescheduled_endttime }}","rightValue":""},{"id":"8ceefa9d-360c-48b6-8faf-e156459f2c07","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.starttime }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"dded1cfa-ce89-481f-967b-6843854a32bd","name":"Finds original appointment","type":"n8n-nodes-base.airtable","maxTries":2,"position":[1600,2560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"options":{"fields":["Email","Name","starttime","eventId"]},"operation":"search","filterByFormula":"={Phone Number} = (\"{{ $json.customer_number }}\")"},"credentials":{},"retryOnFail":false,"typeVersion":2.1,"alwaysOutputData":false},{"id":"a3fd9971-20bb-414a-b06c-1af4da053241","name":"Response with Error","type":"n8n-nodes-base.respondToWebhook","position":[1780,2840],"parameters":{"options":{}},"typeVersion":1.1},{"id":"0731f0ae-fbdb-4149-890a-0a44c95b2691","name":"Update Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1980,2560],"parameters":{"eventId":"={{ $json.eventId }}","calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"update","updateFields":{"end":"={{ $('Checks if required info is provided.').item.json.Rescheduled_endttime }}","start":"={{ $('Checks if required info is provided.').item.json.Rescheduled_starttime }}","allday":"no"}},"credentials":{},"typeVersion":1.3},{"id":"1e7af704-6c5d-4e6b-a606-2c5c7ef64b10","name":"Updates Airtable record","type":"n8n-nodes-base.airtable","position":[2280,2440],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"endtime":"={{ $json.end.dateTime }}","eventId":"={{ $('Finds original appointment').item.json.eventId }}","starttime":"={{ $json.start.dateTime }}","Booking Status":"Updated/Rescheduled"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"Email","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["eventId"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update"},"credentials":{},"typeVersion":2.1},{"id":"5a74d949-f08e-422c-afde-e41690a8512b","name":"Response & call_id","type":"n8n-nodes-base.set","position":[2620,2580],"parameters":{"options":{},"assignments":{"assignments":[{"id":"074d1ef3-e96b-4149-a12c-b8aa71c9c117","name":"results[0].toolCallId","type":"string","value":"={{ $('Updateslots_tool').item.json.body.message.toolCalls[0].id }}"},{"id":"098bb88d-9b17-4aeb-850c-819406aa0f3b","name":"results[0].result","type":"string","value":"={{ $json.error || $json.fields['Booking Status']  }}"}]}},"typeVersion":3.4},{"id":"bb7dc099-c4ac-48d4-bf8c-50f4f8858dd4","name":"Respond to Vapi about Updating slots","type":"n8n-nodes-base.respondToWebhook","position":[2820,2580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"2154c9c8-acd3-4144-9fa6-f6f7de7bbf48","name":"CancelSlots_tool","type":"n8n-nodes-base.webhook","position":[440,3620],"webhookId":"00fedd5a-c03d-4302-b8e0-22c79f26ed05","parameters":{"path":"cancelslots","options":{},"httpMethod":"POST","responseMode":"responseNode"},"typeVersion":2},{"id":"aeabd266-4b0e-436f-9c8c-607fb7b6734a","name":"Input Arguments from cancelslot tool","type":"n8n-nodes-base.set","position":[800,3620],"parameters":{"options":{},"assignments":{"assignments":[{"id":"6f6388ab-a233-4643-9b28-917ad6bdfe22","name":"Calls[0].id","type":"string","value":"={{ $json.body.message.toolCalls[0].id }}"},{"id":"40888d2c-b99d-401d-a6b9-944ba41543c6","name":"name","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.name }}"},{"id":"17be6cf6-8c48-4a4e-a0e8-b5b714f94242","name":"email","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.email }}"},{"id":"d06fd547-39c1-457b-8422-393f140aead6","name":"starttime","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.starttime }}"},{"id":"0a0243b2-afc4-44f1-92cd-81572df79cc5","name":"Cancelnotes","type":"string","value":"={{ $json.body.message.toolCalls[0].function.arguments.Cancelnotes }}"},{"id":"b2fb0887-5545-409c-bba8-fae76a71f660","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"8d528786-75d7-466e-8e8f-2013e4638bc2","name":"customer_number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"b702973e-15f0-4bbe-98ac-d4af7a57cff1","name":"Checks if required info is provided for cancelation","type":"n8n-nodes-base.if","position":[1020,3620],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"87304425-5f17-4637-8aa3-cd84b2f8d856","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.name }}","rightValue":""},{"id":"fdc6ffb0-f234-4869-8f5e-482c394ab860","operator":{"type":"string","operation":"exists","singleValue":true},"leftValue":"={{ $json.email }}","rightValue":""},{"id":"c0b869e4-9490-4c01-b138-835bb34eb1ba","operator":{"type":"dateTime","operation":"exists","singleValue":true},"leftValue":"={{ $json.starttime }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"c5e49060-7b76-4622-bc23-b389f1665215","name":"Finds the appointment record","type":"n8n-nodes-base.airtable","position":[1300,3560],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"options":{"fields":["Email","Name","starttime","eventId"]},"operation":"search","filterByFormula":"={Phone Number} = (\"{{ $json.customer_number }}\")"},"credentials":{},"typeVersion":2.1,"alwaysOutputData":true},{"id":"dd83c017-6f5b-49b4-83f9-ec2f33ca5ed0","name":"Build Error Response","type":"n8n-nodes-base.set","position":[1300,3780],"parameters":{"options":{},"assignments":{"assignments":[{"id":"5cb05b10-e916-459e-84a2-9c314a859a07","name":"results[0].toolCallId","type":"string","value":"={{ $('Input Arguments from booking tools').item.json.toolCallId }}"},{"id":"552246f9-7afd-404e-9fb3-cb38c7447359","name":"results[0].result","type":"string","value":"=You must provide an email, name and starttime to call this tool"}]}},"typeVersion":3.4},{"id":"ca74e845-ee23-4f8a-ba8e-789186fe7add","name":"Respond with Error to Vapi","type":"n8n-nodes-base.respondToWebhook","position":[1500,3780],"parameters":{"options":{}},"typeVersion":1.1},{"id":"ad3c2ad0-ba5e-48a6-865f-a8da63173562","name":"Delete Event","type":"n8n-nodes-base.googleCalendar","onError":"continueErrorOutput","position":[1720,3560],"parameters":{"eventId":"={{ $json.eventId }}","options":{"sendUpdates":"all"},"calendar":{"__rl":true,"mode":"list","value":"pratik@customaistudio.io","cachedResultName":"pratik@customaistudio.io"},"operation":"delete"},"credentials":{},"typeVersion":1.3},{"id":"177a1297-8e96-4d04-a0ff-e16aab71d5b9","name":"Update Airtable record","type":"n8n-nodes-base.airtable","position":[1940,3440],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tblF8LF9lmkHMbk7v","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tblF8LF9lmkHMbk7v","cachedResultName":"Appointments"},"columns":{"value":{"eventId":"={{ $('Finds the appointment record').item.json.eventId }}","Booking Status":"Canceled"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"Email","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Email","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Phone Number","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Phone Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Name","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Booking Status","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Booking Status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"CallRecordingId","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"CallRecordingId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"starttime","type":"dateTime","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"starttime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endtime","type":"dateTime","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"endtime","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetlink","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetlink","defaultMatch":false,"canBeUsedToMatch":true},{"id":"meetdescription","type":"string","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"meetdescription","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Voice Agent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"eventId","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"eventId","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["eventId"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update"},"credentials":{},"typeVersion":2.1},{"id":"4d0c155c-68ad-4f70-b9c6-0dbd4db70fd1","name":"Call_id & Response","type":"n8n-nodes-base.set","position":[2160,3580],"parameters":{"options":{},"assignments":{"assignments":[{"id":"074d1ef3-e96b-4149-a12c-b8aa71c9c117","name":"results[0].toolCallId","type":"string","value":"={{ $('CancelSlots_tool').item.json.body.message.toolCalls[0].id }}"},{"id":"098bb88d-9b17-4aeb-850c-819406aa0f3b","name":"results[0].result","type":"string","value":"={{ $json.error || $json.fields['Booking Status']  }}"}]}},"typeVersion":3.4},{"id":"41ff13bf-0793-4082-8be6-51f0617ab0f8","name":"Respond to Vapi about cancelation","type":"n8n-nodes-base.respondToWebhook","position":[2400,3580],"parameters":{"options":{},"respondWith":"json","responseBody":"={\n    \"results\":[\n        {\n            \"toolCallId\":\"{{ $json.results[0].toolCallId }}\",\n            \"result\":\"{{ $json.results[0].result }}\"\n        }\n    ]\n}"},"typeVersion":1.1},{"id":"599592b1-214c-4e99-84f6-e244e690ed79","name":"call_results","type":"n8n-nodes-base.webhook","position":[440,4300],"webhookId":"4a6205cd-4277-4686-8008-540b802b99fe","parameters":{"path":"callresults","options":{},"httpMethod":"POST"},"typeVersion":2},{"id":"baf3ce79-f302-42ad-bb7e-49f2d9197eae","name":"All Input Arguments","type":"n8n-nodes-base.set","position":[720,4300],"parameters":{"options":{"ignoreConversionErrors":true},"assignments":{"assignments":[{"id":"fd00208a-e833-4834-8c37-0034c44fb47d","name":"transcript","type":"string","value":"={{ $json.body.message.artifact.transcript }}"},{"id":"b72ffa4d-aef3-4d7c-8b81-9238a3c5890b","name":"recordingUrl","type":"string","value":"={{ $json.body.message.artifact.recordingUrl }}"},{"id":"e45d90de-0103-46ba-9fcb-f4c969816da0","name":"call.summary","type":"string","value":"={{ $json.body.message.analysis.summary }}"},{"id":"b0a5557f-483f-47c9-955a-c12ce84f270b","name":"cost","type":"number","value":"={{ $json.body.message.cost }}"},{"id":"2bfcfe4f-4eaf-4274-b3f2-cdaea8c2cc46","name":"call.id","type":"string","value":"={{ $json.body.message.call.id }}"},{"id":"2b7b1638-0d0e-4c48-9989-287fd4e0babd","name":"call.orgId","type":"string","value":"={{ $json.body.message.call.orgId }}"},{"id":"adf4d062-bbfd-4f97-bda4-bdfec1e40ee4","name":"assistant.name","type":"string","value":"={{ $json.body.message.assistant.name }}"},{"id":"3c2af504-d320-45f0-9008-79b3bc1ff897","name":"startedAt","type":"string","value":"={{ $json.body.message.startedAt }}"},{"id":"0486dbfa-ca10-45b5-a79a-3ce1064f13fa","name":"endedAt","type":"string","value":"={{ $json.body.message.endedAt }}"},{"id":"bf97b5eb-5baa-4a87-b34e-2f64c97c0d42","name":"assistant.id","type":"string","value":"={{ $json.body.message.assistant.id }}"},{"id":"58ee9b29-7aa1-4a15-bf83-606287a964a6","name":"assistant.model","type":"string","value":"={{ $json.body.message.assistant.model.model }}"},{"id":"36e2bbef-e12d-4fc4-a0af-bb65aa446023","name":"body.message.assistant","type":"object","value":"={{ $json.body.message.assistant }}"},{"id":"dfa93dbb-67dc-417b-874a-32fbd55d92b0","name":"assistantId","type":"string","value":"={{ $json.body.message.call.assistantId }}"},{"id":"4bc2b480-92a1-470e-bdf0-d6609f346ed2","name":"body.message.assistant.model.emotionRecognitionEnabled","type":"boolean","value":"={{ $json.body.message.assistant.model.emotionRecognitionEnabled }}"},{"id":"acb64bba-e295-4dd0-9ab3-b4166ef5d0ad","name":"customer.number","type":"string","value":"={{ $json.body.message.call.customer.number }}"}]}},"typeVersion":3.4},{"id":"f3394750-7438-47e9-8aa3-996accfa9bac","name":"Save all information","type":"n8n-nodes-base.airtable","position":[900,4300],"parameters":{"base":{"__rl":true,"mode":"list","value":"appnj853UnMRnJ8D3","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3","cachedResultName":"Voice Receptionist Agent"},"table":{"__rl":true,"mode":"list","value":"tbl1b6vMhq9IT9JEZ","cachedResultUrl":"https://airtable.com/appnj853UnMRnJ8D3/tbl1b6vMhq9IT9JEZ","cachedResultName":"Call Recording"},"columns":{"value":{"Cost":"={{ $json.cost }}","endedAt":"={{ $json.endedAt }}","startedAt":"={{ $json.startedAt }}","transcript":"={{ $json.transcript }}","callsummary":"={{ $json.call.summary }}","customer_Number":"={{ $json.customer.number }}","callrecording_id":"={{ $json.call.id }}","Call recording Url":"={{ $json.recordingUrl }}"},"schema":[{"id":"id","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"id","defaultMatch":true},{"id":"callrecording_id","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"callrecording_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Cost","type":"number","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Call recording Url","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"Call recording Url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"transcript","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"transcript","defaultMatch":false,"canBeUsedToMatch":true},{"id":"customer_Number","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"customer_Number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointments","type":"array","display":true,"removed":true,"readOnly":false,"required":false,"displayName":"Appointments","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Appointment time (from Appointments)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Appointment time (from Appointments)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Voice Agent (from Appointments)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"Voice Agent (from Appointments)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"startedAt","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"startedAt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"endedAt","type":"dateTime","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"endedAt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"call_Length (in secs)","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"call_Length (in secs)","defaultMatch":false,"canBeUsedToMatch":true},{"id":"callsummary","type":"string","display":true,"removed":false,"readOnly":false,"required":false,"displayName":"callsummary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["callrecording_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{"typecast":true},"operation":"upsert"},"credentials":{},"typeVersion":2.1},{"id":"5671dcff-8894-42a8-af77-df01d0b6c190","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1800,1980],"parameters":{"color":4,"width":1680,"height":2700,"content":"# Vapi System Prompt\n\n### First Message: \nHi, this is Ellie with Harrison Climate Solutions how can I help you?\n\n----**END**----\n\n### System Prompt:\n\n[Identity]  \nYou are Ellie, the friendly and knowledgeable voice receptionist for Harrison Climate Solutions, an HVAC service company based in San Antonio, Texas.\n- Current Date and Time: {{\"now\" | date: \"%b %d, %Y, %I:%M %p\", \"America/Chicago\"}}\n\n[Style]  \n- Use a friendly, conversational tone with a hint of Texan warmth.\n- Be warm, approachable, and slightly humorous to create a comfortable and friendly experience for callers.\n- Use casual, conversational language, incorporating friendly fillers like “Umm...,” “Well...,” or “I mean.”\n- Keep responses brief and engaging, mirroring a natural conversation style to suit the voice format.\n\n[Response Guideline]  \n- Use a friendly and conversational tone, never saying \"Asterisk\" or similar technical terms.\n- Limit responses to essential information only, breaking up information into bite-sized pieces when possible.\n- Remember this is a telephone conversation. Give the caller opportunities to talk.\n- Politely redirect any off-topic questions back to Harrison Climate Solutions' services or appointment scheduling.\n- If they hadn't requested an endtime always assume for 30 mins meeting.\n- When asking for EMAIL always say: \" Can you spell your email please ? \".\n\n[Reminder]  \n- Use your knowledge base to access more information about the business.\n- Current Date and Time: {{\"now\" | date: \"%b %d, %Y, %I:%M %p\", \"America/Chicago\"}}\n- Do not repeat the caller.\n- Do not Book Calls on Saturday and Sunday and on Holidays (Always getslots)\n- Mention that Harrison Climate Solutions operates Monday through Friday, 8 a.m. to 5 p.m.\n- ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. \n\n- When people ask about your phone number, your phone number is 4158923245\n **Guideline**\nWhen speaking the phone number, transform the format as follows:\n- Input formats like 4158923245, (415) 892-3245, or 415-892-3245\n- Should be pronounced as: \"four one five - eight nine two - three two four five\"\n- Important: Don't omit the space around the dash when speaking\n\nAlways ask to spell the email out. \n**How to spell out**\nThe possible email format is name@company.com\nto spell out an email address is N - A - M - E - @company.com,\nYOU MUST read them out with regular words like 'company' or 'blue'.\nFor names, you must read them out letter by letter, for example, 'P - R - A - T - I - K'.\n@ is pronounced by \"at\" or \"at direct\".\n\n- State Numbers, Times & Dates Slowly\nFor 1:00 PM, say “One PM.”\nFor 3:30 PM, say “Three thirty PM.”\nFor 8:45 AM, say “Eight forty-five AM.”\nNever say “O’Clock.” Instead just say O-Clock never O'clock, This is non-negotiable—always say “AM” or “PM.\n\n[Tool Usage Guidelines]  \n\n1. **Booking Appointments (BookSlot Tool)**  \n   - **Purpose**: Use the `BookSlot` function to finalize an appointment when all required details (name, email, start time, and notes) are gathered.\n   - **Parameters**: Ensure the following parameters are complete before calling:\n     - `name`: The attendee's name (never make up or use a placeholder).\n     - `email`: The attendee's email (never make up or use a placeholder).\n     - `start`: Appointment start time in ISO 8601 format (e.g., `\"2023-04-25T15:00:00Z\"`) in America/Chicago timezone.\n     - `notes`: A brief description (2-3 sentences) summarizing what the customer is looking for and why they need the appointment.\n \n2. **Finding Available Slots (GetSlots Tool)**  \n   - **Purpose**: Use `GetSlots` to check available time slots for an appointment when date parameters (start and end time in ISO format) are known.\n   - **Parameters**:\n     - `startTime`: Start of the search window.\n     - `endTime`: End of the search window.\n   - **Directive**: Immediately call `GetSlots` without waiting for any additional user response if you have all required information for `startTime` and `endTime`. Do not pause or expect further input before calling.\n\n3. **Canceling Appointments (CancelSlots Tool)**  \n   - **Purpose**: Use the `CancelSlots` function to cancel an appointment when all required details (name, email, start time) are gathered.\n   - **Parameters**: Ensure the following parameters are complete before calling:\n     - `name`: The attendee's name (never make up or use a placeholder).\n     - `email`: The attendee's email (never make up or use a placeholder).\n     - `start`: Appointment start time in ISO 8601 format (e.g., `\"2023-04-25T15:00:00Z\"`)  in America/Chicago timezone.\n     - `Cancelnotes`: A brief description (2-3 sentences) summarizing why the customer want to cancel the appointment.\n\n4. **Transferring Calls (TransferCall Tool)**\n**Purpose**: Use the `TransferCall` function to connect the caller to Sam’s forwarding number when absolutely necessary.\n   - **When to Use**: \n     - If the caller says the secret phrase \"Hot Brisket.\"\n     - If you determine the situation is a genuine emergency and requires immediate attention.\n   - **Directive**: Use the `TransferCall` tool immediately when one of the above conditions is met, forwarding the caller to Sam’s specified phone number. Do not attempt to handle emergencies yourself, and do not wait for caller feedback before initiating the transfer. Transfer the call to Sam.\n\n[Task]\n1. **Service Questions**\n   - If the caller has questions about services, provide a concise description of the relevant services based on company offerings.\n   - Mention popular seasonal promotions as relevant (e.g., furnace tune-ups in winter, AC installation deals in summer).\n   - For questions about pricing, explain that Harrison Climate Solutions offers free estimates and stress the transparency of pricing with no hidden fees.\n\n2. **Appointment Scheduling**\n   - Do not try to schedule an appointment for a time in the past. Give a friendly joke about scheduling in the past if they try.\n   - If the caller is interested in scheduling an appointment, **follow these steps**:\n      1. Gather attendee’s email, ask them to spell their email: \" Can you spell your email \" eg: \" P-R-A-T-I-K@gmail.com \", name , preferred time, and reason for the appointment. ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. \n      2. If you have both `startTime` and `endTime`, **immediately call `GetSlots` to check for availability**. Do not wait for caller feedback after confirming you’ll check.\n      3. Only suggest available slots based on confirmed results from `GetSlots`. Never make up availability if none is returned.\n      4. If `GetSlots` returns more than three options, offer just two to three choices to help the caller decide.\n      5. If no availability is found, inform the caller courteously that slots are fully booked and suggest calling back later.\n   - Once a suitable time is identified, use the `BookSlot` tool to schedule the appointment, and confirm the details with the caller. **Only use this tool to book an appointment. Never make up an appointment booking. Do not wait for caller feedback before calling this tool if you have everything you need.**\n   - Mention that Harrison Climate Solutions operates Monday through Friday, 8 a.m. to 5 p.m. If emergency then only 24-hour, 7-day-a-week if needed in America/Chicago time zone.\n\n3. ** Update Appointment** \n- if the caller is interested in Rescheduling/Updating their booking **follow the steps**:\n   1. Gather attendee's name and ask them to spell their email : \" Can you spell your email \", Previous booking timings like starttime and rescheduling time for rescheduling. (ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. )\n   2. If you have 'starttime' and email, **immediately call 'GetSlots' to check if time is not available . Do not wait for caller feedback after confirming you’ll check. \n  3. if time is not available, then Call the 'UpdateSlots' tool for rescheduling.\n  4. If time is available, inform the caller that there is no appointment booked at that time.\n\n4. **Cancel Appointment **\n  - if the caller is interested in canceling a booking, **follow the steps**:\n    1. Gather attendee's name and ask them to spell their email : \" Can you spell your email \", timings and if possible reason for cancelation. ( ONLY MOVE FORWARD when you have correct NAME, EMAIL and TIMMINGS. )\n    2. If you have 'starttime' and email, **immediately call 'GetSlots' to check if time is not available . Do not wait for caller feedback after confirming you’ll check. \n    3. if time is not available, then insists caller to 'Update appointment' first and if he don't want to update appointment then use the 'CancelSlots' tool to cancel the appointment. \n    4. If time is available, inform the caller that there is no appointment booked at that time.\n\n---**END**---"},"typeVersion":1},{"id":"44596616-27ba-47c0-8a6d-cf50f86a136e","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[280,900],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Getslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"226635e5-05cf-4da6-bbd5-304e458a7112","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[400,1960],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Bookslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"dd2caca4-8669-447f-85ee-b0d829e0e8c4","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[460,2880],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Updateslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"be40ca37-c272-4170-a6b1-cf17a28c37ba","name":"Sticky Note18","type":"n8n-nodes-base.stickyNote","position":[440,3780],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `Cancelslot` tool and Webhook in Vapi**\n"},"typeVersion":1},{"id":"98af9e21-fb6e-41ef-a15e-f0b914e1dc8d","name":"Sticky Note19","type":"n8n-nodes-base.stickyNote","position":[440,4440],"parameters":{"color":7,"width":191,"height":80,"content":"**☝️ Set up `call_results` as a Server Webhook in Vapi**\n"},"typeVersion":1},{"id":"ab8f9a65-74b1-42ce-ba65-8f0e0e390839","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[-1800,340],"parameters":{"color":7,"width":1460,"height":1540,"content":"## Voice Receptionist for Appointment Management (tools)\n\n## Introduction\n### What This Template Does:\n- This n8n workflow template automates appointment management using a voice AI receptionist powered by Vapi. It integrates Vapi with Google Calendar for real-time scheduling and Airtable for logging and data management. Agent checks availability, books new appointments, reschedules existing ones, or cancels appointments directly within Google Calendar.\n\n### Problem It Solves:\n- Managing appointment scheduling manually can be time-consuming, and limited by business hours. This template solves these issues by providing an automated, 24/7 (within configured business rules) voice-based scheduling system. It frees up human staff from routine scheduling tasks, reduces booking errors, ensures appointments are logged consistently, and enhances the customer experience by offering immediate scheduling capabilities over the phone. It also captures valuable call data like recordings, summaries, and costs for analysis.\n\n## Setup Instructions\n\n### Prerequisites:\n- An active n8n instance.\n- A Vapi account for the voice agent.\n- A Google account with access to Google Calendar.\n- An Airtable account.\n- API Keys/Credentials for Google Calendar and Airtable configured in your n8n instance.\n\n## Step-by-Step Setup:\n### 1. Copy Airtable Base:\n- Duplicate the provided Airtable base structure to your own Airtable account using this link: https://airtable.com/appxDqRoEgG5sF2gu/shrnZU0D29TPMCjpt\n- Note: The n8n workflow is configured to work with the specific tables and fields in this base (\"Appointments\" and \"Call Recording\" tables).\n\n### 2. Import n8n Workflow:\n- Import the provided n8n workflow JSON into your n8n instance.\n\n### 3. Configure n8n Credentials:\n- Locate the Google Calendar nodes within the workflow (e.g., \"Check Availability\", \"Get All Calendar Events\", \"Create Event\", \"Update Event\", \"Delete Event\"). Ensure they are configured to use your Google Calendar credentials in n8n. Select the correct calendar to manage.\n- Locate the Airtable nodes (e.g., \"Logs the confirmed booking details\", \"Finds original appointment\", \"Updates Airtable record\", \"Save all information\"). Ensure they are configured with your Airtable credentials and point to the correct Base and Tables you created in Step 1.\n\n### 4. Activate the n8n Workflow:\n- Save and activate the n8n workflow. This generates the live Webhook URLs needed for Vapi.\n\n### 5. Configure Vapi Assistant:\n- **System Prompt:** Copy the system prompt provided in the large sticky note within the n8n workflow. Adapt it as needed (e.g., business name, hours) and paste it into your Vapi Assistant's System Prompt configuration. This prompt instructs the AI on its role, rules, and how/when to use the tools.\n\n- **Tools Setup:** In your Vapi Assistant configuration, define the following 4 tools:\n  - Getslots Tool:\n    - Purpose: To check calendar availability.\n    - Webhook URL: Copy the Production URL from the \"Getslot_tool\" Webhook node in your active n8n workflow (path: /getslots) and paste it here.\n  - Bookslots Tool:\n    - Purpose: To create a new calendar event.\n    - Webhook URL: Copy the Production URL from the \"bookslots_tool\" Webhook node in your active n8n workflow (path: /bookslots) and paste it here.\n  - Updateslots Tool:\n    - Purpose: To modify an existing calendar event.\n    - Webhook URL: Copy the Production URL from the \"Updateslots_tool\" Webhook node in your active n8n workflow (path: /updateslots) and paste it here.\n  - Cancelslots Tool:\n    - Purpose: To delete a calendar event.\n    - Webhook URL: Copy the Production URL from the \"CancelSlots_tool\" Webhook node in your active n8n workflow (path: /cancelslots) and paste it here.\n- **Server Webhook (End of Call Report):**\n  - In Vapi's server configuration section (often under webhooks or reporting), find the setting for the end-of-call-report or similar event.\n  - Copy the Production URL from the \"call_results\" Webhook node in your active n8n workflow (path: /callresults).\n  - Paste this URL into the Vapi configuration for the end-of-call server webhook. This allows n8n to receive and log call summaries, recordings, etc., after the call ends.\n\n## Video Walkthrough (coming soon)\n### [🎥 Watch set up video (~2min)](https://www.loom.com/share/d379895004374ddc85dc9171ca37c139?sid=0996f0d2-aff2-45a7-aae9-c62df4fb0799)\n"},"typeVersion":1},{"id":"8d984e05-5bca-4c70-beee-16f7cd70594e","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[40,300],"parameters":{"color":7,"width":3700,"height":4400,"content":"# Workflow"},"typeVersion":1}],"connections":{"Sort":{"main":[[{"node":"Format response","type":"main","index":0}]]},"Enrich Date":{"main":[[{"node":"Build Response Payload","type":"main","index":0}]]},"Escape Json":{"main":[[{"node":"Convert time to CST America / Chicago","type":"main","index":0}]]},"Create Event":{"main":[[{"node":"Booking Payload","type":"main","index":0}],[{"node":"Add Friendly Error","type":"main","index":0}]]},"Delete Event":{"main":[[{"node":"Update Airtable record","type":"main","index":0}],[{"node":"Call_id & Response","type":"main","index":0}]]},"Getslot_tool":{"main":[[{"node":"Input Arguments","type":"main","index":0}]]},"Update Event":{"main":[[{"node":"Updates Airtable record","type":"main","index":0}],[{"node":"Response & call_id","type":"main","index":0}]]},"call_results":{"main":[[{"node":"All Input Arguments","type":"main","index":0}]]},"Flatten Slots":{"main":[[{"node":"Enrich Date","type":"main","index":0}]]},"Error Response":{"main":[[{"node":"Respond to Vapi","type":"main","index":0}]]},"bookslots_tool":{"main":[[{"node":"Input Arguments from booking tools","type":"main","index":0}]]},"Booking Payload":{"main":[[{"node":"Success Response","type":"main","index":0}]]},"Format response":{"main":[[{"node":"Available Start Times & Ranges","type":"main","index":0}]]},"Input Arguments":{"main":[[{"node":"Check Availability","type":"main","index":0}]]},"Respond to Vapi":{"main":[[{"node":"If the booking is confirmed then true","type":"main","index":0}]]},"CancelSlots_tool":{"main":[[{"node":"Input Arguments from cancelslot tool","type":"main","index":0}]]},"Success Response":{"main":[[{"node":"Respond to Vapi","type":"main","index":0}]]},"Updateslots_tool":{"main":[[{"node":"Input Arguments from updateslot tool","type":"main","index":0}]]},"Add Friendly Error":{"main":[[{"node":"Error Response","type":"main","index":0}]]},"Call_id & Response":{"main":[[{"node":"Respond to Vapi about cancelation","type":"main","index":0}]]},"Check Availability":{"main":[[{"node":"Check if time is available or not","type":"main","index":0}]]},"Response & call_id":{"main":[[{"node":"Respond to Vapi about Updating slots","type":"main","index":0}]]},"All Input Arguments":{"main":[[{"node":"Save all information","type":"main","index":0}]]},"Has all information":{"main":[[{"node":"Escape Json","type":"main","index":0}],[{"node":"Build Error Response Payload","type":"main","index":0}]]},"Build Error Response":{"main":[[{"node":"Respond with Error to Vapi","type":"main","index":0}]]},"Build Response Payload":{"main":[[{"node":"Convert into Json format for Vapi","type":"main","index":0}]]},"Update Airtable record":{"main":[[{"node":"Call_id & Response","type":"main","index":0}]]},"Get All Calendar Events":{"main":[[{"node":"Extract start, end and name","type":"main","index":0}]]},"Updates Airtable record":{"main":[[{"node":"Response & call_id","type":"main","index":0}]]},"Finds original appointment":{"main":[[{"node":"Update Event","type":"main","index":0}]]},"Extract start, end and name":{"main":[[{"node":"Sort","type":"main","index":0}]]},"Build Error Response Payload":{"main":[[{"node":"Respond with Error","type":"main","index":0}]]},"Finds the appointment record":{"main":[[{"node":"Delete Event","type":"main","index":0}]]},"Build Error Response Payload2":{"main":[[{"node":"Response with Error","type":"main","index":0}]]},"Available Start Times & Ranges":{"main":[[{"node":"Flatten Slots","type":"main","index":0}]]},"Time available (true) & Call_id":{"main":[[{"node":"Response","type":"main","index":0}]]},"Check if time is available or not":{"main":[[{"node":"Time available (true) & Call_id","type":"main","index":0}],[{"node":"Get All Calendar Events","type":"main","index":0}]]},"Convert into Json format for Vapi":{"main":[[{"node":"Response to Vapi","type":"main","index":0}]]},"Input Arguments from booking tools":{"main":[[{"node":"Has all information","type":"main","index":0}]]},"Information to be Saved in Airtable":{"main":[[{"node":"Logs the confirmed booking details","type":"main","index":0}]]},"Checks if required info is provided.":{"main":[[{"node":"Finds original appointment","type":"main","index":0}],[{"node":"Build Error Response Payload2","type":"main","index":0}]]},"Input Arguments from cancelslot tool":{"main":[[{"node":"Checks if required info is provided for cancelation","type":"main","index":0}]]},"Input Arguments from updateslot tool":{"main":[[{"node":"Checks if required info is provided.","type":"main","index":0}]]},"Convert time to CST America / Chicago":{"main":[[{"node":"Create Event","type":"main","index":0}]]},"If the booking is confirmed then true":{"main":[[{"node":"Information to be Saved in Airtable","type":"main","index":0}]]},"Checks if required info is provided for cancelation":{"main":[[{"node":"Finds the appointment record","type":"main","index":0}],[{"node":"Build Error Response","type":"main","index":0}]]}}}


name: Fully Automated AI Video Generation & Multi-Platform Publishing
author_name: Juan Carlos Cavero Gracia
author_username: carlosgracia
categories: []
created_at: 2025-04-05T18:28:46.255Z
updated_at: 2025-04-05T18:28:46.255Z
url: https://n8n.io/workflows/3442
scraped_at: 2025-07-06 21:16:30
description:
  Description

  This comprehensive n8n automation template orchestrates a complete end-to-end workflow for generating engaging short-form Point-of-View (POV) style videos using multiple AI services and automatically publishing them across major social media platforms. It takes ideas from a Google Sheet and transforms them into finished videos with captions, voiceovers, and platform-specific descriptions, ready for distribution.

  Who Is This For?

  Content Creators & Agencies:** Mass-produce unique short-form video content for various clients or channels with minimal manual effort.
  Digital Marketers:** Automate video content pipelines to boost online presence and engagement across multiple platforms simultaneously.
  Social Media Managers:** Schedule and distribute consistent video content efficiently without juggling multiple tools and manual uploads.
  Businesses:** Leverage AI to create branded video content for marketing, reducing production time and costs.

  What Problem Does This Workflow Solve?

  Creating and distributing high-quality short-form video content consistently across multiple social networks is incredibly time-consuming and resource-intensive. This workflow tackles these challenges by:

  Automating Idea-to-Video Pipeline:** Generates video concepts, image prompts, scripts, images, video clips, and voiceovers using AI.
  Streamlining Video Assembly:** Automatically combines generated assets into a final video using a template.
  Generating Platform-Optimized Descriptions:** Creates relevant descriptions for posts by transcribing the final video audio.
  Automating Multi-Platform Publishing:** Uploads the final video and description to TikTok, Instagram, YouTube, Facebook, and LinkedIn simultaneously.
  Reducing Manual Workload:** Drastically cuts down the time and effort required for video production and distribution.
  Centralized Tracking:** Updates a Google Sheet with results, costs, and status for easy monitoring.

  How It Works

  Trigger & Input: Runs on a daily schedule (configurable) and fetches new video ideas from a designated Google Sheet.
  AI Content Generation:
      Uses OpenAI to generate video captions and image prompts based on the idea.
      Uses PiAPI (Flux) to generate images from prompts.
      Uses PiAPI (Kling) to generate video clips from the images (Image-to-Video).
      Uses OpenAI to generate a voiceover script based on the captions.
      Uses ElevenLabs to generate voiceover audio from the script and uploads it to Google Drive.
  Video Assembly: Combines the generated video clips, captions, and voiceover audio using a Creatomate template to render the final video.
  Description Generation: Uploads the final video to Google Drive, extracts the audio using OpenAI (Whisper), and generates a social media description using OpenAI (GPT).
  Multi-Platform Distribution: Uses upload-post.com to upload the final video and generated description to TikTok, Instagram, YouTube, Facebook, and LinkedIn.
  Tracking & Notification: Updates the original Google Sheet row with output details (video link, costs, tokens used) and sends a completion notification via Discord.

  Setup

  Accounts & API Keys: Obtain accounts and generate API keys/credentials for:
      n8n
      Google Cloud Platform (for Google Sheets & Google Drive APIs + OAuth Credentials)
      OpenAI
      PiAPI
      ElevenLabs
      Creatomate
      upload-post.com
      Discord (Webhook URL)
  Google Sheet: Make a copy of the provided Google Sheet Template and connect it in the Load Google Sheet node.
  Creatomate Template: Set up a video template in Creatomate (use the provided JSON source code as a base) and note its Template ID.
  Configure Nodes:
      Enter all API Keys/Credentials in the Set API Keys node and other relevant credential sections (Google nodes, upload-post nodes, etc.).
      Configure Google Drive nodes (Folder IDs, Permissions).
      Configure the upload-post.com nodes with your user identifier and necessary platform details (e.g., Facebook Page ID).
      Customize AI prompts within the OpenAI nodes (Generate Video Captions, Generate Image Prompts, Generate Script, Generate Description...) if desired.
      Set the Discord Webhook URL in the Notify me on Discord node.
  Enable Google APIs: Ensure Google Drive API and Google Sheets API are enabled in your Google Cloud Project.

  Requirements

  Accounts:** n8n, Google (Sheets, Drive, Cloud Platform), OpenAI, PiAPI, ElevenLabs, Creatomate, upload-post.com, Discord.
  API Keys & Credentials:** API Keys for OpenAI, PiAPI, ElevenLabs, Creatomate, upload-post.com. Google Cloud OAuth 2.0 Credentials. Discord Webhook URL.
  Templates:** A configured Google Sheet based on the template, a configured Creatomate video template.
  (Potentially) Paid Plans:** Some services (OpenAI, PiAPI, Creatomate, upload-post.com) may require paid plans depending on usage volume after free trials/credits are exhausted.

  Use this template to build a powerful, automated video content factory, scaling your production and distribution efforts across the social media landscape.

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","n8n-nodes-base.googleDrive","n8n-nodes-base.discord","n8n-nodes-base.code","@n8n/n8n-nodes-langchain.openAi"]

workflow_json:
  {"id":"KY0vB3hifSrA24k2","meta":{"instanceId":"3378b0d68c3b7ebfc71b79896d94e1a044dec38e99a1160aed4e9c323910fbe2","templateId":"3121"},"name":"AI-Powered Short-Form Video Generator with OpenAI, Flux, Kling, and ElevenLabs and upload to all social networks","tags":[],"nodes":[{"id":"e5095169-dc78-4d90-9662-04cfc82c38d9","name":"Get image","type":"n8n-nodes-base.httpRequest","position":[1160,480],"parameters":{"url":"=https://api.piapi.ai/api/v1/task/{{ $json.data.task_id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"f477250a-fc8e-407e-a632-cffc0e564596","name":"Generate Image","type":"n8n-nodes-base.httpRequest","position":[880,480],"parameters":{"url":"https://api.piapi.ai/api/v1/task","body":"={\n  \"model\": \"Qubico/flux1-dev\",\n  \"task_type\": \"txt2img\",\n  \"input\": {\n    \"prompt\": \"{{ $('Generate Image Prompts').item.json.choices[0].message.content }} realistic and casual as if taken by an iphone camera by a TikTok influencer\",\n    \"negative_prompt\": \"taking a photo of a room, recording a video of a room, photos app, video recorder, illegible text, blurry text, low quality text, DSLR, unnatural\",\n    \"width\": 540,\n    \"height\": 960\n  }\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"retryOnFail":false,"typeVersion":4.2},{"id":"622ce9f5-ad58-485b-a3c6-1265700b04da","name":"Image-to-Video","type":"n8n-nodes-base.httpRequest","position":[520,1000],"parameters":{"url":"https://api.piapi.ai/api/v1/task","body":"={\n  \"model\": \"kling\",\n  \"task_type\": \"video_generation\",\n  \"input\": {\n    \"prompt\": \"{{ $json.data.input.prompt }}\",\n    \"negative_prompt\": \"blurry motion, distorted faces, unnatural lighting, over produced, bad quality\",\n    \"cfg_scale\": 0.5,\n    \"duration\": 5,\n    \"mode\": \"pro\",\n    \"image_url\": \"{{ $json.data.output.image_url }}\",\n    \"version\": \"1.6\",\n    \"camera_control\": {\n      \"type\": \"simple\",\n      \"config\": {\n        \"horizontal\": 0,\n        \"vertical\": 0,\n        \"pan\": 0,\n        \"tilt\": 0,\n        \"roll\": 0,\n        \"zoom\": 5\n      }\n    }\n  },\n  \"config\": {}\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"ed14eac3-1d63-481d-871c-a04c52977fc6","name":"Get Video","type":"n8n-nodes-base.httpRequest","position":[780,1000],"parameters":{"url":"=https://api.piapi.ai/api/v1/task/{{ $json.data.task_id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"X-API-Key","value":"={{ $('Set API Keys').item.json['PiAPI Key'] }}"}]}},"typeVersion":4.2},{"id":"8b68100c-8a5a-405c-825e-d9e8a898f235","name":"List Elements","type":"n8n-nodes-base.code","position":[1400,1040],"parameters":{"jsCode":"return [\n  {\n    scene_titles: items.map(item => item.json.response.text),\n    video_urls: items.map(item => item.json.data.output.video_url),\n    input_tokens: $('Calculate Token Usage').first().json.total_prompt_tokens,\n    output_tokens: $('Calculate Token Usage').first().json.total_completion_tokens,\n    model: $('Generate Image Prompts').first().json.model\n  }\n];"},"typeVersion":2},{"id":"f8780885-508e-4dc9-b146-f367297d7b68","name":"Wait 10min","type":"n8n-nodes-base.wait","position":[660,1000],"webhookId":"1f9d716f-6544-4e4e-94ec-408ac3ea6e82","parameters":{"unit":"minutes","amount":10},"typeVersion":1.1},{"id":"6290bc91-0eb9-4053-bd93-961cb9e917c0","name":"Wait 3min","type":"n8n-nodes-base.wait","position":[1020,480],"webhookId":"77cdee73-5e99-456a-b5e7-410b4d257669","parameters":{"unit":"minutes","amount":3},"typeVersion":1.1},{"id":"818a66ef-b9fa-4efc-85d1-b295300cbed8","name":"Wait 5min","type":"n8n-nodes-base.wait","position":[1480,400],"webhookId":"31d5b1a2-dbb5-4849-ae25-cb491539c16e","parameters":{"unit":"minutes"},"typeVersion":1.1},{"id":"afd66320-dfe0-4872-a09d-d53fe08152ce","name":"Generate voice","type":"n8n-nodes-base.httpRequest","position":[880,1460],"parameters":{"url":"https://api.elevenlabs.io/v1/text-to-speech/onwK4e9ZLuTAKqWW03F9","method":"POST","options":{},"sendBody":true,"sendHeaders":true,"bodyParameters":{"parameters":[{"name":"text","value":"={{ $json.choices[0].message.content }}"}]},"headerParameters":{"parameters":[{"name":"xi-api-key","value":"={{ $('Set API Keys').item.json['ElevenLabs API Key'] }}"}]}},"retryOnFail":false,"typeVersion":4.2},{"id":"916f19e1-7928-4141-a5c5-ca39bd22b0a0","name":"List Elements1","type":"n8n-nodes-base.code","position":[1400,1260],"parameters":{"jsCode":"return [\n  {\n    sound_urls: items.map(item => $('Upload Voice Audio').first().json.webContentLink)\n  }\n];"},"typeVersion":2},{"id":"b95fd80c-ec7f-4d50-99ae-f3f544b8a111","name":"Fail check","type":"n8n-nodes-base.if","position":[920,1000],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a920eb54-fc23-4b68-8f56-2eee907a5481","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data.status }}","rightValue":"failed"}]}},"typeVersion":2.2},{"id":"7e3f5cda-1d49-4a59-956f-f639daf203e0","name":"Wait to retry","type":"n8n-nodes-base.wait","position":[1060,960],"webhookId":"3b0fae8f-4419-45cd-8380-8f72eca05ff8","parameters":{"unit":"minutes"},"typeVersion":1.1},{"id":"48ec39c9-1802-4860-918d-9c660051f27b","name":"Generate Image Prompts","type":"@n8n/n8n-nodes-langchain.openAi","position":[400,560],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"o3-mini","cachedResultName":"O3-MINI"},"options":{},"messages":{"values":[{"content":"=You are an advanced, unhinged, hilariously entertaining prompt-generation AI specializing in expanding short POV image prompt ideas into detailed, hyper-realistic prompts optimized for Qubico/flux1-dev. Your task is to take a brief input tied to job seeking, job hunting, or resume building and morph it into a cinematic, immersive prompt locked in a first-person perspective, making the viewer feel they’re living the scene.\n\nNEVER include quotation marks or emojis in your response—flux API will choke on them, and that’s a hard no.\n\nThe topic of this narrative is: {{ $('Load Google Sheet').item.json.idea }}\n\nThe short prompt idea to expand for this image generation is: {{ $json.response.text }}\n\nONLY GENERATE ONE PROMPT PER IDEA—NO COMBINING. In at least one scene, weave in this environment descriptor: {{ $('Load Google Sheet').first().json.environment_prompt }}, but go wild with unhinged, edgy, funny twists elsewhere (skip the cringe or cheesy garbage). Most job hunting happens on laptops or desktops, so prioritize those over phones. If a phone sneaks in, it’s only showing job-related content like email, LinkedIn, a resume, or a job posting—never a photo or video app.\n\nEvery prompt has two parts:\n\nForeground: Kick off with First person view POV GoPro shot of... and show the viewer’s hands, limbs, or feet locked in a job-related action.\n\nBackground: Start with In the background,... and paint the scenery, blending the environment descriptor when required, plus sensory zingers.\n\nTop Rules:\n\nNO quotation marks or emojis—EVER. This is life or death for flux.\nStick to first-person POV—the viewer’s in the driver’s seat, not watching from the sidelines.\nShow a limb (hands, feet) doing something job-focused—typing, holding a resume, adjusting a tie.\nKeep it dynamic, like a GoPro clip, with motion and depth mimicking human vision.\nIf tech’s involved (phone, computer), it’s displaying job-hunting gold—email, job boards, resumes—not random trash.\nNo off-topic actions like recording videos or snapping pics—job hunting only, fam.\nExtra Vibes:\n\nFull-body awareness: Drop hints of physical feels—cramping fingers, racing pulse, slumping shoulders.\nSensory overload: Hit sight, touch, sound, smell, temperature for max realism (coffee whiffs, keyboard clacks).\nWorld grip: Limbs interact with the scene—tapping keys, handing over papers, stepping up.\nKeep it under 1000 characters, one slick sentence, no fluff or formatting.\nMake it entertaining, relatable, with an Andrew Tate viral edge for the down-and-out job hustlers.\nExamples:\n\nInput: Updating a LinkedIn profile after a long day\n\nEnvironment_prompt: Tired, cluttered apartment, laptop glow\n\nOutput: First person view POV GoPro shot of my hands hammering a laptop, cheeto-dusted fingers aching from the grind, the screen flashing my LinkedIn profile with a fresh connection ping; in the background, a trashed apartment lit by the laptop’s ghostly glow, pizza boxes toppling, traffic humming outside, stale takeout stench hitting my nose as my back screams from the hustle.\n\nInput: Handing over a resume at a job fair\n\nEnvironment_prompt: Hopeful, busy convention hall, suits everywhere\n\nOutput: First person view POV GoPro shot of my hand thrusting out a crisp resume, fingers twitching with nerves as it brushes another palm; in the background, a buzzing convention hall packed with suits, coffee fumes and shoe polish in the air, chatter drowning my pounding heart as I lock eyes with the recruiter.\n\nNO QUOTATION MARKS. NO EMOJIS. EVER."}]},"simplify":false},"typeVersion":1.8},{"id":"5c1b8dc8-4eb3-49fe-81c7-c811d73fac0d","name":"Calculate Token Usage","type":"n8n-nodes-base.code","position":[700,560],"parameters":{"jsCode":"// Get all input items (the 5 LLM responses)\nconst items = $input.all();\n\n// Calculate total prompt tokens and total completion tokens\nconst totalPromptTokens = items.reduce((sum, item) => sum + item.json.usage.prompt_tokens, 0);\nconst totalCompletionTokens = items.reduce((sum, item) => sum + item.json.usage.completion_tokens, 0);\n\n// Create new items with original data plus the totals\nconst outputItems = items.map(item => ({\n  json: {\n    ...item.json,                   // Spread the original item data\n    total_prompt_tokens: totalPromptTokens,     // Add total prompt tokens\n    total_completion_tokens: totalCompletionTokens // Add total completion tokens\n  }\n}));\n\n// Return the modified items\nreturn outputItems;"},"typeVersion":2},{"id":"efc3d0dd-70dc-4fba-b040-22c773ed5602","name":"Check for failures","type":"n8n-nodes-base.if","position":[1300,480],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"567d1fc9-0638-4a44-b5f5-30a9a6683794","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.data.status }}","rightValue":"failed"}]}},"typeVersion":2.2},{"id":"3161c993-5696-4419-9299-fde51719dfc7","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[380,240],"parameters":{"color":5,"width":1260,"height":460,"content":"## 2. 🖼️Generate images with Flux using [PiAPI](https://piapi.ai/?via=n8n) \n### (total cost: $0.0948 approx. as of 3/9/25)\n1. OpenAI is used to generate 5 Flux image prompts based on the 5 captions generated. Edit this node to see/edit the prompt instructions. \n2. Next we use some custom javascript to total up how many tokens were used for each 5 generations so we can track our costs later.\n3. Then we generate an image with Flux using the [PiAPI service](https://piapi.ai/?via=n8n), waiting to check for failures and retrying if there are any.\n\nYou can change the image model used by editing the Generate Image node API call.\nFlux models available (as of 3/9/25):\n- Qubico/flux1-dev ($0.015) - Currently set\n- Qubico/flux1-schnell ($0.0015)\n- Qubico/flux1-advanced ($0.02)\n\nFor full list of API settings, see the [Flux API Documentation](https://piapi.ai/docs/flux-api/text-to-image?via=n8n)\n"},"typeVersion":1},{"id":"e5cdec7e-cb75-4200-a8e3-615621d20150","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[480,720],"parameters":{"color":6,"width":1040,"height":500,"content":"## 3. 🎬Generate videos with Kling using [PiAPI](https://piapi.ai/?via=n8n)\n### (total cost: $2.30 approx. as of 3/9/25)\n1. We use image-to-video with Kling using [PiAPI](https://piapi.ai/?via=n8n) to generate a video from each image.\n2. Then we wait to check for failures, and repeat the generations the failed if there are any.\n\nYou can edit the video model used in the Image-to-Video node. For testing, I'd recommend switching from pro to std for lower quality and cheaper price.\nKling models available (as of 3/9/25):\n- std (Standard) $0.26 per 5 second video\n- pro (Professional) $0.46 per 5 second video - Currently set\n\nFor full list of API settings, see the [Kling API Documentation](https://piapi.ai/docs/kling-api/create-task?via=n8n)\n"},"typeVersion":1},{"id":"8404a390-a402-4703-8cb5-4a54490dc7bd","name":"Generate Video Captions","type":"@n8n/n8n-nodes-langchain.openAi","position":[-40,1220],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"role":"system","content":"DO NOT include any quotation marks in your response. Do not put a quote at the beginning or the end of your response.\n\nYou are a prompt-generation AI specializing in crafting unhinged, entertaining TikTok captions for a \"day in the life\" POV story about job hunting or resume writing. Generate five concise, action-driven captions (5-10 words each) that follow a Problem > Action > Reward structure. The first caption should be a shocking or funny hook, and the last should conclude with a satisfying reward. Use emojis sparingly—only one per caption at most, and only when they add impact; skip them if they don’t enhance the message.\n\nGuidelines:\n\nPerspective: Always first-person POV, immersing the viewer in the story.\nTone: Channel Andrew Tate mixed with Charlie Sheen—cursing and sexual innuendos are fair game.\nContent: Focus on job seeking, hunting, or resume building, spotlighting AI as the game-changer.\nNarrative: Start with the grind of unemployment or a shitty job, pivot to using AI for resumes and cover letters, and end with scoring the dream gig.\nScenes: Highlight raw, emotional moments—skip the boring stuff.\nYour captions should be wild and entertaining, not polished or professional. The first caption is the hook—make it shocking, hilarious, or ballsy, something Andrew Tate would growl. Use emojis sparingly—max one per caption, only if it hits harder with it.\n\nYour response should be a list of 5 items separated by \"\\n\" (for example: \"item1\\nitem2\\nitem3\\nitem4\\nitem5\")"},{"content":"={{ $json.idea }}"}]},"simplify":false},"typeVersion":1.8},{"id":"f614c784-a3ee-4eb8-aee3-cc0ad3e87556","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[480,1240],"parameters":{"color":4,"width":1040,"height":400,"content":"## 4. 🔉Generate voice overs with [Eleven Labs](https://try.elevenlabs.io/n8n)\n1. OpenAI API is used to generate a funny script that relates to the captions. Open this node to see/edit the prompt instructions. \n2. Then we use the [Eleven Labs API](https://try.elevenlabs.io/n8n) to generate the voiceover and upload it to our Google Drive so it can be accessed in the next step.\n\nTo replace the voice, find the voice ID of the voice you want to use in [Eleven Labs](https://try.elevenlabs.io/n8n), then change the URL in the Generate Voice node to: https://api.elevenlabs.io/v1/text-to-speech/{voice ID here}\n\nFor full list of API settings, see the [Eleven Labs API Documentation](https://elevenlabs.io/docs/api-reference/text-to-speech/convert)\n"},"typeVersion":1},{"id":"e59306c1-8efe-4d98-9391-10c68c17787b","name":"Match captions with videos","type":"n8n-nodes-base.merge","position":[1240,1040],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3},{"id":"8da7e16e-691b-4335-bfc7-e196c36f982d","name":"Generate Script","type":"@n8n/n8n-nodes-langchain.openAi","position":[520,1460],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o-mini","cachedResultName":"GPT-4O-MINI"},"options":{},"messages":{"values":[{"role":"system","content":"=You are an unhinged and hilarious TikTok influencer who's like a mix of Andrew Tate and Charlie Sheen. The user is going to provide you with a topic, and then 5 different parts of a story. Your task is to narrate the story as this hilarious character, who isn't afraid to be edgy or curse or use sexual innuendos. However keep each of the 5 talking points brief, as you only have about 5 seconds to speak during each. The entire length of your narration should be around 15 seconds.\n\nEach line item of the users message represents 1 5 second clip, so your response needs to be able to quickly and easily be spoken in those time constraints. Don't say extra things you don't need to. Just quickly tell the story, in order, and make it unhinged, funny, entertaining, and potentially controversially viral. Don't worry about offendeding anyone. Andrew Tate style it.\n\nDo not include any emojis, as your response will be converted from text to speech, so anything but text and punctuation isn't neccesary. Also, don't make your jokes overly corny, speak in a witty, edgy, funny way, but no corny dad jokes or anything cringe."},{"content":"={{ $('Generate Video Captions').item.json.choices[0].message.content }}"}]},"simplify":false},"executeOnce":true,"typeVersion":1.8},{"id":"ad87317d-3ed0-4fdf-aea5-7b2fa60fb59f","name":"Upload Voice Audio","type":"n8n-nodes-base.googleDrive","position":[1080,1460],"parameters":{"name":"={{ $('Load Google Sheet').item.json.id }}-voiceover.mp3","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultUrl":"https://drive.google.com/drive/folders/1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultName":"Resume Studio"}},"typeVersion":3},{"id":"eec529e9-2601-4f7b-b415-63d2ebba1574","name":"Set Access Permissions","type":"n8n-nodes-base.googleDrive","position":[1260,1460],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{},"operation":"share","permissionsUi":{"permissionsValues":{"role":"writer","type":"anyone","allowFileDiscovery":true}}},"typeVersion":3},{"id":"63e72d56-140e-47d8-9f72-b58c764deed9","name":"Pair Videos with Audio","type":"n8n-nodes-base.merge","position":[1620,1140],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3},{"id":"60a80c6f-0385-48e6-9b71-c23a74cbc15c","name":"Render Final Video","type":"n8n-nodes-base.httpRequest","position":[1800,1140],"parameters":{"url":"https://api.creatomate.com/v1/renders","body":"={\n  \"template_id\": \"{{ $('Set API Keys').item.json['Creatomate Template ID'] }}\",\n  \"modifications\": {\n    \n    \"Video-1.source\": \"{{ $json.video_urls[0] }}\",\n    \"Video-2.source\": \"{{ $json.video_urls[1] }}\",\n    \"Video-3.source\": \"{{ $json.video_urls[2] }}\",\n    \"Video-4.source\": \"{{ $json.video_urls[3] }}\",\n    \"Video-5.source\": \"{{ $json.video_urls[4] }}\",\n\n    \"Audio-1.source\": \"{{ $json.sound_urls[0] }}\",\n\n    \"Text-1.text\": \"{{ $json.scene_titles[0] }}\",\n    \"Text-2.text\": \"{{ $json.scene_titles[1] }}\",\n    \"Text-3.text\": \"{{ $json.scene_titles[2] }}\",\n    \"Text-4.text\": \"{{ $json.scene_titles[3] }}\",\n    \"Text-5.text\": \"{{ $json.scene_titles[4] }}\"\n  }\n}","method":"POST","options":{},"sendBody":true,"contentType":"raw","sendHeaders":true,"rawContentType":"application/json","headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $('Set API Keys').item.json['Creatomate API Key'] }}"},{"name":"Content-Type","value":"application/json"}]}},"executeOnce":true,"typeVersion":4.2},{"id":"89c0e958-7690-4f3d-af49-3e9776f2c979","name":"Notify me on Discord","type":"n8n-nodes-base.discord","position":[2780,1140],"webhookId":"1541bc50-06e4-48e8-8c76-23850ee4edf6","parameters":{"content":"=A new Resume Studio POV video has been created: {{ $json.final_output }}","options":{},"authentication":"webhook"},"typeVersion":2},{"id":"14a09794-5e02-4880-b33d-139a91726dda","name":"Once Per Day","type":"n8n-nodes-base.scheduleTrigger","position":[-600,1220],"parameters":{"rule":{"interval":[{"triggerAtHour":7}]}},"typeVersion":1.2},{"id":"4de1f1c7-52ad-4e00-ad22-b4c3c0f718d8","name":"Load Google Sheet","type":"n8n-nodes-base.googleSheets","position":[-180,1220],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"for production","lookupColumn":"production"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=drivesdk","cachedResultName":"Sheet Template"}},"typeVersion":4.5,"alwaysOutputData":true},{"id":"e5c83690-1696-43aa-a0db-164ca128dd67","name":"Create List","type":"n8n-nodes-base.code","position":[280,1140],"parameters":{"jsCode":"// Get the text directly from the OpenAI response\nconst text = $input.first().json.choices[0].message.content;\n\n// Split the text on literal '\\\\n', trim, and filter empty lines\nconst lines = text.split('\\\\n').map(line => line.trim()).filter(line => line !== '');\n\n// Create an array of items for n8n\nconst items = lines.map(line => ({\n  json: {\n    response: { text: line }\n  }\n}));\n\n// Return the array of items\nreturn items;"},"typeVersion":2},{"id":"ed99df67-2068-4c8b-a6ba-e67d234f03c4","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1560,920],"parameters":{"color":3,"width":1360,"height":380,"content":"## 5. 📥Complete video with [Creatomate](https://creatomate.com/)\n### (total cost: $0.38 approx. with the Essential plan credits | Free trial credits available)\n1. First, the list of videos/captions is combined with the generated voice over into a single item containing all 3 elements.\n2. Those are then passed over to the Creatomate Template ID you specified, replacing the template captions/video/audio with your generated ones.\n3. When the video is finished rendering, it's then uploaded to Google Drive and the permissions set so it can be accessed with a link.\n4. Then we update the original Google Sheet template with the information from our generation, including tokens to calculate cost, then mark this idea as completed.\n5. Finally, we send a notification to via [webhook to the Discord server](https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks) when the video is ready to be downloaded and used!\n\n"},"typeVersion":1},{"id":"e7064a56-c500-4f9f-a54a-c4352c263b56","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-320,280],"parameters":{"width":620,"height":420,"content":"# 🤖 AI-Powered Short-Form Video Generator with OpenAI, Flux, Kling, and ElevenLabs\n\n## 📃Before you get started, you'll need:\n- [n8n installation](https://n8n.partnerlinks.io/n8nTTVideoGenTemplate) (tested on version 1.81.4)\n- [OpenAI API Key](https://platform.openai.com/api-keys) (free trial credits available)\n- [PiAPI](https://piapi.ai/?via=n8n) (free trial credits available)\n- [Eleven Labs](https://try.elevenlabs.io/n8n) (free account)\n- [Creatomate API Key](https://creatomate.com/) (free trial credits available)\n- Google Sheets API enabled in [Google Cloud Console](https://console.cloud.google.com/apis/api/sheets.googleapis.com/overview)\n- Google Drive API enabled in [Google Cloud Console](https://console.cloud.google.com/apis/api/drive.googleapis.com/overview)\n- OAuth 2.0 Client ID and Client Secret from your [Google Cloud Console Credentials](https://console.cloud.google.com/apis/credentials)\n"},"typeVersion":1},{"id":"4ddb7249-9785-4f51-b35c-b9a0c6a66e3b","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-480,780],"parameters":{"color":7,"width":920,"height":700,"content":"## 1. 🗨️Generate video captions from ideas in a Google Sheet\n\n1. Setup your API keys for [PiAPI](https://piapi.ai/?via=n8n), [Eleven Labs](https://try.elevenlabs.io/n8n), and [Creatomate](https://creatomate.com/).\n- Once logged in to your Creatomate account, create a new video template and click \"source code\" in the top right. [Paste this JSON code](https://pastebin.com/c7aMTeLK). This will be your example template for this workflow.\n- In your Creatomate template, click the \"Use Template\" button in the top right and then click \"API Integration\" and you'll see your template_id. Set this value as your Creatomate Template ID in the Set API Keys node\n\n2. The next node will load a Google Sheet, you can copy the [Google Sheet Template](https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=sharing), simply choose File > Make a copy. Then in the Google Sheets node, connect to your copied sheet template.\n\n3. Next, we generate 5 captions for our video idea with OpenAI. You can edit this node to see the prompt and change it to your needs.\n\n4. In the final two nodes, we use custom javascript code to turn the OpenAI response into a list. Then, it validates to make sure the list was formed correctly (incase of an OpenAI failure to follow instructions)\n"},"typeVersion":1},{"id":"57ee2f8f-5371-4dab-b661-c58b25c7dd55","name":"Wait1","type":"n8n-nodes-base.wait","position":[1920,1140],"webhookId":"206d0cdf-b71f-44a7-909f-97df885c471a","parameters":{"unit":"minutes","amount":3},"typeVersion":1.1},{"id":"33781e51-ef30-437b-8499-94e39bfb38fa","name":"Get Final Video","type":"n8n-nodes-base.httpRequest","position":[2040,1140],"parameters":{"url":"=https://api.creatomate.com/v1/renders/{{ $('Render Final Video').item.json.id }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"Authorization","value":"=Bearer {{ $('Set API Keys').item.json['Creatomate API Key'] }}"},{"name":"Content-Type","value":"application/json"}]}},"executeOnce":true,"typeVersion":4.2},{"id":"b0d0fe6f-39c2-4da6-9fcf-b0151ed2c351","name":"Upload Final Video","type":"n8n-nodes-base.googleDrive","position":[2300,1140],"parameters":{"name":"=POV-{{ $('Render Final Video').item.json.id }}.mp4","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultUrl":"https://drive.google.com/drive/folders/1w1EQ8xyth6w7AbX2wpDI3vInfYeRy8vH","cachedResultName":"Resume Studio"}},"credentials":{"googleDriveOAuth2Api":{"id":"2TbhWtnbRfSloGxX","name":"Google Drive account"}},"typeVersion":3},{"id":"3893d1de-7464-48ad-91a3-14b867c2a516","name":"Get Raw File","type":"n8n-nodes-base.httpRequest","position":[2160,1140],"parameters":{"url":"={{ $json.url }}","options":{"response":{"response":{"responseFormat":"file"}}}},"typeVersion":4.2},{"id":"74de5f28-f081-4ec5-a47e-681eb845f701","name":"Set Permissions","type":"n8n-nodes-base.googleDrive","position":[2440,1140],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{},"operation":"share","permissionsUi":{"permissionsValues":{"role":"writer","type":"anyone","allowFileDiscovery":true}}},"credentials":{"googleDriveOAuth2Api":{"id":"2TbhWtnbRfSloGxX","name":"Google Drive account"}},"typeVersion":3},{"id":"a2c07158-e949-4b5b-a92e-f4b021742831","name":"Update Google Sheet","type":"n8n-nodes-base.googleSheets","position":[2600,1140],"parameters":{"columns":{"value":{"id":"={{ $('Load Google Sheet').first().json.id }}","width":"={{ $('Get Raw File').item.json.width }}","height":"={{ $('Get Raw File').item.json.height }}","model1":"={{ $('Generate Video Captions').item.json.model }}","model2":"={{ $('Pair Videos with Audio').item.json.model }}","model3":"={{ $('Generate Script').item.json.model }}","duration":"={{ $('Get Raw File').item.json.duration }}","fluxCost":"0.075","frameRate":"={{ $('Get Raw File').item.json.frame_rate }}","klingCost":"2.3","production":"done","publishing":"for publishing","final_output":"={{ $('Upload Final Video').item.json.webContentLink }}","prompt1 input tokens":"={{ $('Generate Video Captions').item.json.usage.prompt_tokens }}","prompt2 input tokens":"={{ $('Pair Videos with Audio').item.json.input_tokens }}","prompt3 input tokens":"={{ $('Generate Script').item.json.usage.prompt_tokens }}","prompt1 output tokens":"={{ $('Generate Video Captions').item.json.usage.completion_tokens }}","prompt2 output tokens":"={{ $('Pair Videos with Audio').item.json.output_tokens }}","prompt3 output tokens":"={{ $('Generate Script').item.json.usage.completion_tokens }}"},"schema":[{"id":"id","type":"string","display":true,"removed":false,"required":false,"displayName":"id","defaultMatch":true,"canBeUsedToMatch":true},{"id":"idea","type":"string","display":true,"removed":false,"required":false,"displayName":"idea","defaultMatch":false,"canBeUsedToMatch":true},{"id":"caption","type":"string","display":true,"removed":false,"required":false,"displayName":"caption","defaultMatch":false,"canBeUsedToMatch":true},{"id":"production","type":"string","display":true,"removed":false,"required":false,"displayName":"production","defaultMatch":false,"canBeUsedToMatch":true},{"id":"environment_prompt","type":"string","display":true,"removed":false,"required":false,"displayName":"environment_prompt","defaultMatch":false,"canBeUsedToMatch":true},{"id":"publishing","type":"string","display":true,"removed":false,"required":false,"displayName":"publishing","defaultMatch":false,"canBeUsedToMatch":true},{"id":"final_output","type":"string","display":true,"removed":false,"required":false,"displayName":"final_output","defaultMatch":false,"canBeUsedToMatch":true},{"id":"width","type":"string","display":true,"removed":false,"required":false,"displayName":"width","defaultMatch":false,"canBeUsedToMatch":true},{"id":"height","type":"string","display":true,"removed":false,"required":false,"displayName":"height","defaultMatch":false,"canBeUsedToMatch":true},{"id":"duration","type":"string","display":true,"removed":false,"required":false,"displayName":"duration","defaultMatch":false,"canBeUsedToMatch":true},{"id":"frameRate","type":"string","display":true,"removed":false,"required":false,"displayName":"frameRate","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model1","type":"string","display":true,"removed":false,"required":false,"displayName":"model1","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt1 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt1 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt1 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt1 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model1 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model1 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model2","type":"string","display":true,"removed":false,"required":false,"displayName":"model2","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt2 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt2 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt2 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt2 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model2 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model2 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model3","type":"string","display":true,"removed":false,"required":false,"displayName":"model3","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt3 input tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt3 input tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"prompt3 output tokens","type":"string","display":true,"removed":false,"required":false,"displayName":"prompt3 output tokens","defaultMatch":false,"canBeUsedToMatch":true},{"id":"model3 cost","type":"string","display":true,"removed":false,"required":false,"displayName":"model3 cost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"cmCost","type":"string","display":true,"removed":false,"required":false,"displayName":"cmCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"upgradeCmCost","type":"string","display":true,"removed":false,"required":false,"displayName":"upgradeCmCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"fluxCost","type":"string","display":true,"removed":false,"required":false,"displayName":"fluxCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"klingCost","type":"string","display":true,"removed":false,"required":false,"displayName":"klingCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"totalCost","type":"string","display":true,"removed":false,"required":false,"displayName":"totalCost","defaultMatch":false,"canBeUsedToMatch":true},{"id":"datePosted","type":"string","display":true,"removed":false,"required":false,"displayName":"datePosted","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1cjd8p_yx-M-3gWLEd5TargtoB35cW-3y66AOTNMQrrM/edit?usp=drivesdk","cachedResultName":"Sheet Template"}},"credentials":{"googleSheetsOAuth2Api":{"id":"3IOU2VjBnR4hGohx","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"62423325-f9da-4cdf-8864-c011fb4fa14f","name":"Set API Keys","type":"n8n-nodes-base.set","notes":"SET BEFORE STARTING","position":[-380,1220],"parameters":{"options":{},"assignments":{"assignments":[{"id":"35659353-d8e2-4677-876b-401b549605a0","name":"PiAPI Key","type":"string","value":""},{"id":"c4927dd6-c597-48fe-b7c1-bbffcf5ff02f","name":"ElevenLabs API Key","type":"string","value":""},{"id":"f5e90c05-dd24-4918-9005-4c87a4fb344d","name":"Creatomate API Key","type":"string","value":""},{"id":"d0ebba50-5a99-4090-adcb-d18aa0b21be2","name":"Creatomate Template ID","type":"string","value":""}]}},"notesInFlow":true,"typeVersion":3.4},{"id":"4252d793-5f16-4d5e-bb78-9b155aef5d3e","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-440,1160],"parameters":{"color":3,"width":220,"height":220,"content":"## DO THIS FIRST\n"},"typeVersion":1},{"id":"845d5b4a-8a3f-4d0d-afce-39aa4e349a7b","name":"Validate list formatting","type":"n8n-nodes-base.if","position":[280,1280],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2681c0e9-aa45-4f0f-8933-6e6de324c7aa","operator":{"type":"array","operation":"lengthGt","rightType":"number"},"leftValue":"={{$input.all()}}","rightValue":1}]}},"typeVersion":2.2},{"id":"98a3761e-544a-473c-aa7f-cc14390750d8","name":"Get Audio from Video","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Extract the audio from video for generate the description","position":[3820,1360],"parameters":{"options":{},"resource":"audio","operation":"transcribe"},"credentials":{"openAiApi":{"id":"XJdxgMSXFgwReSsh","name":"n8n key"}},"notesInFlow":true,"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"ec498643-1ef1-42e5-90ee-ec49d0e2b63b","name":"Generate Description for Videos  in Tiktok and Instagram","type":"@n8n/n8n-nodes-langchain.openAi","notes":"Request to OpenAi for generate description with the audio extracted from the video","position":[4060,1360],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"role":"system","content":"You are an expert assistant in creating engaging social media video titles."},{"content":"=I'm going to upload a video to social media. Here are some examples of descriptions that have worked well on Instagram:\n\nFollow and save for later. Discover InfluencersDe, the AI tool that automates TikTok creation and publishing to drive traffic to your website. Perfect for entrepreneurs and brands.\n#digitalmarketing #ugc #tiktok #ai #influencersde #contentcreation\n\nDiscover the video marketing revolution with InfluencersDe!\n.\n.\n.\n#socialmedia #videomarketing #ai #tiktok #influencersde #growthhacking\n\nDon't miss InfluencersDe, the tool that transforms your marketing strategy with just one click!\n.\n.\n.\n#ugc #ai #tiktok #digitalmarketing #influencersde #branding\n\nCan you create another title for the Instagram post based on this recognized audio from the video?\n\nAudio: {{ $('Get Audio from Video').item.json.text }}\n\nIMPORTANT: Reply only with the description, don't add anything else."}]}},"credentials":{"openAiApi":{"id":"XJdxgMSXFgwReSsh","name":"n8n key"}},"notesInFlow":true,"retryOnFail":true,"typeVersion":1.4,"waitBetweenTries":5000},{"id":"2f9f753d-86f3-4489-9dd2-a691f2da80ba","name":"Upload Video and Description to Tiktok","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,940],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"tiktok"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"WNjAx7UqrEZ1JDrR","name":"VituManco"}},"notesInFlow":true,"typeVersion":4.2},{"id":"4f007ef7-3f0a-4b4d-8dca-96028f29dd0c","name":"Upload Video and Description to Instagram","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1140],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"instagram"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"3805750b-65c4-4f28-b811-967681eda0ff","name":"Upload Video and Description to Youtube","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1360],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\").substring(0, 70) }}\n"},{"name":"platform[]","value":"youtube"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"754e3f54-87cd-4b50-947e-a9b20ce2d2ab","name":"Upload Video and Description to Facebook","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1600],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"facebook"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"},{"name":"facebook_page_id","value":"61556896550301"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"4090c098-2381-4e57-8e53-d24a2bed57cd","name":"Upload Video and Description to Linkedin","type":"n8n-nodes-base.httpRequest","notes":"Generate in upload-post.com the token and add to the credentials in the header-> Authorization: Apikey (token here)","position":[4880,1840],"parameters":{"url":"https://api.upload-post.com/api/upload","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $('Generate Description for Videos  in Tiktok and Instagram').item.json.message.content.replaceAll(\"\\\"\", \"\") }}"},{"name":"platform[]","value":"linkedin"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"data"},{"name":"user","value":"Add user generated in upload-post"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"47dO31ED0WIaJkR6","name":"Header Auth account"}},"notesInFlow":true,"typeVersion":4.2},{"id":"cd9fbbf5-262e-43bc-9c09-382516de1cca","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2940,920],"parameters":{"width":2480,"height":1160,"content":"## 6. Upload to all social networks with upload-post.com\n### (premium plan 15$ | Free trial credits available)\n\n\n\nThis automation will automatically create descriptions from videos and upload it to Instagram, TikTok, Youtube, Facebook and Linkedin.\n\n## How to Use\n1. Generate an API token at upload-post.com and add to Upload to Tiktok and Upload to Instagram nodes etc\n2. Customize the OpenAI prompt for your specific use case\n3. Optional: Configure Telegram for error notifications\n\n## Requirements\n- upload-post.com account\n- OpenAI API key\n"},"typeVersion":1},{"id":"f3524df6-484b-40e6-a9a3-f4d2211f3988","name":"Read Video from Google Drive","type":"n8n-nodes-base.readBinaryFile","position":[4420,1360],"parameters":{"filePath":"={{ $('Write video').item.json.originalFilename.replaceAll(\" \", \"_\") }}","dataPropertyName":"datavideo"},"typeVersion":1},{"id":"f082675c-1682-4679-88df-ae410e323f5b","name":"Write video","type":"n8n-nodes-base.writeBinaryFile","position":[3440,1360],"parameters":{"options":{},"fileName":"={{ $json.originalFilename.replaceAll(\" \", \"_\") }}"},"typeVersion":1}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"8f78312c-a5e3-48f0-a386-e1251586a6e7","connections":{"Wait1":{"main":[[{"node":"Get Final Video","type":"main","index":0}]]},"Get Video":{"main":[[{"node":"Fail check","type":"main","index":0}]]},"Get image":{"main":[[{"node":"Check for failures","type":"main","index":0}]]},"Wait 3min":{"main":[[{"node":"Get image","type":"main","index":0}]]},"Wait 5min":{"main":[[{"node":"Generate Image","type":"main","index":0}]]},"Fail check":{"main":[[{"node":"Wait to retry","type":"main","index":0}],[{"node":"Match captions with videos","type":"main","index":1}]]},"Wait 10min":{"main":[[{"node":"Get Video","type":"main","index":0}]]},"Create List":{"main":[[{"node":"Validate list formatting","type":"main","index":0}]]},"Write video":{"main":[[{"node":"Get Audio from Video","type":"main","index":0}]]},"Get Raw File":{"main":[[{"node":"Upload Final Video","type":"main","index":0},{"node":"Write video","type":"main","index":0}]]},"Once Per Day":{"main":[[{"node":"Set API Keys","type":"main","index":0}]]},"Set API Keys":{"main":[[{"node":"Load Google Sheet","type":"main","index":0}]]},"List Elements":{"main":[[{"node":"Pair Videos with Audio","type":"main","index":0}]]},"Wait to retry":{"main":[[{"node":"Image-to-Video","type":"main","index":0}]]},"Generate Image":{"main":[[{"node":"Wait 3min","type":"main","index":0}]]},"Generate voice":{"main":[[{"node":"Upload Voice Audio","type":"main","index":0}]]},"Image-to-Video":{"main":[[{"node":"Wait 10min","type":"main","index":0}]]},"List Elements1":{"main":[[{"node":"Pair Videos with Audio","type":"main","index":1}]]},"Generate Script":{"main":[[{"node":"Generate voice","type":"main","index":0}]]},"Get Final Video":{"main":[[{"node":"Get Raw File","type":"main","index":0}]]},"Set Permissions":{"main":[[{"node":"Update Google Sheet","type":"main","index":0}]]},"Load Google Sheet":{"main":[[{"node":"Generate Video Captions","type":"main","index":0}]]},"Check for failures":{"main":[[{"node":"Wait 5min","type":"main","index":0}],[{"node":"Image-to-Video","type":"main","index":0}]]},"Render Final Video":{"main":[[{"node":"Wait1","type":"main","index":0}]]},"Upload Final Video":{"main":[[{"node":"Set Permissions","type":"main","index":0}]]},"Upload Voice Audio":{"main":[[{"node":"Set Access Permissions","type":"main","index":0}]]},"Update Google Sheet":{"main":[[{"node":"Notify me on Discord","type":"main","index":0}]]},"Get Audio from Video":{"main":[[{"node":"Generate Description for Videos  in Tiktok and Instagram","type":"main","index":0}]]},"Notify me on Discord":{"main":[[]]},"Calculate Token Usage":{"main":[[{"node":"Generate Image","type":"main","index":0}]]},"Generate Image Prompts":{"main":[[{"node":"Calculate Token Usage","type":"main","index":0}]]},"Pair Videos with Audio":{"main":[[{"node":"Render Final Video","type":"main","index":0}]]},"Set Access Permissions":{"main":[[{"node":"List Elements1","type":"main","index":0}]]},"Generate Video Captions":{"main":[[{"node":"Create List","type":"main","index":0}]]},"Validate list formatting":{"main":[[{"node":"Generate Image Prompts","type":"main","index":0},{"node":"Match captions with videos","type":"main","index":0},{"node":"Generate Script","type":"main","index":0}],[{"node":"Generate Video Captions","type":"main","index":0}]]},"Match captions with videos":{"main":[[{"node":"List Elements","type":"main","index":0}]]},"Read Video from Google Drive":{"main":[[{"node":"Upload Video and Description to Tiktok","type":"main","index":0},{"node":"Upload Video and Description to Instagram","type":"main","index":0},{"node":"Upload Video and Description to Youtube","type":"main","index":0},{"node":"Upload Video and Description to Facebook","type":"main","index":0},{"node":"Upload Video and Description to Linkedin","type":"main","index":0}]]},"Generate Description for Videos  in Tiktok and Instagram":{"main":[[{"node":"Read Video from Google Drive","type":"main","index":0}]]}}}


name: Scrape business leads from Google Maps using OpenAI and Google Sheets
author_name: Dr. Firas
author_username: drfiras
categories: []
created_at: 2025-04-05T19:50:44.805Z
updated_at: 2025-04-05T19:50:44.805Z
url: https://n8n.io/workflows/3443
scraped_at: 2025-07-06 21:16:30
description:
  Google Maps Data Extraction Workflow for Lead Generation

  This workflow is ideal for sales teams, marketers, entrepreneurs, and researchers looking to efficiently gather detailed business information from Google Maps for:

  Lead generation  
  Market analysis  
  Competitive research

  Who Is This Workflow For?

  Sales professionals** aiming to build targeted contact lists  
  Marketers** looking for localized business data  
  Researchers** needing organized, comprehensive business information  

  Problem This Workflow Solves

  Manually gathering business contact details from Google Maps is:

  Tedious  
  Error-prone  
  Time-consuming  

  This workflow automates data extraction to increase efficiency, accuracy, and productivity.

  What This Workflow Does

  Automates extraction of business data (name, address, phone, email, website) from Google Maps  
  Crawls and extracts additional website content  
  Integrates OpenAI to enhance data processing  
  Stores structured results in Google Sheets for easy access and analysis  
  Uses Google Search API to fill in missing information  

  Setup

  Import the provided n8n workflow JSON into your n8n instance.  
  Set your OpenAI and Google Sheets API credentials.  
  Provide your Google Maps Scraper and Website Content Crawler API keys.  
  Ensure SerpAPI is configured to enhance data completeness.  

  Customizing This Workflow to Your Needs

  Adjust scraping parameters:
    Location  
    Business category  
    Country code  
  Customize Google Sheets output format to fit your current data structure  
  Integrate additional AI processing steps or APIs for richer data enrichment  

  Final Notes

  This structured approach ensures:

  Accurate and compliant data extraction** from Google Maps  
  Streamlined lead generation  
  Actionable and well-organized data ready for business use  

  📄 Documentation: Notion Guide

  Demo Video

  🎥 Watch the full tutorial here: YouTube Demo

nodes_used:
  ["n8n-nodes-base.googleSheets","n8n-nodes-base.httpRequest","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.toolSerpApi","@n8n/n8n-nodes-langchain.toolWorkflow"]

workflow_json:
  {"id":"qhZvZVCoV3HLjRkq","meta":{"instanceId":"a2b23892dd6989fda7c1209b381f5850373a7d2b85609624d7c2b7a092671d44","templateCredsSetupCompleted":true},"name":"Google Maps FULL","tags":[],"nodes":[{"id":"c5d63d91-ffcc-4c05-a1ee-d78ca955fc85","name":"Trigger - When User Sends Message","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-400,-60],"webhookId":"e5c0f357-c0a4-4ebc-9162-0382d8009539","parameters":{"options":{}},"typeVersion":1.1},{"id":"e422761f-a662-4fef-81fe-de42cdb350fc","name":"AI Agent - Lead Collection","type":"@n8n/n8n-nodes-langchain.agent","position":[-160,-60],"parameters":{"options":{"systemMessage":"' UNIFIED AND OPTIMIZED PROMPT FOR DATA EXTRACTION VIA GOOGLE MAPS SCRAPER\n\n' --- 1. Task ---\n' - Collect high-quality professional leads from Google Maps, including:\n'   - Business name\n'   - Address\n'   - Phone number\n'   - Website\n'   - Email\n'   - Other relevant contact details\n' - Deliver organized, accurate, and actionable data.\n\n' --- 2. Context & Collaboration ---\n' - Tools & Sources:\n'   * Google Maps Scraper: Extracts data based on location, business type, and country code \n'     (ISO 3166 Alpha-2 in lowercase).\n'   * Website Scraper: Extracts data from provided URLs (the URL must be passed exactly as received, without quotation marks).\n'   * Google Sheets: Stores and retrieves previously extracted data.\n'   * Internet Search: Provides additional information if the scraping results are incomplete.\n' - Priorities: Accuracy and efficiency, avoiding unnecessary searches.\n\n' --- 3. Ethical Guidelines ---\n' - Only extract publicly accessible professional data.\n' - Do not collect or store personal/sensitive data.\n' - Adhere to scraping policies and data protection regulations.\n' - Error Handling:\n'   * In case of failure or incomplete results, suggest a retry, adjusted search parameters, or an alternative source.\n'   * If Google Sheets is unavailable, notify the user and propose workarounds.\n\n' --- 4. Constraints ---\n' - Country codes must follow the ISO 3166 Alpha-2 format in lowercase (e.g., \"fr\" for France).\n' - When using the Website Scraper, pass the URL exactly as provided, without quotation marks or modifications.\n' - Validate and correctly format all data (no duplicates or errors).\n' - Store results in Google Sheets in an organized and accessible manner.\n\n' --- 5. Final Requirements & Quality Checks ---\n' - Verification: Ensure the country code is always passed in lowercase to the Google Maps Scraper.\n' - URL: If a URL is provided, forward it directly to the Website Scraper without adding quotation marks.\n' - Existing Data: Check Google Sheets to see if the data is already available before performing new scraping.\n' - Supplementary: In case of partial results, propose using Internet Search to complete the information.\n\n' --- 6. Interaction ---\n' - If data already exists in Google Sheets, retrieve and present it to the user instead of launching a new scrape.\n' - If scraping fails or returns incomplete results, suggest alternative actions (e.g., web search, verifying the country code).\n\n' --- 7. Examples ---\n' BAD Example (Google Maps Scraper)\n'   User: \"Find coffee shops in Paris, France.\"\n'   AI: \"Extracting coffee shop data from Google Maps in France.\"\n'   > Issue: The country code \"fr\" was not provided.\n'\n' GOOD Example (Google Maps Scraper)\n'   User: \"Find coffee shops in Paris, France.\"\n'   AI:\n'     - \"Extracting coffee shop data from Google Maps in fr (France).\"\n'     - \"Scraped 50 businesses with names, addresses, phone numbers, and websites.\"\n'     - \"Storing results in Google Sheets under Lead_Generation_Paris_FR.\"\n'\n' BAD Example (Website Scraper)\n'   User: \"Scrape data from https://www.example.com/\"\n'   AI: \"Forwarding 'https://www.example.com/' to the Website Scraper.\"\n'   > Issue: Unnecessary quotation marks around the URL.\n'\n' GOOD Example (Website Scraper)\n'   User: \"Scrape data from https://www.example.com/\"\n'   AI:\n'     - \"Forwarding https://www.example.com to the Website Scraper.\"\n'     - \"Processing data extraction and storing results in Google Sheets.\"\n\n' --- 8. Output Format ---\n' - Responses should be concise and informative.\n' - Present data in a structured manner (e.g., business name, address, phone, website, etc.).\n' - If data already exists, clearly display the retrieved information from Google Sheets.\n\n' --- Additional Context & Details ---\n'\n' You interact with scraping APIs and databases to retrieve, update, and manage lead information.\n' Always pass country information using lowercase ISO 3166 Alpha-2 format when using the Google Maps Scraper.\n' If a URL is provided, it must be passed exactly as received, without quotation marks, to the Website Scraper.\n'\n' Known details:\n' You extract business names, addresses, phone numbers, websites, emails, and other relevant contact information.\n'\n' The URL must be passed exactly as provided (e.g., https://www.example.com/) without quotation marks or formatting changes.\n' Google Maps Scraper requires location, business type, and ISO 3166 Alpha-2 country codes to extract business listings.\n'\n' Context:\n' - System environment:\n'   You have direct integration with scraping tools, Internet search capabilities, and Google Sheets.\n'   You interact with scraping APIs and databases to retrieve, update, and manage lead information.\n'\n' Role:\n' You are a Lead Generation & Web Scraping Agent.\n' Your primary responsibility is to identify, collect, and organize relevant business leads by scraping websites, Google Maps, and performing Internet searches.\n' Ensure all extracted data is structured, accurate, and stored properly for easy access and analysis.\n' You have access to two scraping tools:\n'   1. Website Scraper – Requires only the raw URL to extract data from a specific website.\n'      - The URL must be passed exactly as provided (e.g., https://www.example.com/) without quotation marks or formatting changes.\n'   2. Google Maps Scraper – Requires location, business type, and ISO 3166 Alpha-2 country codes to extract business listings.\n\n' --- FINAL INSTRUCTIONS ---\n' 1. Adhere to all the directives and constraints above when extracting data from Google Maps (or other sources).\n' 2. Systematically check if data already exists in Google Sheets.\n' 3. In case of failure or partial results, propose an adjustment to the query or resort to Internet search.\n' 4. Ensure ethical compliance: only collect public data and do not store sensitive information.\n'\n' This prompt will guide the AI agent to efficiently extract and manage business data using Google Maps Scraper (and other mentioned tools)\n' while adhering to the structure, ISO country code standards, and ethical handling of information.\n"}},"typeVersion":1.8},{"id":"8469f6f8-e56e-433f-8439-ac0f568b01b1","name":"GPT-4o - Generate & Process Requests","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-360,160],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"6h3DfVhNPw9I25nO","name":"OpenAi account"}},"typeVersion":1.2},{"id":"8f89996c-f5d1-48e3-8023-9c5d4c8db12a","name":"Memory - Track Recent Context","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-180,160],"parameters":{"contextWindowLength":50},"typeVersion":1.3},{"id":"ef32b577-47a2-489f-8b5a-3640126a0ff9","name":"Tool - Scrape Google Maps Business Data","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[160,160],"parameters":{"name":"extract_google_maps","workflowId":{"__rl":true,"mode":"list","value":"9rD7iD6sbXqDX44S","cachedResultName":"Google Maps - sous 1 - Extract Google maps"},"description":"Extract data from hundreds of places fast. Scrape Google Maps by keyword, category, location, URLs & other filters. Get addresses, contact info, opening hours, popular times, prices, menus & more. Export scraped data, run the scraper via API, schedule and monitor runs, or integrate with other tools.","workflowInputs":{"value":{"city":"={{ $fromAI('city', ``, 'string') }}","search":"={{ $fromAI('search', ``, 'string') }}","countryCode":"={{ $fromAI('countryCode', ``, 'string') }}","state/county":"={{ $fromAI('state_county', ``, 'string') }}"},"schema":[{"id":"search","type":"string","display":true,"required":false,"displayName":"search","defaultMatch":false,"canBeUsedToMatch":true},{"id":"city","type":"string","display":true,"required":false,"displayName":"city","defaultMatch":false,"canBeUsedToMatch":true},{"id":"state/county","type":"string","display":true,"required":false,"displayName":"state/county","defaultMatch":false,"canBeUsedToMatch":true},{"id":"countryCode","type":"string","display":true,"removed":false,"required":false,"displayName":"countryCode","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"86a6eafe-9ffc-4d58-85f7-eef7171eeb8e","name":"Fallback - Enrich with Google Search","type":"@n8n/n8n-nodes-langchain.toolSerpApi","position":[-20,160],"parameters":{"options":{}},"credentials":{"serpApi":{"id":"FlfGC4PlqpLMJYRU","name":"SerpAPI account"}},"typeVersion":1},{"id":"37409653-0409-4f2d-8105-9216f974f6a8","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-780,-200],"parameters":{"width":1300,"height":540,"content":"# AI-Powered Lead Generation Workflow\n\nThis workflow extracts business data from Google Maps and associated websites using an AI agent.\n\n## Dependencies\n- **OpenAI API**\n- **Google Sheets API**\n- **Apify Actors**: Google Maps Scraper \n- **Apify Actors**: Website Content Crawler\n- **SerpAPI**: Used as a fallback to enrich data\n\n## External Setup Guide\n**Notion** : [Guide](https://automatisation.notion.site/GOOGLE-MAPS-SCRAPER-1cc3d6550fd98005a99cea02986e7b05)\n"},"typeVersion":1},{"id":"0b42dfae-49e6-4117-8a5d-d1f396f22dcb","name":"Tool - Crawl Business Website","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[340,160],"parameters":{"name":"Website_Content_Crawler","workflowId":{"__rl":true,"mode":"list","value":"I7KceT8Mg1lW7BW4","cachedResultName":"Google Maps - sous 2 - Extract Google"},"description":"Crawl websites and extract text content to feed AI models, LLM applications, vector databases, or RAG pipelines. The Actor supports rich formatting using Markdown, cleans the HTML, downloads files, and integrates well with 🦜🔗 LangChain, LlamaIndex, and the wider LLM ecosystem.","workflowInputs":{"value":{},"schema":[],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"8a713b20-99e6-4df1-88ce-698ffc3c1e31","name":"Trigger - On Subworkflow Start","type":"n8n-nodes-base.executeWorkflowTrigger","position":[-460,520],"parameters":{"inputSource":"jsonExample","jsonExample":"{\n  \"search\": \"carpenter\",\n  \"city\": \"san francisco\",\n  \"state/county\": \"california\",\n  \"countryCode\": \"us\"\n}"},"typeVersion":1.1},{"id":"59af012d-de3f-4a44-b3ad-e587857b554d","name":"Scrape Google Maps (via Apify)","type":"n8n-nodes-base.httpRequest","position":[-240,520],"parameters":{"url":"https://api.apify.com/v2/acts/2Mdma1N6Fd0y3QEjR/run-sync-get-dataset-items","method":"POST","options":{},"jsonBody":"={\n    \"city\": \"{{ $json.city }}\",\n    \"countryCode\": \"{{ $json.countryCode }}\",\n    \"locationQuery\": \"{{ $json.city }}\",\n    \"maxCrawledPlacesPerSearch\": 5,\n    \"searchStringsArray\": [\n        \"{{ $json.search }}\"\n    ],\n    \"skipClosedPlaces\": false\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"},{"name":"Authorization","value":"Bearer <token>"}]}},"typeVersion":4.2},{"id":"b1c40871-aa57-4b15-9f19-34a07dc6c45f","name":"Save Extracted Data to Google Sheets","type":"n8n-nodes-base.googleSheets","position":[-20,520],"parameters":{"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"","cachedResultUrl":"","cachedResultName":""},"documentId":{"__rl":true,"mode":"id","value":"="}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"679f2af5-0024-4a71-8c04-dcbccc8f00c8","name":"Aggregate Business Listings","type":"n8n-nodes-base.aggregate","position":[200,520],"parameters":{"options":{},"aggregate":"aggregateAllItemData"},"typeVersion":1},{"id":"dff1191a-b9f4-4ba6-ba42-a479fab76a5b","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-780,380],"parameters":{"color":4,"width":1300,"height":440,"content":"# 📍 Google Maps Extractor Subworkflow\n\nThis subworkflow handles business data extraction from Google Maps using the Apify Google Maps Scraper.\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Purpose\n- Automates the collection of business leads based on:\n  - Search term (e.g., plumber, agency)\n  - City and region\n  - ISO 3166 Alpha-2 country code"},"typeVersion":1},{"id":"dd691f9c-15e2-4b4a-a6eb-8765905a2cb4","name":"Scrape Website Content (via Apify)","type":"n8n-nodes-base.httpRequest","position":[-320,1000],"parameters":{"url":"https://api.apify.com/v2/acts/aYG0l9s7dbB7j3gbS/run-sync-get-dataset-items","method":"POST","options":{},"jsonBody":"={\n    \"aggressivePrune\": false,\n    \"clickElementsCssSelector\": \"[aria-expanded=\\\"false\\\"]\",\n    \"clientSideMinChangePercentage\": 15,\n    \"crawlerType\": \"playwright:adaptive\",\n    \"debugLog\": false,\n    \"debugMode\": false,\n    \"expandIframes\": true,\n    \"ignoreCanonicalUrl\": false,\n    \"keepUrlFragments\": false,\n    \"proxyConfiguration\": {\n        \"useApifyProxy\": true\n    },\n    \"readableTextCharThreshold\": 100,\n    \"removeCookieWarnings\": true,\n    \"removeElementsCssSelector\": \"nav, footer, script, style, noscript, svg, img[src^='data:'],\\n[role=\\\"alert\\\"],\\n[role=\\\"banner\\\"],\\n[role=\\\"dialog\\\"],\\n[role=\\\"alertdialog\\\"],\\n[role=\\\"region\\\"][aria-label*=\\\"skip\\\" i],\\n[aria-modal=\\\"true\\\"]\",\n    \"renderingTypeDetectionPercentage\": 10,\n    \"saveFiles\": false,\n    \"saveHtml\": false,\n    \"saveHtmlAsFile\": false,\n    \"saveMarkdown\": true,\n    \"saveScreenshots\": false,\n    \"startUrls\": [\n        {\n            \"url\": \"{{ $json.query }}\",\n            \"method\": \"GET\"\n        }\n    ],\n    \"useSitemaps\": false\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"},{"name":"Authorization","value":"Bearer YOUR_TOKEN_HERE"}]}},"typeVersion":4.2},{"id":"7cc813a7-e1a5-40fe-a76a-3e52438cf2f4","name":"Save Website Data to Google Sheets","type":"n8n-nodes-base.googleSheets","position":[-100,1000],"parameters":{"columns":{"value":{},"schema":[{"id":"url","type":"string","display":true,"removed":false,"required":false,"displayName":"url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"crawl","type":"string","display":true,"removed":false,"required":false,"displayName":"crawl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"metadata","type":"string","display":true,"removed":false,"required":false,"displayName":"metadata","defaultMatch":false,"canBeUsedToMatch":true},{"id":"screenshotUrl","type":"string","display":true,"removed":false,"required":false,"displayName":"screenshotUrl","defaultMatch":false,"canBeUsedToMatch":true},{"id":"text","type":"string","display":true,"removed":false,"required":false,"displayName":"text","defaultMatch":false,"canBeUsedToMatch":true},{"id":"markdown","type":"string","display":true,"removed":false,"required":false,"displayName":"markdown","defaultMatch":false,"canBeUsedToMatch":true},{"id":"debug","type":"string","display":true,"removed":false,"required":false,"displayName":"debug","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"autoMapInputData","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":1886744055,"cachedResultUrl":"https://docs.google.com/spreadsheets/d/1JewfKbdS6gJhVFz0Maz6jpoDxQrByKyy77I5s7UvLD4/edit#gid=1886744055","cachedResultName":"MYWEBBASE"},"documentId":{"__rl":true,"mode":"list","value":"1JewfKbdS6gJhVFz0Maz6jpoDxQrByKyy77I5s7UvLD4","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1JewfKbdS6gJhVFz0Maz6jpoDxQrByKyy77I5s7UvLD4/edit?usp=drivesdk","cachedResultName":"GoogleMaps_LEADS"}},"credentials":{"googleSheetsOAuth2Api":{"id":"51us92xkOlrvArhV","name":"Google Sheets account"}},"typeVersion":4.5},{"id":"6c20b427-48e8-4ba1-885e-7db71406a0db","name":"Aggregate Website Content","type":"n8n-nodes-base.aggregate","position":[120,1000],"parameters":{"options":{},"aggregate":"aggregateAllItemData"},"typeVersion":1},{"id":"7b1ff556-f212-4ab5-9995-deeb83f68da4","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-780,860],"parameters":{"color":5,"width":1300,"height":400,"content":"# 🌐 Website Content Crawler Subworkflow\n\nThis subworkflow processes URLs to extract readable website content using Apify's Website Content Crawler.\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## Purpose\n- Extracts detailed and structured content from business websites.\n- Enhances leads with enriched, on-site information."},"typeVersion":1}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"fd75b3e6-1dba-4e01-8c95-fdd9dd07fac4","connections":{"Memory - Track Recent Context":{"ai_memory":[[{"node":"AI Agent - Lead Collection","type":"ai_memory","index":0}]]},"Tool - Crawl Business Website":{"ai_tool":[[{"node":"AI Agent - Lead Collection","type":"ai_tool","index":0}]]},"Scrape Google Maps (via Apify)":{"main":[[{"node":"Save Extracted Data to Google Sheets","type":"main","index":0}]]},"Trigger - On Subworkflow Start":{"main":[[{"node":"Scrape Google Maps (via Apify)","type":"main","index":0}]]},"Trigger - When User Sends Message":{"main":[[{"node":"AI Agent - Lead Collection","type":"main","index":0}]]},"Save Website Data to Google Sheets":{"main":[[{"node":"Aggregate Website Content","type":"main","index":0}]]},"Scrape Website Content (via Apify)":{"main":[[{"node":"Save Website Data to Google Sheets","type":"main","index":0}]]},"Fallback - Enrich with Google Search":{"ai_tool":[[{"node":"AI Agent - Lead Collection","type":"ai_tool","index":0}]]},"GPT-4o - Generate & Process Requests":{"ai_languageModel":[[{"node":"AI Agent - Lead Collection","type":"ai_languageModel","index":0}]]},"Save Extracted Data to Google Sheets":{"main":[[{"node":"Aggregate Business Listings","type":"main","index":0}]]},"Tool - Scrape Google Maps Business Data":{"ai_tool":[[{"node":"AI Agent - Lead Collection","type":"ai_tool","index":0}]]}}}


name: Scalable Multi-Agent Chat Using @mentions
author_name: Jon Doran
author_username: jondoran
categories: []
created_at: 2025-04-08T12:49:14.252Z
updated_at: 2025-04-08T12:49:14.252Z
url: https://n8n.io/workflows/3473
scraped_at: 2025-07-06 21:16:30
description:
  Summary

  Engage multiple, uniquely configured AI agents (using different models via OpenRouter) in a single conversation. Trigger specific agents with @mentions or let them all respond. Easily scalable by editing simple JSON settings.

  Overview

  This workflow is for users who want to experiment with or utilize multiple AI agents with distinct personalities, instructions, and underlying models within a single chat interface, without complex setup. It solves the problem of managing and interacting with diverse AI assistants simultaneously for tasks like brainstorming, comparative analysis, or role-playing scenarios.

  It enables dynamic conversations with multiple AI assistants simultaneously within a single chat interface. You can:

  Define multiple unique AI agents.
  Configure each agent with its own name, system instructions, and LLM model (via OpenRouter).
  Interact with specific agents using @AgentName mentions.
  Have all agents respond (in random order) if no specific agents are mentioned.
  Maintain conversation history across multiple turns.

  It's designed for flexibility and scalability, allowing you to easily add or modify agents without complex workflow restructuring.

  Key Features

  Multi-Agent Interaction:** Chat with several distinct AI personalities at once.
  Individual Agent Configuration:** Customize name, system prompt, and LLM for each agent.
  OpenRouter Integration:** Access a wide variety of LLMs compatible with OpenRouter.
  Mention-Based Triggering:** Direct messages to specific agents using @AgentName.
  All-Agent Fallback:** Engages all defined agents randomly if no mentions are used.
  Scalable Setup:** Agent configuration is centralized in a single Code node (as JSON).
  Conversation Memory:** Remembers previous interactions within the session.

  How to Set Up

  Configure Settings (Code Nodes):
      Open the Define Global Settings Code node: Edit the JSON to set user details (name, location, notes) and add any system message instructions that all agents should follow.
      Open the Define Agent Settings Code node: Edit the JSON to define your agents. Add or remove agent objects as needed. For each agent, specify:
          "name": The unique name for the agent (used for @mentions).
          "model": The OpenRouter model identifier (e.g., "openai/gpt-4o", "anthropic/claude-3.7-sonnet").
          "systemMessage": Specific instructions or persona for this agent.
  Add OpenRouter Credentials:
      Locate the AI Agent node.
      Click the OpenRouter Chat Model node connected below it via the Language Model input.
      In the 'Credential for OpenRouter API' field, select or create your OpenRouter API credentials.

  How to Use

  Start a conversation using the Chat Trigger input.
  To address specific agents, include @AgentName in your message. Agents will respond sequentially in the order they are mentioned.
      Example: "@Gemma @Claude, please continue the count: 1" will trigger Gemma first, followed by Claude.
  If your message contains no @mentions, all agents defined in Define Agent Settings will respond in a randomized order.
      Example: "What are your thoughts on the future of AI?" will trigger Chad, Claude, and Gemma (based on your default settings) in a random sequence.
  The workflow will collect responses from all triggered agents and return them as a single, formatted message.

  How It Works (Technical Details)

  Settings Nodes: Define Global Settings and Define Agent Settings load your configurations.
  Mention Extraction: The Extract mentions Code node parses the user's input (chatInput) from the When chat message received trigger. It looks for @AgentName patterns matching the names defined in Define Agent Settings.
  Agent Selection:
      If mentions are found, it creates a list of the corresponding agent configurations in the order they were mentioned.
      If no mentions are found, it creates a list of all defined agent configurations and shuffles them randomly.
  Looping: The Loop Over Items node iterates through the selected agent list.
  Dynamic Agent Execution: Inside the loop:
      An If node (First loop?) checks if it's the first agent responding. If yes (true path -&gt; Set user message as input), it passes the original user message to the Agent. If no (false path -&gt; Set last Assistant message as input), it passes the previous agent's formatted output (lastAssistantMessage) to the next agent, creating a sequential chain.
      The AI Agent node receives the input message. Its System Message and the Model in the connected OpenRouter Chat Model node are dynamically populated using expressions referencing the current agent's data from the loop ({{ $('Loop Over Items').item.json.* }}).
      The Simple Memory node provides conversation history to the AI Agent.
      The agent's response is formatted (e.g., AgentName:\n\nResponse) in the Set lastAssistantMessage node.
  Response Aggregation: After the loop finishes, the Combine and format responses Code node gathers all the lastAssistantMessage outputs and joins them into a single text block, separated by horizontal rules (---), ready to be sent back to the user.

  Benefits

  Scalability & Flexibility:** Instead of complex branching logic, adding, removing, or modifying agents only requires editing simple JSON in the Define Agent Settings node, making setup and maintenance significantly easier, especially for those managing multiple assistants.
  Model Choice:** Use the best model for each agent's specific task or persona via OpenRouter.
  Centralized Configuration:** Keeps agent setup tidy and manageable.

  Limitations

  Sequential Responses:** Agents respond one after another based on mention order (or randomly), not in parallel.
  No Direct Agent-to-Agent Interaction (within a turn):* Agents cannot directly call or reply to each other *during the processing of a single user message. Agent B sees Agent A's response only because the workflow passes it as input in the next loop iteration.
  Delayed Output:* The user receives the combined response only *after all triggered agents have completed their generation.

nodes_used:
  ["n8n-nodes-base.code","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.lmChatOpenRouter"]

workflow_json:
  {"id":"0QQxgdQABUbbDJ0G","meta":{"instanceId":"c98909b50b05c4069bd93ee5a4753d07322c9680e81da8568e96de2c713adb5c"},"name":"Multi-Agent Conversation","tags":[],"nodes":[{"id":"218308e2-dc68-43ee-ae84-d931ad7a4ac5","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-1880,-3280],"webhookId":"a74752f3-419a-4510-856f-3efeaceec019","parameters":{"options":{}},"typeVersion":1.1},{"id":"a519fe1e-8739-46e0-9770-deb256ab96cf","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-340,-3280],"parameters":{"text":"={{ $json.chatInput }}","options":{"systemMessage":"=Current date is {{ $now.format('yyyy-MM-dd') }}. The current time is {{ $now.format('HH:MM:ss') }}.\n\nThe user is {{ $('Define Global Settings').item.json.user.name }}, based in {{ $('Define Global Settings').item.json.user.location }}. {{ $('Define Global Settings').item.json.user.notes }}\n\nYou are part of a conversation with a user and multiple AI Assistants: {{ $('Define Agent Settings').item.json.keys() }}\n\nYou are {{ $('First loop?').item.json.name }}.\n\n{{ $('Loop Over Items').item.json.systemMessage }}\n\n{{ $('Define Global Settings').item.json.global.systemMessage }}"},"promptType":"define"},"typeVersion":1.8},{"id":"2e00f0ff-e7af-45d5-99bc-23031b5d7892","name":"Loop Over Items","type":"n8n-nodes-base.splitInBatches","position":[-1000,-3280],"parameters":{"options":{}},"typeVersion":3},{"id":"1c979a20-46a5-4591-92da-82c1c96277c6","name":"Extract mentions","type":"n8n-nodes-base.code","position":[-1220,-3280],"parameters":{"jsCode":"// Analyzes the user message and extracts @mentions in the order they appear. If there are none, all Assistants will be called in random order.\n// --- Configuration: Adjust these lines ---\nconst chatMessageNodeName = 'When chat message received'; // <-- Replace with your Chat Message node name\nconst agentSetupNodeName = 'Define Agent Settings';         // <-- Replace with your Agent Setup node name\nconst chatTextPath = 'json.chatInput';               // <-- Replace with path to text in Chat node output (e.g., 'json.message')\n// --- End Configuration ---\n\n// Helper function for safe nested property access (alternative to _.get)\nfunction getSafe(obj, path, defaultValue = undefined) {\n    const pathParts = path.split('.');\n    let current = obj;\n    for (const part of pathParts) {\n        if (current === null || current === undefined || typeof current !== 'object' || !Object.prototype.hasOwnProperty.call(current, part)) {\n            return defaultValue;\n        }\n        current = current[part];\n    }\n    return current ?? defaultValue;\n}\n\n// 1. Get Chat Text\nconst chatMessageNode = $(chatMessageNodeName);\nconst chatText = getSafe(chatMessageNode.item, chatTextPath, '');\n\n// 2. Get Agent Data and Names\nconst agentSetupNode = $(agentSetupNodeName);\nconst agentData = getSafe(agentSetupNode.item, 'json', {}); // e.g., { Chad: {...}, Gemma: {...}, Claude: {...} }\nconst agentNames = Object.keys(agentData);\n\n// 3. Find all mentions, their names, and their positions in the text\nconst foundMentions = [];\nif (chatText && agentNames.length > 0) {\n    const escapeRegex = (s) => s.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n    const agentPatternPart = agentNames.map(escapeRegex).join('|');\n\n    if (agentPatternPart) {\n        const mentionPattern = new RegExp(`\\\\B@(${agentPatternPart})\\\\b`, 'gi');\n        const matches = chatText.matchAll(mentionPattern);\n\n        for (const match of matches) {\n            const matchedNameCaseInsensitive = match[1];\n            const matchIndex = match.index;\n            const canonicalName = agentNames.find(name => name.toLowerCase() === matchedNameCaseInsensitive.toLowerCase());\n            if (canonicalName) {\n                foundMentions.push({ name: canonicalName, index: matchIndex });\n            }\n        }\n    }\n}\n\n// 4. Sort the found mentions by their index (order of appearance)\nfoundMentions.sort((a, b) => a.index - b.index);\n\n// 5. Map the sorted mentions to the desired output format (array of agent detail objects)\nlet outputArray = foundMentions.map(mention => {\n    const agentDetails = agentData[mention.name];\n    if (!agentDetails) {\n        console.warn(`Could not find details for agent: ${mention.name}`);\n        return null;\n    }\n    return {\n        name: agentDetails.name,\n        model: agentDetails.model,\n        systemMessage: agentDetails.systemMessage\n    };\n}).filter(item => item !== null);\n\n// 6. Check if any mentions were specifically found. If not, populate outputArray with ALL agents in RANDOM order.\nif (outputArray.length === 0 && foundMentions.length === 0) { // Check if NO mentions were found initially\n    // --- NO MENTIONS FOUND ---\n    // Populate outputArray with ALL agents from agentData\n    const allAgentDetailsArray = Object.values(agentData);\n\n    // --- Simple Randomization ---\n    // Shuffle the array in place using sort with a random comparator\n    allAgentDetailsArray.sort(() => 0.5 - Math.random());\n    // --- End Randomization ---\n\n    // Map all agents (now in random order) to the output structure\n    outputArray = allAgentDetailsArray.map(agentObject => ({\n        name: agentObject.name,\n        model: agentObject.model,\n        systemMessage: agentObject.systemMessage\n    }));\n} // Intentionally no 'else' here, if outputArray already had items from mentions, we use that.\n\n// 7. Final Output Formatting (Handles both cases: specific mentions OR all agents)\n// Check if, after everything, the outputArray is *still* empty (e.g., if agentData was empty initially)\nif (outputArray.length === 0) {\n    // If still empty, return a status or error as a fallback\n     return [{ json: { status: \"no_agents_available\", message: \"No mentions found and no agents defined.\" } }];\n} else {\n    // Return the array of agent objects formatted for n8n (multiple items)\n    return outputArray.map(agentObject => ({ json: agentObject }));\n}"},"typeVersion":2},{"id":"45f635ca-f4fa-4f6c-a32a-9722906255fd","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-192,-3060],"parameters":{"sessionKey":"={{ $('When chat message received').first().json.sessionId }}","sessionIdType":"customKey","contextWindowLength":99},"typeVersion":1.3},{"id":"5c903044-bce2-4aa8-b168-a460a4999c54","name":"Set last Assistant message as input","type":"n8n-nodes-base.set","position":[-560,-3180],"parameters":{"options":{},"assignments":{"assignments":[{"id":"38aa959a-e1e5-4c84-a7bd-ff5e0f61b62d","name":"=chatInput","type":"string","value":"={{ $('Set lastAssistantMessage').first().json.lastAssistantMessage }}"}]}},"typeVersion":3.4},{"id":"7b389b9f-1751-4bc1-9c6f-bf6a04a1e09f","name":"Set user message as input","type":"n8n-nodes-base.set","position":[-560,-3380],"parameters":{"options":{},"assignments":{"assignments":[{"id":"75b61275-7526-4431-b624-f8e098aa812d","name":"chatInput","type":"string","value":"={{ $('When chat message received').item.json.chatInput }}"}]}},"typeVersion":3.4},{"id":"a238817f-0d10-4cd4-9760-53f69bb179f7","name":"First loop?","type":"n8n-nodes-base.if","position":[-780,-3280],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"51c41fdf-f4d3-4c7a-ac18-06815a59a958","operator":{"type":"number","operation":"equals"},"leftValue":"={{ $runIndex}}","rightValue":0}]}},"typeVersion":2.2},{"id":"415927d7-b1a4-42b2-9607-c6ff707a528b","name":"Set lastAssistantMessage","type":"n8n-nodes-base.set","position":[36,-3155],"parameters":{"options":{},"assignments":{"assignments":[{"id":"b93025b2-f5a7-476b-bd09-b5b4af050e73","name":"lastAssistantMessage","type":"string","value":"=**{{ $('Loop Over Items').item.json.name }}**:\n\n{{ $json.output }}"}]}},"typeVersion":3.4},{"id":"77861e4b-a1d2-4c35-bf50-15914602a8b5","name":"Combine and format responses","type":"n8n-nodes-base.code","position":[-780,-3480],"parameters":{"jsCode":"// Get the array of items from the input (output of the loop)\nconst inputItems = items;\n\n// Extract the 'lastAssistantMessage' from each item's JSON data.\n// If the field is missing or not a string, use an empty string to avoid errors.\nconst messages = inputItems.map(item => {\n  const message = item.json.lastAssistantMessage;\n  return typeof message === 'string' ? message : '';\n});\n\n// Join the extracted messages together with a horizontal rule separator\nconst combinedText = messages.join('\\n\\n---\\n\\n');\n\n// Return a new single item containing the combined text.\n// You can rename 'output' if you like.\nreturn [{ json: { output: combinedText } }];"},"typeVersion":2},{"id":"4da2f95d-bce4-4844-a23c-63ca777efbfd","name":"Define Global Settings","type":"n8n-nodes-base.code","position":[-1660,-3280],"parameters":{"jsCode":"// Configure Global settings. This includes information about you - the user - and a section of the System Message that all Assistants will see. (Assistant-specific System Message sections can be set in the 'Define Agent Settings' node.)\nreturn [\n  {\n    json: {\n      \"user\": {\n        \"name\": \"Jon\",\n        \"location\": \"Melbourne, Australia\",\n        \"notes\": \"Jon likes a casual, informal conversation style.\"\n      },\n      \"global\": {\n        \"systemMessage\": \"Don't overdo the helpful, agreeable approach.\"\n      }\n    }\n  }\n];\n"},"typeVersion":2},{"id":"6639a554-9e5f-40ac-b68e-b8eaa777252d","name":"Define Agent Settings","type":"n8n-nodes-base.code","position":[-1440,-3280],"parameters":{"jsCode":"// Configure Assistants. The number of Assistants can be changed by adding or removing JSON objects. Use the OpenRouter model naming convention.\nreturn [\n  {\n    json: {\n      \"Chad\": {\n        \"name\": \"Chad\",\n        \"model\": \"openai/gpt-4o\",\n        \"systemMessage\": \"You are a helpful Assistant. You are eccentric and creative, and try to take discussions into unexpected territory.\"\n      },\n      \"Claude\": {\n        \"name\": \"Claude\",\n        \"model\": \"anthropic/claude-3.7-sonnet\",\n        \"systemMessage\": \"You are logical and practical.\"\n      },\n      \"Gemma\": {\n        \"name\": \"Gemma\",\n        \"model\": \"google/gemini-2.0-flash-lite-001\",\n        \"systemMessage\": \"You are super friendly and love to debate.\"\n      }\n    }\n  }\n];\n"},"typeVersion":2},{"id":"d55a7e02-3574-4d78-a141-db8d3657857b","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1750,-3620],"parameters":{"color":4,"width":500,"height":500,"content":"## Step 1: Configure Settings Nodes\n\nEdit the JSON in these nodes to:\n\n- Configure details about you (the user)\n- Define content that will appear in all system messages\n- Define Agents.\n\nFor Agents, you can configure:\n- How many you create\n- Their names\n- The LLM model they use (choose any that are available via OpenRouter)\n- Agent-specific system prompt content"},"typeVersion":1},{"id":"d3eb2797-4008-4bdb-a588-b2412ed5ffa7","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-400,-3620],"parameters":{"color":4,"width":360,"height":720,"content":"## Step 2: Connect Agent to OpenRouter\n\nSet your OpenRouter credentials, and all other parameters including system messages and model selection are dynamically populated."},"typeVersion":1},{"id":"a6085a55-db36-42d8-8c57-c9123490581f","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-1940,-3900],"parameters":{"color":5,"width":2180,"height":1100,"content":"# Scalable Multi-Agent Conversations\n\n"},"typeVersion":1},{"id":"d2ee6317-3a9c-4df8-8fce-87daa3530233","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-1200,-3860],"parameters":{"width":380,"height":360,"content":"## About this workflow\n\n**What does this workflow do?**\nEnables you to initiate a conversation with multiple AI agents at once. Each agent can be configured with a unique name, system instructions, a different model.\n\n**How do I use it?**\n1. Configure the settings nodes to create the Agents you need.\n2. Call one or more individual agents using @Name mentions in your messages. If your message does not have @mentions, all agents will be called, in random order."},"typeVersion":1},{"id":"a190a268-7f90-4c4e-aceb-482545d0b72b","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-820,-3860],"parameters":{"width":380,"height":360,"content":"**How does it work?**\nSettings are configured in the first two nodes after the chat trigger. Then @mentions in your message are extracted and fed into a loop. With each loop, the agent's system message and model are dynamically populated, avoiding the need to create multiple agent nodes and complex routing logic.\n\nWhen all agents have had their say, their responses are combined and formatted. The use of a shared memory node enables multi-round conversations.\n\n**What are the limitations?**\nAgents cannot call each other or respond in parallel. Agents' responses are not visible to the user until all agents have responded.\n\n"},"typeVersion":1},{"id":"30d8c207-9a7a-46c5-be89-0deafc6c183f","name":"OpenRouter Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[-312,-3060],"parameters":{"model":"={{ $('Extract mentions').item.json.model }}","options":{}},"credentials":{"openRouterApi":{"id":"jB56IT6KRdHSBbkw","name":"OpenRouter account"}},"typeVersion":1}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"6c0312e7-7a81-41cd-9403-8ad947100b80","connections":{"AI Agent":{"main":[[{"node":"Set lastAssistantMessage","type":"main","index":0}]]},"First loop?":{"main":[[{"node":"Set user message as input","type":"main","index":0}],[{"node":"Set last Assistant message as input","type":"main","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"Loop Over Items":{"main":[[{"node":"Combine and format responses","type":"main","index":0}],[{"node":"First loop?","type":"main","index":0}]]},"Extract mentions":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Define Agent Settings":{"main":[[{"node":"Extract mentions","type":"main","index":0}]]},"OpenRouter Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"Define Global Settings":{"main":[[{"node":"Define Agent Settings","type":"main","index":0}]]},"Set lastAssistantMessage":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Set user message as input":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"When chat message received":{"main":[[{"node":"Define Global Settings","type":"main","index":0}]]},"Combine and format responses":{"main":[[]]},"Set last Assistant message as input":{"main":[[{"node":"AI Agent","type":"main","index":0}]]}}}


name: Automated LinkedIn Profile Discovery with Airtop and Google Search
author_name: Airtop
author_username: cesar-at-airtop
nodes_used: ["n8n-nodes-base.googleSheets","n8n-nodes-base.code","n8n-nodes-base.airtop"]
categories: []
created_at: 2025-04-08T17:36:04.378Z
updated_at: 2025-04-08T17:36:04.378Z
url: https://n8n.io/workflows/3477
scraped_at: 2025-07-06 21:16:30
description:
  About The LinkedIn Profile Discovery Automation

  Are you tired of manually searching for LinkedIn profiles or paying expensive data providers for often outdated information? If you spend countless hours trying to find accurate LinkedIn URLs for your prospects or candidates, this automation will change your workflow forever. Just give this workflow the information you have about a contact, and it will automatically augment it with a LinkedIn profile.

  How to find a LinkedIn Profile Link

  In this guide, you'll learn how to automate LinkedIn profile link discovery using Airtop's built-in node in n8n. Using this automation, you'll have a fully automated workflow that saves you hours of manual searching while providing accurate, validated LinkedIn URLs.

  What You'll Need

  A free Airtop API key
  A Google Workspace account. If you have a Gmail account, you’re all set
  Estimated setup time: 10 minutes

  Understanding the Process

  This automation leverages the power of intelligent search algorithms combined with LinkedIn validation to ensure accuracy. Here's how it works:

  Takes your input data (name, company, etc.) and constructs intelligent search queries
  Utilizes Google search to identify potential LinkedIn profile URLs
  Validates the discovered URLs directly against LinkedIn to ensure accuracy
  Returns confirmed, accurate LinkedIn profile URLs

  Setting Up Your Automation

  Getting started with this automation is straightforward:

  Prepare Your Google Sheet

  Create a new Google Sheet with columns for input data (name, company, domain, etc.)
  Add columns for the output LinkedIn URL and validation status (see this example)

  Configure the Automation

  Connect your Google Workspace account to n8n if you haven't already
  Add your Airtop API credentials
  (Optionally) Configure your Airtop Profile and sign-in to LinkedIn in order to validate profile URL's

  Run Your First Test

  Add a few test entries to your Google Sheet
  Run the workflow
  Check the results in your output columns

  Customization Options

  While the default setup uses Google Sheets, this automation is highly flexible:

  Webhook Integration**: Perfect for integrating with tools like Clay, Instantly, or your custom applications
  Alternatives**: Replace Google Sheets with Airtable, Notion, or any other tools you already use for more robust database capabilities
  Custom Output Formatting**: Modify the output structure to match your existing systems
  Batch Processing**: Configure for bulk processing of multiple profiles

  Real-World Applications

  This automation has the potential to transform how we organizations handle profile enrichment.

  Recruiting Firm Success Story

  With this automation, a recruiting firm could save hundreds of dollars a month in data enrichment fees, achieve better accuracy, and eliminate subscription costs. They would also be able to process thousands of profiles weekly with near-perfect accuracy.

  Sales Team Integration

  A B2B sales team could integrate this automation with their CRM, automatically enriching new leads with validated LinkedIn profiles and saving their SDRs hours per week on manual research.

  Best Practices

  To maximize the accuracy of your results:

  Always include company information (domain or company name) with your search queries
  Use full names rather than nicknames or initials when possible
  Consider including location data for more accurate results with common names
  Implement rate limiting to respect LinkedIn's usage guidelines
  Keep your input data clean and standardized for best results
  Use the integrated proxy to navigate more effectively through Google and LinkedIn

  What's Next?

  Now that you've automated LinkedIn profile discovery, consider exploring related automations:

  Automated lead scoring based on LinkedIn profile data
  Email finder automation using validated LinkedIn profiles
  Integration with your CRM for automated contact enrichment

workflow_json:
  {"id":"lifB7iUXlDzr5dmI","meta":{"instanceId":"660cf2c29eb19fa42319afac3bd2a4a74c6354b7c006403f6cba388968b63f5d","templateCredsSetupCompleted":true},"name":"LinkedIn Profile Discovery","tags":[{"id":"a8B9vqj0vNLXcKVQ","name":"template","createdAt":"2025-04-04T15:38:37.785Z","updatedAt":"2025-04-04T15:38:37.785Z"}],"nodes":[{"id":"9ae64a3a-c7e7-45ca-88ee-ebf6144f3197","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[0,0],"parameters":{},"typeVersion":1},{"id":"a22416bb-ef9e-422f-b480-cd52d8c93bfa","name":"Person info","type":"n8n-nodes-base.googleSheets","position":[220,0],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E/edit?usp=drivesdk","cachedResultName":"Linkedin Profile URLs"}},"credentials":{"googleSheetsOAuth2Api":{"id":"CwpCAR1HwgHZpRtJ","name":"Google Drive"}},"typeVersion":4.5},{"id":"a4699dd8-54ef-478e-9ff8-2c2046ad6ea8","name":"Search profile","type":"n8n-nodes-base.airtop","notes":"This could take a few minutes depending on the number of rows","position":[440,0],"parameters":{"url":"=https://www.google.com/search?q={{ encodeURI($json['Person Info']) }}","prompt":"=This is Google Search results. the first results should be the Linkedin Page of {{ $json['Person Info'] }} \nReturn the Linkedin URL and nothing else.\nIf you cannot find the Linkedin URL, return an empty string. \nA valid Linkedin profile URL starts with \"https://www.linkedin.com/in/\"","resource":"extraction","operation":"query","sessionMode":"new","additionalFields":{}},"credentials":{"airtopApi":{"id":"byhouJF8RLH5DkmY","name":"Airtop"}},"notesInFlow":true,"typeVersion":1},{"id":"2dd4d350-743e-48a7-ab69-d0996bc46f49","name":"Parse response","type":"n8n-nodes-base.code","position":[660,0],"parameters":{"mode":"runOnceForEachItem","jsCode":"const linkedInProfile = $json.data.modelResponse\nconst rowData = $('Person info').item.json\n\nreturn { json: {\n  ...rowData,\n  'LinkedIn URL': linkedInProfile\n}};"},"typeVersion":2},{"id":"3efc182a-8707-4c8d-8263-a2aebe62b0a7","name":"Update row","type":"n8n-nodes-base.googleSheets","position":[880,0],"parameters":{"columns":{"value":{},"schema":[{"id":"Person Info","type":"string","display":true,"required":false,"displayName":"Person Info","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Linkedin URL","type":"string","display":true,"required":false,"displayName":"Linkedin URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Validated","type":"string","display":true,"required":false,"displayName":"Validated","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":false,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"autoMapInputData","matchingColumns":["row_number"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1rjlKzphEbknNh_ToS9pR_dP_Tw93FsxDte5AI4LH5_E/edit?usp=drivesdk","cachedResultName":"Linkedin Profile URLs"}},"credentials":{"googleSheetsOAuth2Api":{"id":"CwpCAR1HwgHZpRtJ","name":"Google Drive"}},"typeVersion":4.5}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"97cd5141-63d5-4ece-83eb-e544455097d3","connections":{"Person info":{"main":[[{"node":"Search profile","type":"main","index":0}]]},"Parse response":{"main":[[{"node":"Update row","type":"main","index":0}]]},"Search profile":{"main":[[{"node":"Parse response","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Person info","type":"main","index":0}]]}}}


name: Automated LinkedIn Lead Generation, Scoring & Communication with AI-Agent
author_name: Andrey
author_username: kulia
categories: []
created_at: 2025-04-08T23:40:26.853Z
updated_at: 2025-04-08T23:40:26.853Z
url: https://n8n.io/workflows/3490
scraped_at: 2025-07-06 21:16:30
description:
  ⚠️ DISCLAIMER: This workflow uses the HDW LinkedIn community node, which is only available on self-hosted n8n instances. It will not work on n8n.cloud.

  Overview

  This workflow automates the entire LinkedIn lead generation process from finding prospects that match your Ideal Customer Profile (ICP) to sending personalized messages. It uses AI to analyze lead data, score potential clients, and prioritize your outreach efforts.

  Key Features

  AI-Driven Lead Generation**: Convert ICP descriptions into LinkedIn search parameters
  Comprehensive Data Enrichment**: Analyze company websites, LinkedIn posts, and news
  Intelligent Lead Scoring**: Prioritize leads based on AI analysis of intent signals
  Automated Outreach**: Connect with prospects and send personalized messages

  Requirements

  Self-hosted n8n instance with the HDW LinkedIn community node installed
  OpenAI API access (for GPT-4o)
  Google Sheets access
  HDW API key (available at app.horizondatawave.ai)
  LinkedIn account

  Setup Instructions

  1. Install Required Nodes

  Ensure the HDW LinkedIn community node is installed on your n8n instance
  Command: npm install n8n-nodes-hdw
  (or use this instruction)

  2. Configure Credentials

  OpenAI**: Add your OpenAI API key
  Google Sheets**: Set up Google account access
  HDW LinkedIn**: Configure your API key from horizondatawave.ai

  3. Set Up Google Sheet

  Create a new Google Sheet with the following columns (or copy template):
    Name, URN, URL, Headline, Location, Current company, Industry, etc.
    The workflow will populate these columns automatically

  4. Customize Your ICP

  Use chat to provide the AI Agent with your Ideal Customer Profile
  Example: "Target marketing directors at SaaS companies with 50-200 employees"

  5. Adjust Scoring Criteria

  Modify the lead scoring prompt in the "Company Score Analysis" node to match your specific product/service
  Tune the evaluation criteria based on your unique business needs

  6. Configure Message Templates

  Update the HDW LinkedIn Send Message node with your custom message

  How It Works

  ICP Translation: AI converts your ICP description into LinkedIn search parameters
  Lead Discovery: Workflow searches LinkedIn using these parameters
  Data Collection: Results are saved to Google Sheets
  Enrichment: System collects additional data about each lead:
     Company website analysis
     Lead's LinkedIn posts
     Company's LinkedIn posts
     Recent company news
  Intent Analysis: AI analyzes all data to identify buying signals
  Lead Scoring: Leads are scored on a 1-10 scale based on likelihood of interest
  Connection Requests: Top-scoring leads receive connection requests
  Follow-Up: When connections are accepted, automated messages are sent

  Customization

  Search Parameters**: Adjust the AI Agent prompt to refine your target audience
  Scoring Criteria**: Modify scoring prompts to highlight indicators relevant to your product
  Message Content**: Update message templates for personalized outreach
  Schedule**: Configure when connection requests and messages are sent

  Rate Limits & Best Practices

  LinkedIn has connection request limits (approximately 100-200 per week)
  The workflow includes safeguards to avoid exceeding these limits
  Consider spacing your outreach for better response rates

  Note: Always use automation tools responsibly and in accordance with LinkedIn's terms of service.

nodes_used:
  ["n8n-nodes-base.googleSheets","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.chainLlm","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.openAi"]

workflow_json:
  {"id":"orrlMUaAvSsvAOgm","meta":{"instanceId":"9bce59fa408e249dab636faffc5a13e5aa1a2e4af3383a551051e8bd22b2a1b9","templateCredsSetupCompleted":true},"name":"HDW Lead Geländewagen","tags":[],"nodes":[{"id":"bd3fe9aa-d16e-4ee8-a2c9-8ac2e0a98c66","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-2320,1260],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1","cachedResultName":"gpt-4.1"},"options":{}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"typeVersion":1.2},{"id":"e4f4a3df-1544-4afa-9aae-81f17d642f95","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","notes":"For changing limits use \"count\"","position":[-2120,1260],"parameters":{"jsonSchemaExample":"[\n  {\n    \"salesNavigatorParams\": {\n      \"current_titles\": \"title1\",\n      \"current_companies\": \"company1\",\n      \"location\": \"location1\",\n      \"industry\": \"industry1\",\n      \"company_sizes\": [\n        \"Self-employed\",\n        \"1-10\",\n        \"11-50\",\n        \"51-200\",\n        \"201-500\",\n        \"501-1,000\",\n        \"1,001-5,000\",\n        \"5,001-10,000\",\n        \"10,001+\"\n      ]\n    },\n    \"count\": 10\n  },\n  {\n    \"salesNavigatorParams\": {\n      \"current_titles\": \"title2\",\n      \"current_companies\": \"company2\",\n      \"location\": \"location2\",\n      \"industry\": \"industry2\",\n      \"company_sizes\": [\n        \"Self-employed\",\n        \"1-10\",\n        \"11-50\",\n        \"51-200\",\n        \"201-500\",\n        \"501-1,000\",\n        \"1,001-5,000\",\n        \"5,001-10,000\",\n        \"10,001+\"\n      ]\n    },\n    \"count\": 10\n  }\n]"},"notesInFlow":true,"typeVersion":1.2},{"id":"3084f957-886b-466a-96d1-2918b9448c63","name":"Google Sheets2","type":"n8n-nodes-base.googleSheets","position":[-400,2080],"parameters":{"columns":{"value":{"URN":"={{ $('Read companies').item.json.URN }}","Website":"={{ $json.website }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Lead Score","type":"string","display":true,"removed":true,"required":false,"displayName":"Lead Score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Contact Request","type":"string","display":true,"removed":true,"required":false,"displayName":"Contact Request","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Connected","type":"string","display":true,"removed":true,"required":false,"displayName":"Connected","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Message Sent","type":"string","display":true,"removed":true,"required":false,"displayName":"Message Sent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"a64188c8-f976-41e5-a8e5-b49e3c50e458","name":"Loop Over Items","type":"n8n-nodes-base.splitInBatches","position":[-900,1680],"parameters":{"options":{"reset":false}},"retryOnFail":true,"typeVersion":3},{"id":"d5cd8de3-b1ec-442d-a026-9adc411b8b49","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-2400,540],"parameters":{"color":4,"width":1320,"content":"Find leads in LinkedIn"},"typeVersion":1},{"id":"f9b7b200-4dec-43ee-8e00-e60914f1949d","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-1020,540],"parameters":{"color":4,"width":980,"content":"Get company website "},"typeVersion":1},{"id":"3d2e343a-a81c-4754-a852-c43d7f592417","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[0,0],"parameters":{"color":4,"width":1520,"content":"Research company website"},"typeVersion":1},{"id":"1c9b4718-bd53-4c3f-b94c-371adea118c1","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1560,540],"parameters":{"color":4,"width":980,"content":"Score data"},"typeVersion":1},{"id":"6c3b801e-838e-4c03-9f04-b7c27bb9cd59","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[2580,540],"parameters":{"color":4,"width":1860,"content":"Communicate with leads"},"typeVersion":1},{"id":"412f6d55-6d36-4602-b6db-ae5c449602e3","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[0,180],"parameters":{"color":4,"width":1520,"content":"Research lead LN post"},"typeVersion":1},{"id":"ed07b5b5-4b36-4cff-9dd4-150a8378967b","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[0,540],"parameters":{"color":4,"width":1520,"content":"Research company LN post"},"typeVersion":1},{"id":"8199980a-42d2-414a-a387-8faab1193a5c","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[0,360],"parameters":{"color":4,"width":1520,"content":"Research company News"},"typeVersion":1},{"id":"bde206ab-617e-425f-9cd9-df4da03c7146","name":"HDW LinkedIn SN","type":"n8n-nodes-hdw.hdwLinkedin","onError":"continueRegularOutput","position":[-1800,1060],"parameters":{"count":"={{ $json.output.count }}","keywords":"={{ $json.output.salesNavigatorParams.keywords }}","resource":"search","additionalFilters":{"industry":"={{ $json.output.salesNavigatorParams.industry }}","location":"={{ $json.output.salesNavigatorParams.location }}","company_sizes":"={{ $json.output.salesNavigatorParams.company_sizes }}","current_titles":"={{ $json.output.salesNavigatorParams.current_titles }}","company_keyword":"={{ $json.output.salesNavigatorParams.current_companies }}"}},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"alwaysOutputData":false},{"id":"79da9bcd-01df-41a3-9627-dff9ac226e3a","name":"HDW Get Company Website","type":"n8n-nodes-hdw.hdwLinkedin","onError":"continueRegularOutput","position":[-540,1940],"parameters":{"company":"={{ $json[\"Company URN\"] }}","resource":"company"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"notesInFlow":true,"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"d6263cff-7a21-462a-81a4-e09dfacc10a4","name":"Google Sheets3","type":"n8n-nodes-base.googleSheets","position":[20,880],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"719377c5-150f-4819-968a-b69d75eb70ad","name":"Loop Over Items1","type":"n8n-nodes-base.splitInBatches","position":[540,860],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"0d88ce35-4fa3-4cef-87ef-23f6992e1855","name":"Google Sheets4","type":"n8n-nodes-base.googleSheets","position":[40,1420],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"cd54b602-8fbc-4b29-869f-e2fcec4e1fbd","name":"HDW Get User Posts","type":"n8n-nodes-hdw.hdwLinkedin","position":[680,1460],"parameters":{"urn":"={{ $('Post summary is empty').item.json.URN }}","operation":"getPosts"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"alwaysOutputData":true},{"id":"69135673-0acc-43a1-bdb9-9b927839d896","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[860,1460],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"text"},{"renameField":true,"outputFieldName":"repost","fieldToAggregate":"repost.text"}]}},"retryOnFail":true,"typeVersion":1,"alwaysOutputData":true},{"id":"499a0e1f-d0f2-49f3-9f76-b6c8e8a6f11c","name":"Loop Over Items2","type":"n8n-nodes-base.splitInBatches","position":[520,1300],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"afbd8a72-e766-4ce1-8231-6ea3b75389fd","name":"Google Sheets5","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[1360,1460],"parameters":{"columns":{"value":{"URN":"={{ $('Post summary is empty').item.json.URN }}","Posts summary":"={{ $json.message.content }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":false,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"6c540033-4a12-4980-aa03-0e2129b3477d","name":"Google Sheets6","type":"n8n-nodes-base.googleSheets","position":[40,1880],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"8b356508-c494-421c-a88d-83f3f7808d99","name":"Aggregate1","type":"n8n-nodes-base.aggregate","position":[860,1880],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"description"}]}},"typeVersion":1},{"id":"3c9bb26b-ce71-4625-a472-c3008bbd1bbf","name":"Loop Over Items3","type":"n8n-nodes-base.splitInBatches","position":[520,1720],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"fa18d1f6-545d-43d4-a6e2-27bb634d1681","name":"Google Sheets7","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[1380,1880],"parameters":{"columns":{"value":{"URN":"={{ $('Company news is empty').item.json.URN }}","Company News":"={{ $json.message.content }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":false,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"d8d6941c-8e43-4bb2-8767-86b211a08e34","name":"Google Sheets8","type":"n8n-nodes-base.googleSheets","position":[40,2380],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"111ce09c-7635-4496-ab85-bcd575c244d5","name":"Aggregate2","type":"n8n-nodes-base.aggregate","position":[860,2380],"parameters":{"options":{},"fieldsToAggregate":{"fieldToAggregate":[{"fieldToAggregate":"text"}]}},"typeVersion":1},{"id":"8f26f598-e6b4-45be-bc9a-a47315fcdfe3","name":"Loop Over Items4","type":"n8n-nodes-base.splitInBatches","position":[520,2240],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"d39d0bcd-a36a-4310-b13b-65f4ebf0e5d2","name":"Google Sheets9","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[1380,2380],"parameters":{"columns":{"value":{"URN":"={{ $('Company post is empty').item.json.URN }}","Company post summary":"={{ $('Summarise company posts').item.json.message.content }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":false,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"8cfb6af5-6360-4440-b1a6-598eb443c8f5","name":"HDW Get Company News","type":"n8n-nodes-hdw.hdwLinkedin","position":[680,1880],"parameters":{"query":"={{ $('Company news is empty').item.json[\"Current company\"] }} (news OR press OR announcement OR update)","resource":"google","operation":"googleSearch"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"alwaysOutputData":true},{"id":"2f7b9aaf-1fe1-45f9-a63e-34b8a8a2658c","name":"HDW Get Company Posts","type":"n8n-nodes-hdw.hdwLinkedin","onError":"continueRegularOutput","position":[680,2380],"parameters":{"urn":"={{ $('Google Sheets8').item.json[\"Company URN\"] }}","resource":"company","operation":"getCompanyPosts"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"alwaysOutputData":true},{"id":"efc019e2-5439-44bc-907b-b77e05833a7c","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[-1980,1060],"parameters":{"include":"allOtherFields","options":{},"fieldToSplitOut":"output"},"retryOnFail":true,"typeVersion":1},{"id":"89c665d7-0d0c-47ce-9e74-780a57ef582e","name":"OpenAI Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[740,1120],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"gpt-4o"},"options":{}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"typeVersion":1.2},{"id":"920fe0db-bef0-4f78-a793-e406565df11a","name":"Google Sheets10","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[1340,860],"parameters":{"columns":{"value":{"URN":"={{ $('Website is not empty').item.json.URN }}","Product Summary":"={{ $json.output }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":false,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"402b88d8-1f0c-4a13-b93f-242703a3861e","name":"HDW Site-map","type":"n8n-nodes-hdw.hdwWebParserTool","position":[1060,1120],"parameters":{"url":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('URL', `use company url to get a site-map`, 'string') }}","operation":"map","descriptionType":"manual","toolDescription":"Get sitemap by url"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"typeVersion":1},{"id":"37e1f633-6e14-4ab0-a205-cdc5e88b3b7d","name":"HDW Parser","type":"n8n-nodes-hdw.hdwWebParserTool","position":[1220,1120],"parameters":{"url":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('URL', ``, 'string') }}","descriptionType":"manual","toolDescription":"Parse info from website by url"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"typeVersion":1},{"id":"91cd0c40-4f6e-417c-9139-7479ed306808","name":"Summarise user posts","type":"@n8n/n8n-nodes-langchain.openAi","position":[1020,1460],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"content":"=Make summary of this text:\n {{ $json.text }}\n{{ $json.repost }}"}]}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"retryOnFail":true,"typeVersion":1.8},{"id":"34580e4c-ac3c-48b1-bf3c-c09b4e7b0236","name":"Summarise company news","type":"@n8n/n8n-nodes-langchain.openAi","position":[1040,1880],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"content":"=Make summary of this news:\n{{ $json.description }}"}]}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"retryOnFail":true,"typeVersion":1.8},{"id":"a21ceccb-1e64-4849-a0b2-a74171f672b7","name":"Summarise company posts","type":"@n8n/n8n-nodes-langchain.openAi","position":[1040,2380],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"content":"=Make summary of this company posts:\n{{ $json.text }}"}]}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"retryOnFail":true,"typeVersion":1.8},{"id":"286996d7-510e-495d-95b6-fcfcd4fb15e5","name":"Summarise company website","type":"@n8n/n8n-nodes-langchain.agent","position":[820,860],"parameters":{"text":"=Research company website {{ $json.Website }} and get summary about business and products\n1. Get site-map with the tool\n2. Define what links may contain data about company business and products\n3. Scrape data for every links\n4. Summarize info from website ","options":{},"promptType":"define"},"retryOnFail":true,"typeVersion":1.8},{"id":"c660d9fe-7796-44dd-bed4-aa61f08ca485","name":"Google Sheets11","type":"n8n-nodes-base.googleSheets","position":[1740,1740],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"b9a84c97-b921-44f6-9f76-839237c9ad71","name":"Loop Over Items6","type":"n8n-nodes-base.splitInBatches","position":[2080,1620],"parameters":{"options":{"reset":false}},"retryOnFail":true,"typeVersion":3},{"id":"69a200f9-0ed8-45d7-b338-36b7a6d3dab6","name":"Google Sheets12","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[2580,1740],"parameters":{"columns":{"value":{"URN":"={{ $('Google Sheets11').item.json.URN }}","Lead Score":"={{ $json.message.content }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Lead Score","type":"string","display":true,"removed":false,"required":false,"displayName":"Lead Score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"da054df5-af1d-4433-b382-7b9bd7477e4b","name":"Google Sheets13","type":"n8n-nodes-base.googleSheets","position":[3080,1120],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"6b3e0f6f-c3b6-460c-acca-92b5ff8914c4","name":"Sort","type":"n8n-nodes-base.sort","position":[3300,1120],"parameters":{"options":{},"sortFieldsUi":{"sortField":[{"order":"descending","fieldName":"Lead Score"}]}},"typeVersion":1},{"id":"115e2770-f19f-4796-943b-293e6be14f01","name":"If2","type":"n8n-nodes-base.if","position":[3500,1120],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"or","conditions":[{"id":"140d284f-34c0-4bf4-bb88-b0a9bdbc80f7","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Contact Request\"] }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"7d3b6e0a-afc8-432b-9da1-a71743fc9f9f","name":"Limit","type":"n8n-nodes-base.limit","notes":"max 200 per week","position":[3720,1020],"parameters":{"maxItems":50},"notesInFlow":true,"typeVersion":1},{"id":"d3c9bf50-c72c-4e7e-8f29-59bef7635ac8","name":"Loop Over Items7","type":"n8n-nodes-base.splitInBatches","position":[3860,1240],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"84cd1b25-5781-4449-87fc-2e72b127c0df","name":"Google Sheets14","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[4400,1260],"parameters":{"columns":{"value":{"URN":"={{ $('Google Sheets13').item.json.URN }}","Contact Request":"TRUE"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Lead Score","type":"string","display":true,"removed":true,"required":false,"displayName":"Lead Score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Contact Request","type":"string","display":true,"removed":false,"required":false,"displayName":"Contact Request","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Connected","type":"string","display":true,"removed":true,"required":false,"displayName":"Connected","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"ccce3a0a-6ff1-4c9a-948a-d19f7a4f3bce","name":"Google Sheets15","type":"n8n-nodes-base.googleSheets","maxTries":5,"position":[3560,1540],"parameters":{"columns":{"value":{"URN":"={{ $json.urn.type }}:{{ $json.urn.value }}","Connected":"TRUE"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Lead Score","type":"string","display":true,"removed":true,"required":false,"displayName":"Lead Score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Contact Request","type":"string","display":true,"removed":true,"required":false,"displayName":"Contact Request","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Connected","type":"string","display":true,"removed":false,"required":false,"displayName":"Connected","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Message Sent","type":"string","display":true,"removed":true,"required":false,"displayName":"Message Sent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"notesInFlow":false,"retryOnFail":true,"typeVersion":4.5,"alwaysOutputData":false,"waitBetweenTries":5000},{"id":"bfc9b9b9-3be3-4966-b93d-7b22898e240c","name":"Google Sheets17","type":"n8n-nodes-base.googleSheets","onError":"continueRegularOutput","position":[4720,2240],"parameters":{"columns":{"value":{"URN":"={{ $('Google Sheets16').item.json.URN }}","Message Sent":"TRUE","Messages History":"={{ $json.text }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":true,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":true,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":true,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":true,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":true,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":true,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":true,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":true,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":true,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":true,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":true,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":true,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Posts summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Posts summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Product Summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Product Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company News","type":"string","display":true,"removed":true,"required":false,"displayName":"Company News","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company post summary","type":"string","display":true,"removed":true,"required":false,"displayName":"Company post summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Lead Score","type":"string","display":true,"removed":true,"required":false,"displayName":"Lead Score","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Contact Request","type":"string","display":true,"removed":true,"required":false,"displayName":"Contact Request","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Connected","type":"string","display":true,"removed":true,"required":false,"displayName":"Connected","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Message Sent","type":"string","display":true,"removed":false,"required":false,"displayName":"Message Sent","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Messages History","type":"string","display":true,"removed":false,"required":false,"displayName":"Messages History","defaultMatch":false,"canBeUsedToMatch":true},{"id":"row_number","type":"string","display":true,"removed":true,"readOnly":true,"required":false,"displayName":"row_number","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5},{"id":"a9a7435c-a276-42d3-ae85-96c0cf86dec6","name":"Loop Over Items8","type":"n8n-nodes-base.splitInBatches","position":[3900,1980],"parameters":{"options":{}},"retryOnFail":true,"typeVersion":3},{"id":"f7e9963b-bff1-4452-a7ce-2e53ab06b1a6","name":"HDW LinkedIn Send Message","type":"n8n-nodes-hdw.hdwLinkedinManagement","position":[4460,2120],"parameters":{"text":"Hello","user":"={{ $json.URN }}","resource":"chat"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1},{"id":"5cf24040-0343-476a-8e74-9ab803a5dab4","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[2640,1120],"parameters":{"rule":{"interval":[{"triggerAtHour":7}]}},"typeVersion":1.2},{"id":"0eca2bdb-0145-4082-9b45-7d05b176376f","name":"Schedule Trigger1","type":"n8n-nodes-base.scheduleTrigger","position":[2920,1560],"parameters":{"rule":{"interval":[{"triggerAtHour":7}]}},"typeVersion":1.2},{"id":"c89614c9-304a-44d0-9bf6-f5578ad5ca73","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[-3280,800],"parameters":{"color":7,"width":620,"height":640,"content":"# LinkedIn Lead Automation Flow\n\nThis flow is designed to automate working with leads on LinkedIn from the process of finding leads according to ICP (Ideal Customer Profile) to sending messages in chat.\n\n## Stages:\n1. Building search filters based on your ICP\n2. Searching LinkedIn using these filters\n3. Saving the list of leads in Google Spreadsheet\n4. Data enrichment\n  • Company website\n  • Intent search in lead's posts\n  • Intent search in company posts\n  • Analysis of company news\n  • Analysis of company website\n5. Scoring information about the lead to prioritize interaction\n6. Adding the lead to LinkedIn connections\n7. Checking for reciprocal connection\n8. Writing messages\n\n## Requirements:\n1. Access to LLM (the example uses OpenAI API)\n2. Access to Google Drive\n3. API key for horizondatawave.ai\n4. LinkedIn account"},"typeVersion":1},{"id":"244a300a-a0f6-4d35-90c1-e87078ed6600","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[-2080,920],"parameters":{"color":7,"width":300,"height":80,"content":"This node - an AI agent transforms your ICP description into filters for querying data in LinkedIn"},"typeVersion":1},{"id":"f8cf06a5-e69a-4e8c-9132-b46093b22f16","name":"Sticky Note10","type":"n8n-nodes-base.stickyNote","position":[-1360,1340],"parameters":{"color":7,"width":320,"height":80,"content":"Data is requested through the HDW API for each filter and saved in Google Sheets."},"typeVersion":1},{"id":"1506055f-de26-4317-85d8-b4b0e99f78f7","name":"Sticky Note11","type":"n8n-nodes-base.stickyNote","position":[-640,860],"parameters":{"color":7,"width":320,"height":120,"content":"At this stage, the presence of the company name in the lead's profile is verified, and a website search is performed for each company"},"typeVersion":1},{"id":"8e70ff75-9cd9-4e17-9a55-40e87dbe2947","name":"Sticky Note12","type":"n8n-nodes-base.stickyNote","position":[780,740],"parameters":{"color":5,"width":360,"height":100,"content":"You can modify the prompt here so that at this stage the search corresponds to your product. \nFor example, you can explicitly mark mentions of certain topics, locations, or other entities."},"typeVersion":1},{"id":"7d6ad9ee-65cc-4235-abb1-557b0a602173","name":"Sticky Note13","type":"n8n-nodes-base.stickyNote","position":[740,1320],"parameters":{"color":5,"width":360,"height":100,"content":"You can modify the prompt here so that at this stage the search corresponds to your product. \nFor example, you can explicitly mark mentions of certain topics, locations, or other entities."},"typeVersion":1},{"id":"e04cbd74-c77e-4cfe-945d-447191ba4dbe","name":"Sticky Note14","type":"n8n-nodes-base.stickyNote","position":[760,1760],"parameters":{"color":5,"width":360,"height":100,"content":"You can modify the prompt here so that at this stage the search corresponds to your product. \nFor example, you can explicitly mark mentions of certain topics, locations, or other entities."},"typeVersion":1},{"id":"39852dfc-6077-4a3d-8dca-8760eaf20d18","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[760,2240],"parameters":{"color":5,"width":360,"height":100,"content":"You can modify the prompt here so that at this stage the search corresponds to your product. \nFor example, you can explicitly mark mentions of certain topics, locations, or other entities."},"typeVersion":1},{"id":"e55a0d94-30c1-4d00-9b32-835a5ce8e66f","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[2200,1620],"parameters":{"color":5,"width":360,"height":100,"content":"You can also change the scoring criteria to assess the probability of need based on your product or business by adjusting the prompt in this node"},"typeVersion":1},{"id":"66b08e98-dfe4-425a-83c6-0c11f4ad6a53","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[3600,900],"parameters":{"color":5,"width":360,"height":100,"content":"Here you can change the number of connection requests. It is not recommended to add more than 200 connections per week."},"typeVersion":1},{"id":"4d8240ad-688e-4469-bcd4-b708b19cecba","name":"Sticky Note18","type":"n8n-nodes-base.stickyNote","position":[4360,1980],"parameters":{"color":3,"width":360,"height":100,"content":"In this node, you need to modify the message that will be automatically sent to the user after the connection is confirmed."},"typeVersion":1},{"id":"ad3f07f9-645a-49d8-be56-b45b3a38736a","name":"Sticky Note19","type":"n8n-nodes-base.stickyNote","position":[2620,1040],"parameters":{"color":3,"width":180,"height":80,"content":"Change the schedule for when connection requests will be sent."},"typeVersion":1},{"id":"8c13451c-13a3-4b36-b0ba-341dbc4c6e93","name":"Sticky Note20","type":"n8n-nodes-base.stickyNote","position":[3040,1840],"parameters":{"color":3,"width":200,"height":100,"content":"Change the schedule for when connection request responses will be checked and messages will be sent."},"typeVersion":1},{"id":"b462dd15-76a6-4d09-a258-6a64c5e7c2b5","name":"HDW Get LinkedIn Profile Connections","type":"n8n-nodes-hdw.hdwLinkedinManagement","maxTries":5,"position":[3260,1540],"parameters":{"count":40,"operation":"getConnections","connectedAfter":0},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"44e0fce5-df66-4572-bc91-c3600cb9377e","name":"HDW Send LinkedIn Connection","type":"n8n-nodes-hdw.hdwLinkedinManagement","onError":"continueRegularOutput","maxTries":5,"position":[4140,1200],"parameters":{"user":"={{ $('Google Sheets13').item.json.URN }}"},"credentials":{"hdwLinkedinApi":{"id":"ZT0V5HkxTZIlAkvE","name":"HDW LinkedIn account"}},"retryOnFail":true,"typeVersion":1,"waitBetweenTries":5000},{"id":"d5870d51-8f5e-41b2-b05e-1b49b04ede86","name":"AI Agent: ICP -> LinkedIn search filters","type":"@n8n/n8n-nodes-langchain.agent","onError":"continueRegularOutput","position":[-2320,1060],"parameters":{"text":"=ICP  description - {{ $json.output }}","options":{"systemMessage":"Your task is to analyze an ICP (Ideal Customer Profile) description and convert it into LinkedIn Sales Navigator search parameters that are compatible with the HDW LinkedIn node in n8n.\n\n⸻\n\nHard rules (do not break them)\n\t1.\tNo guesswork.\n\t•\tNever invent new values for location, industry, current_companies, or any other field. Use only what is explicitly present in the ICP.\n\t2.\tReal companies only.\n\t•\tThe current_companies field may contain only company names that are directly mentioned in the ICP.\n\t3.\tNo fabricated locations.\n\t•\tIn location, specify only countries or cities that appear in the ICP.\n\t4.\t“Smart” filter combinations.\n\t•\tIf the ICP includes several locations and/or industries, generate multiple objects (filters)—one for each unique combination of actual values (do not create combinations that do not exist in the ICP).\n\t•\tReturn a maximum of 10 filters in one response.\n\t5.\tOmit undefined data.\n\t•\tIf a field is missing in the ICP, omit that key entirely (do not output null, empty strings, or empty arrays).\n\n\t7.\tIndustry list only.\n\t•\tFor industry, you may use only the names from the approved list (see below). Try with different industries in different filters\n\t8.\tJSON validation.\n\t•\tThe final answer must be a valid JSON array in the exact structure shown under “Response Format.”\n\t9.\tUp to 10 filters.\n\t•\tYou may return no more than ten filter objects per ICP request.\n\t10.\tUnclear roles → multiple title variants.\n\t•\tIf job roles/titles are not specified precisely in the ICP (e.g., only a function or department is mentioned), create several filters that cover plausible title variants.\n\t•\tEach variant goes into its own filter object (or grouped logically if other parameters are identical), still respecting the overall limit of 10 filters.\n\t•\tUse common, realistic synonyms or seniority variations relevant to the ICP \n\t•\tDo not invent wholly unrelated titles; stay within the role scope implied by the ICP.\n\nResponse Format\n\nReturn only a JSON array with no comments, explanations, or extra text. Each object represents one filter.\n\n[\n  {\n    \"salesNavigatorParams\": {\n      \"current_titles\": \"title1\",\n      \"current_companies\": \"company1\",\n      \"location\": \"location1\",\n      \"industry\": \"industry1\",\n      \"company_sizes\": [\n        \"Self-employed\",\n        \"1-10\",\n        \"11-50\",\n        \"51-200\",\n        \"201-500\",\n        \"501-1,000\",\n        \"1,001-5,000\",\n        \"5,001-10,000\",\n        \"10,001+\"\n      ]\n    },\n    \"count\": 10\n  },\n  {\n    \"salesNavigatorParams\": {\n      \"current_titles\": \"title2\",\n      \"current_companies\": \"company2\",\n      \"location\": \"location2\",\n      \"industry\": \"industry2\",\n      \"company_sizes\": [\n        \"Self-employed\",\n        \"1-10\",\n        \"11-50\",\n        \"51-200\",\n        \"201-500\",\n        \"501-1,000\",\n        \"1,001-5,000\",\n        \"5,001-10,000\",\n        \"10,001+\"\n      ]\n    },\n    \"count\": 10\n  }\nother filters\n]\n\nImportant: If a field does not apply, omit it entirely. For example, if company size is not specified, remove the whole company_sizes block.\n\n\n• (Allowed values for industry) If you need industry name use one from this list closer to the user request:\nChiropractors \nDefense and Space Manufacturing\nOptometrists\nComputer Hardware Manufacturing\nSoftware Development\nComputer Networking Products\nTransportation Equipment Manufacturing\nTechnology, Information and Internet\nPhysical, Occupational and Speech Therapists\nSemiconductor Manufacturing\nTelecommunications\nLaw Practice\nHousing Programs\nLegal Services\nBusiness Consulting and Services\nBiotechnology Research\nFamily Planning Centers\nMedical Practices\nTransportation Programs\nHospitals and Health Care\nUtilities Administration\nPharmaceutical Manufacturing\nOutpatient Care Centers\nVeterinary Services\nMedical Equipment Manufacturing\nSpace Research and Technology\nMotor Vehicle Parts Manufacturing\nPersonal Care Product Manufacturing\nRetail Apparel and Fashion\nSporting Goods Manufacturing\nTobacco Manufacturing\nMedical and Diagnostic Laboratories\nRetail Groceries\nFood and Beverage Manufacturing\nOil Extraction\nComputers and Electronics Manufacturing\nNatural Gas Extraction\nManufacturing\nFurniture and Home Furnishings Manufacturing\nHome Health Care Services\nRetail\nEmbedded Software Products\nEntertainment Providers\nMobile Computing Software Products\nGambling Facilities and Casinos\nAmbulance Services\nDesktop Computing Software Products\nIT System Custom Software Development\nTravel Arrangements\nIT System Operations and Maintenance\nHospitality\nIT System Installation and Disposal\nRestaurants\nIT System Training and Support\nHospitals\nSpectator Sports\nIT System Data Services\nFood and Beverage Services\nIT System Testing and Evaluation\nMovies, Videos, and Sound\nBroadcast Media Production and Distribution\nMuseums, Historical Sites, and Zoos\nArtists and Writers\nPerforming Arts\nRecreational Facilities\nBanking\nInsurance\nNursing Homes and Residential Care Facilities\nFinancial Services\nReal Estate\nInvestment Banking\nInvestment Management\nAccounting\nConstruction\nWholesale Building Materials\nArchitecture and Planning\nCivil Engineering\nInternet News\nAviation and Aerospace Component Manufacturing\nBlogs\nMotor Vehicle Manufacturing\nInterior Design\nChemical Manufacturing\nSocial Networking Platforms\nMachinery Manufacturing\nHousehold and Institutional Furniture Manufacturing\nBusiness Intelligence Platforms\nMining\nBusiness Content\nOil and Gas\nData Security Software Products\nShipbuilding\nUtilities\nMobile Gaming Apps\nTextile Manufacturing\nInternet Publishing\nPaper and Forest Product Manufacturing\nMedia and Telecommunications\nRailroad Equipment Manufacturing\nBlockchain Services\nFarming\nServices for the Elderly and Disabled\nRanching\nDairy Product Manufacturing\nOffice Furniture and Fixtures Manufacturing\nFisheries\nCommunity Services\nPrimary and Secondary Education\nHigher Education\nEducation Administration Programs\nResearch Services\nMattress and Blinds Manufacturing\nArmed Forces\nLegislative Offices\nAdministration of Justice\nInternational Affairs\nEmergency and Relief Services\nGovernment Administration\nExecutive Offices\nLaw Enforcement\nVocational Rehabilitation Services\nPublic Safety\nPublic Policy Offices\nAdvertising Services\nChild Day Care Services\nNewspaper Publishing\nPerforming Arts and Spectator Sports\nBook and Periodical Publishing\nPrinting Services\nInformation Services\nLibraries\nTheater Companies\nEnvironmental Services\nFreight and Package Transportation\nDance Companies\nIndividual and Family Services\nReligious Institutions\nCivic and Social Organizations\nConsumer Services\nCircuses and Magic Shows\nTruck Transportation\nWarehousing and Storage\nSports Teams and Clubs\nAirlines and Aviation\nMaritime Transportation\nRacetracks\nIT Services and IT Consulting\nMarket Research\nPublic Relations and Communications Services\nDesign Services\nNon-profit Organizations\nFundraising\nStrategic Management Services\nWriting and Editing\nStaffing and Recruiting\nWholesale Motor Vehicles and Parts\nProfessional Training and Coaching\nVenture Capital and Private Equity Principals\nPolitical Organizations\nTranslation and Localization\nComputer Games\nEvents Services\nRetail Art Supplies\nMuseums\nAppliances, Electrical, and Electronics Manufacturing\nOnline Audio and Video Media\nWholesale Furniture and Home Furnishings\nHistorical Sites\nNanotechnology Research\nRetail Art Dealers\nMusicians\nZoos and Botanical Gardens\nTransportation, Logistics, Supply Chain and Storage\nPlastics Manufacturing\nComputer and Network Security\nWireless Services\nAmusement Parks and Arcades\nAlternative Dispute Resolution\nSecurity and Investigations\nFacilities Services\nOutsourcing and Offshoring Consulting\nWellness and Fitness Services\nAlternative Medicine\nMedia Production\nAnimation and Post-production\nLeasing Non-residential Real Estate\nCapital Markets\nWholesale Photography Equipment and Supplies\nThink Tanks\nPhilanthropic Fundraising Services\nGolf Courses and Country Clubs\nE-Learning Providers\nWholesale\nWholesale Computer Equipment\nSkiing Facilities\nWholesale Import and Export\nIndustrial Machinery Manufacturing\nPhotography\nHuman Resources Services\nRetail Office Equipment\nMental Health Care\nGraphic Design\nInternational Trade and Development\nBeverage Manufacturing\nAccommodation and Food Services\nWholesale Metals and Minerals\nRetail Luxury Goods and Jewelry\nGlass, Ceramics and Concrete Manufacturing\nPackaging and Containers Manufacturing\nHotels and Motels\nAutomation Machinery Manufacturing\nWholesale Appliances, Electrical, and Electronics\nGovernment Relations Services\nBed-and-Breakfasts, Hostels, Homestays\nHorticulture\nWholesale Hardware, Plumbing, Heating Equipment\nWholesale Machinery\nCaterers\nMobile Food Services\nRenewable Energy Power Generation\nBars, Taverns, and Nightclubs\nRenewable Energy Equipment Manufacturing\nEngineering Services\nServices for Renewable Energy\nDigital Accessibility Services\nAccessible Hardware Manufacturing\nAccessible Architecture and Design\nRobot Manufacturing\nRobotics Engineering\nRepair and Maintenance\nSurveying and Mapping Services\nVehicle Repair and Maintenance\nRetail Pharmacies\nClimate Technology Product Manufacturing\nClimate Data and Analytics\nAlternative Fuel Vehicle Manufacturing\nWholesale Recyclable Materials\nSmart Meter Manufacturing\nFuel Cell Manufacturing\nWholesale Luxury Goods and Jewelry\nRegenerative Design\nFuneral Services\nDeath Care Services\nEnergy Technology\nWholesale Paper Products\nElectronic and Precision Equipment Maintenance\nWholesale Drugs and Sundries\nWholesale Apparel and Sewing Supplies\nCommercial and Industrial Machinery Maintenance\nFarming, Ranching, Forestry\nReupholstery and Furniture Repair\nWholesale Footwear\nWholesale Food and Beverage\nFootwear and Leather Goods Repair\nPersonal and Laundry Services\nPersonal Care Services\nLaundry and Drycleaning Services\nWholesale Raw Farm Products\nWholesale Chemical and Allied Products\nPet Services\nWholesale Petroleum and Petroleum Products\nWholesale Alcoholic Beverages\nRanching and Fisheries\nInternet Marketplace Platforms\nRetail Motor Vehicles\nHousehold Services\nRetail Furniture and Home Furnishings\nRetail Appliances, Electrical, and Electronic Equipment\nForestry and Logging\nRetail Building Materials and Garden Equipment\nHealth and Human Services\nPublic Health\nPublic Assistance Programs\nFood and Beverage Retail\nAir, Water, and Waste Program Management\nConservation Programs\nHousing and Community Development\nCommunity Development and Urban Planning\nEconomic Programs\nOil, Gas, and Mining\nRetail Health and Personal Care Products\nCoal Mining\nMilitary and International Affairs\nMetal Ore Mining\nRetail Gasoline\nOperations Consulting\nNonmetallic Mineral Mining\nElectric Power Transmission, Control, and Distribution\nRetail Musical Instruments\nElectric Power Generation\nHydroelectric Power Generation\nRetail Books and Printed News\nFossil Fuel Electric Power Generation\nNuclear Electric Power Generation\nSolar Electric Power Generation\nEnvironmental Quality Programs\nGeothermal Electric Power Generation\nBiomass Electric Power Generation\nNatural Gas Distribution\nWater, Waste, Steam, and Air Conditioning Services\nRetail Florists\nRetail Office Supplies and Gifts\nWater Supply and Irrigation Systems\nSteam and Air-Conditioning Supply\nBuilding Construction\nRetail Recyclable Materials & Used Merchandise\nResidential Building Construction\nData Infrastructure and Analytics\nNonresidential Building Construction\nUtility System Construction\nElectrical Equipment Manufacturing\nOnline and Mail Order Retail\nSubdivision of Land\nHighway, Street, and Bridge Construction\nSpecialty Trade Contractors\nBuilding Structure and Exterior Contractors\nWind Electric Power Generation\nWineries\nBuilding Equipment Contractors\nRail Transportation\nBuilding Finishing Contractors\nGround Passenger Transportation\nUrban Transit Services\nInterurban and Rural Bus Services\nTaxi and Limousine Services\nAnimal Feed Manufacturing\nSchool and Employee Bus Services\nShuttles and Special Needs Transportation Services\nSugar and Confectionery Product Manufacturing\nPipeline Transportation\nFruit and Vegetable Preserves Manufacturing\nSightseeing Transportation\nMeat Products Manufacturing\nSeafood Product Manufacturing\nBaked Goods Manufacturing\nPostal Services\nBreweries\nDistilleries\nTechnology, Information and Media\nPeriodical Publishing\nBook Publishing\nMovies and Sound Recording\nApparel Manufacturing\nSound Recording\nSheet Music Publishing\nRadio and Television Broadcasting\nFashion Accessories Manufacturing\nLeather Product Manufacturing\nCable and Satellite Programming\nTelecommunications Carriers\nFootwear Manufacturing\nSatellite Telecommunications\nWomen's Handbag Manufacturing\nCredit Intermediation\nSavings Institutions\nLoan Brokers\nOil and Coal Product Manufacturing\nSecurities and Commodity Exchanges\nChemical Raw Materials Manufacturing\nInvestment Advice\nInsurance Carriers\nArtificial Rubber and Synthetic Fiber Manufacturing\nAgricultural Chemical Manufacturing\nInsurance Agencies and Brokerages\nClaims Adjusting, Actuarial Services\nFunds and Trusts\nInsurance and Employee Benefit Funds\nPension Funds\nPaint, Coating, and Adhesive Manufacturing\nTrusts and Estates\nSoap and Cleaning Product Manufacturing\nReal Estate and Equipment Rental Services\nLeasing Residential Real Estate\nPlastics and Rubber Product Manufacturing\nReal Estate Agents and Brokers\nEquipment Rental Services\nConsumer Goods Rental\nRubber Products Manufacturing\nClay and Refractory Products Manufacturing\nCommercial and Industrial Equipment Rental\nGlass Product Manufacturing\nWood Product Manufacturing\nProfessional Services\nLime and Gypsum Products Manufacturing\nAbrasives and Nonmetallic Minerals Manufacturing\nPrimary Metal Manufacturing\nIT System Design Services\nMarketing Services\nFabricated Metal Products\nCutlery and Handtool Manufacturing\nArchitectural and Structural Metal Manufacturing\nBoilers, Tanks, and Shipping Container Manufacturing\nConstruction Hardware Manufacturing\nSpring and Wire Product Manufacturing\nTurned Products and Fastener Manufacturing\nHolding Companies\nMetal Treatments\nIndustry Associations\nLandscaping Services\nProfessional Organizations\nMetal Valve, Ball, and Roller Manufacturing\nAdministrative and Support Services\nOffice Administration\nExecutive Search Services\nTemporary Help Services\nAgriculture, Construction, Mining Machinery Manufacturing\nTelephone Call Centers\nCollection Agencies\nCommercial and Service Industry Machinery Manufacturing\nHVAC and Refrigeration Equipment Manufacturing\nMetalworking Machinery Manufacturing\nSecurity Guards and Patrol Services\nSecurity Systems Services\nEngines and Power Transmission Equipment Manufacturing\nJanitorial Services\nWaste Collection\nWaste Treatment and Disposal\nCommunications Equipment Manufacturing\nAudio and Video Equipment Manufacturing\nEducation\nMeasuring and Control Instrument Manufacturing\nSecretarial Schools\nTechnical and Vocational Training\nMagnetic and Optical Media Manufacturing\nCosmetology and Barber Schools\nFlight Training\nElectric Lighting Equipment Manufacturing\nFine Arts Schools\nSports and Recreation Instruction\nHousehold Appliance Manufacturing\nLanguage Schools\nPhysicians\nCourts of Law\nCorrectional Institutions\nDentists\nFire Protection\n\nSelf-check checklist\n\t•\tAre all locations actually present in the ICP?\n\t•\tAre company names copied verbatim, without changes?\n\t•\tAre industries taken only from the allowed list above?\n\t•\tIs the number of objects ≤ 10?\n\t•\tAre there no extra or empty fields?\n\t•\tIs the JSON valid and in the required structure?\n\nFollow these instructions for each ICP request to generate accurate LinkedIn Sales Navigator filters."},"promptType":"define","hasOutputParser":true},"executeOnce":false,"notesInFlow":true,"retryOnFail":true,"typeVersion":1.8},{"id":"1755a3e7-26d8-435d-853b-18128610b7b3","name":"Company name is not empty","type":"n8n-nodes-base.if","position":[-1240,1060],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"1e7e7c6d-401d-4b6e-ba9c-1e9caacb3f89","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json['Current company'] }}","rightValue":""},{"id":"5fa79c84-9e9a-4cf9-a3ed-3a84a286b734","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json.Website }}","rightValue":""}]}},"typeVersion":2.2},{"id":"b6f67554-1d08-4573-ad48-d77fb5f16835","name":"Website is not empty","type":"n8n-nodes-base.if","position":[240,880],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3f21375a-b09c-464d-a82a-b37f7b6de87b","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.Website }}","rightValue":""},{"id":"96105806-c0b8-461d-8cc1-975d8936814c","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Product Summary\"] }}","rightValue":""}]}},"typeVersion":2.2},{"id":"c7add783-44a3-470c-be4f-b7b68ee07523","name":"Post summary is empty","type":"n8n-nodes-base.if","position":[260,1560],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3f21375a-b09c-464d-a82a-b37f7b6de87b","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.URN }}","rightValue":""},{"id":"96105806-c0b8-461d-8cc1-975d8936814c","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Posts summary\"] }}","rightValue":""}]}},"typeVersion":2.2},{"id":"4e54ace8-96cd-40b6-b9a0-141f71ba70a7","name":"Company news is empty","type":"n8n-nodes-base.if","position":[260,1880],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3f21375a-b09c-464d-a82a-b37f7b6de87b","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.URN }}","rightValue":""},{"id":"96105806-c0b8-461d-8cc1-975d8936814c","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Company News\"] }}","rightValue":""}]}},"typeVersion":2.2},{"id":"6d5b7133-9b85-4795-ae55-303a7670bb4d","name":"Company post is empty","type":"n8n-nodes-base.if","position":[260,2380],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3f21375a-b09c-464d-a82a-b37f7b6de87b","operator":{"type":"string","operation":"notEquals"},"leftValue":"={{ $json[\"Company URN\"] }}","rightValue":":"},{"id":"96105806-c0b8-461d-8cc1-975d8936814c","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Company post summary\"] }}","rightValue":""},{"id":"44880d26-6f7d-4ee6-a71c-1cee7733368a","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json[\"Company URN\"] }}","rightValue":""}]}},"typeVersion":2.2},{"id":"9db340da-d10f-4873-838c-8f912ba36695","name":"Lead Score is empty","type":"n8n-nodes-base.if","position":[1900,1740],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"or","conditions":[{"id":"140d284f-34c0-4bf4-bb88-b0a9bdbc80f7","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Lead Score\"] }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"0edd4748-d13b-4aa7-9b13-cb7f216fc5d9","name":"Company Score Analysis","type":"@n8n/n8n-nodes-langchain.openAi","onError":"continueRegularOutput","position":[2260,1740],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"role":"system","content":"You are an expert in evaluating lead potential for our product.\nAnalyze the company’s and lead’s profile content, assessing their likelihood of interest in our product on a scale from 1 to 10 (where 1 indicates minimal potential, and 10 indicates maximum potential).\n\nKey evaluation criteria:\n\t•\tMentions of Hotels suppliers \n\t•\tMentions of Hotel Services\n\nEvaluation scale:\n\t•\t8–10 points: Clear mentions of both criteria, active engagement, and explicit interest.\n\t•\t5–7 points: Mention of one criterion or indirect indicators of interest in both criteria.\n\t•\t1–4 points: No clear mentions, or only weak indirect indicators of interest.\n\nYour answer must ONLY be a single number from 1 to 10, without any additional text."},{"content":"=Lead posts summary:\n {{ $json[\"Posts summary\"] }}\nLead company website analysis:\n{{ $('Google Sheets11').item.json['Product Summary'] }}\n\nCompany news summary:\n{{ $('Google Sheets11').item.json['Company News'] }}\nCompany posts summary\n{{ $('Google Sheets11').item.json['Company post summary'] }}\nCompany descriptin\n{{ $json.Description }}"}]}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"retryOnFail":true,"typeVersion":1.8},{"id":"d59cae4f-a8ea-4db1-a4cb-44bf9d64fd75","name":"5s","type":"n8n-nodes-base.wait","position":[4180,2120],"webhookId":"58b70ce8-992f-4437-9f13-669649afcaa3","parameters":{},"typeVersion":1.1},{"id":"f4492b0f-a260-4d94-8b05-4d785c8c097e","name":"Sticky Note27","type":"n8n-nodes-base.stickyNote","position":[3020,1900],"parameters":{"width":2260,"height":680,"content":"Send the first message"},"typeVersion":1},{"id":"fb56b1a5-cefe-4ccb-b901-b5d44d54b4d5","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-2720,2420],"parameters":{},"typeVersion":1.3},{"id":"9ffc5ef5-61db-40f8-be7f-4427387c806c","name":"If","type":"n8n-nodes-base.if","position":[-2400,2140],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"cd898792-a224-459f-9027-97bc007c31df","operator":{"type":"string","operation":"contains"},"leftValue":"={{ $json.output }}","rightValue":"\"icpData\":"}]}},"typeVersion":2.2},{"id":"42e32163-0529-4d2d-bc93-92ed2a57ee44","name":"Basic LLM Chain","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[-2200,2160],"parameters":{"text":"=repeat this sentence:  {{ $('ICP Agent').item.json.output }}","messages":{"messageValues":[{"message":"You are repeater"}]},"promptType":"define"},"typeVersion":1.5},{"id":"f8246169-7a15-44f8-92aa-55661bd6ec53","name":"OpenAI Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-2420,2420],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"gpt-4o"},"options":{}},"credentials":{"openAiApi":{"id":"DzKhX3E7SSLddnv4","name":"OpenAi account"}},"typeVersion":1.2},{"id":"7e200d49-02b5-41f1-b3fe-df052d0d851a","name":"Sticky Note24","type":"n8n-nodes-base.stickyNote","position":[-3240,1940],"parameters":{"width":1840,"height":820,"content":"## Conversation agent"},"typeVersion":1},{"id":"9b09a602-9f41-4e79-b111-2f2a59cf3680","name":"Schedule Trigger3","type":"n8n-nodes-base.scheduleTrigger","position":[3100,1980],"parameters":{"rule":{"interval":[{"triggerAtHour":7}]}},"typeVersion":1.2},{"id":"3badf4f0-592b-41b3-be51-7f39879edf96","name":"Google Sheets21","type":"n8n-nodes-base.googleSheets","position":[3320,1980],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"typeVersion":4.5,"alwaysOutputData":false},{"id":"17a825fc-5dfa-480b-9c4a-f8543afbf7c4","name":"If3","type":"n8n-nodes-base.if","position":[3540,1980],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"5be9c0af-558c-4b8f-9de2-a21a0f6bb60c","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.Connected }}","rightValue":"true"},{"id":"bf0095c5-f74e-4022-a6ec-66066d43cb6c","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json[\"Message Sent\"] }}","rightValue":""}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"16a83e7a-3020-4687-b632-ca16c251687d","name":"Sticky Note25","type":"n8n-nodes-base.stickyNote","position":[2800,1440],"parameters":{"width":1220,"height":340,"content":"## Check the connections"},"typeVersion":1},{"id":"949c7342-115d-4fc4-b819-eab822b2644d","name":"Sticky Note29","type":"n8n-nodes-base.stickyNote","position":[2600,980],"parameters":{"width":1800,"height":440,"content":"## Add new connections"},"typeVersion":1},{"id":"476dfcd2-47de-4c20-be98-7c8090ac807a","name":"If4","type":"n8n-nodes-base.if","position":[-740,1820],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4d0c7d09-934f-4327-9eed-e1c04b773166","operator":{"type":"string","operation":"empty","singleValue":true},"leftValue":"={{ $json.Website }}","rightValue":""}]}},"typeVersion":2.2},{"id":"3ad79f6e-fcc7-4fd1-b546-3ab04b1084af","name":"Read companies","type":"n8n-nodes-base.googleSheets","maxTries":5,"position":[-1420,1060],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"executeOnce":true,"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"e5338e9b-cae3-4301-88ad-16128978d42b","name":"Save new companies","type":"n8n-nodes-base.googleSheets","position":[-1600,1060],"parameters":{"columns":{"value":{"URL":"={{ $json.url }}","URN":"={{ $json.urn.type }}:{{ $json.urn.value }}","img":"={{ $json.image }}","Date":"={{ $json.current_companies[0].joined }}","Name":"={{ $json.name }}","Headline":"={{ $json.headline }}","Industry":"={{ $json.current_companies[0].company.industry }}","Position":"={{ $json.current_companies[0].position }}","location":"={{ $json.location }}","is premium":"={{ $json.is_premium }}","Company URN":"={{ $json.current_companies[0].company.urn.type }}:{{ $json.current_companies[0].company.urn.value }}","Description":"={{ $json.current_companies[0].description }}","Current company":"={{ $json.current_companies[0].company.name }}"},"schema":[{"id":"Name","type":"string","display":true,"removed":false,"required":false,"displayName":"Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URN","type":"string","display":true,"removed":false,"required":false,"displayName":"URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":false,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"img","type":"string","display":true,"removed":false,"required":false,"displayName":"img","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Headline","type":"string","display":true,"removed":false,"required":false,"displayName":"Headline","defaultMatch":false,"canBeUsedToMatch":true},{"id":"location","type":"string","display":true,"removed":false,"required":false,"displayName":"location","defaultMatch":false,"canBeUsedToMatch":true},{"id":"is premium","type":"string","display":true,"removed":false,"required":false,"displayName":"is premium","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Current company","type":"string","display":true,"removed":false,"required":false,"displayName":"Current company","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company URN","type":"string","display":true,"removed":false,"required":false,"displayName":"Company URN","defaultMatch":false,"canBeUsedToMatch":true},{"id":"URL","type":"string","display":true,"removed":false,"required":false,"displayName":"URL","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Industry","type":"string","display":true,"removed":false,"required":false,"displayName":"Industry","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"removed":false,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Description","type":"string","display":true,"removed":false,"required":false,"displayName":"Description","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Date","type":"string","display":true,"removed":false,"required":false,"displayName":"Date","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Website","type":"string","display":true,"removed":false,"required":false,"displayName":"Website","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["URN"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs","cachedResultUrl":"https://docs.google.com/spreadsheets/d/19n84gbJPp-VmAUz6fElLSQcMajh5btPvI7Lhf20u7hs/edit?usp=drivesdk","cachedResultName":"HDW_OutReach"}},"credentials":{"googleSheetsOAuth2Api":{"id":"ZKhilXnb085cZbuM","name":"Google Sheets account"}},"retryOnFail":true,"typeVersion":4.5,"waitBetweenTries":5000},{"id":"d28278df-0ce3-4d3b-bf91-181085f27685","name":"Discourse your ICP with Agent","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-3020,2140],"webhookId":"80d69e6f-5dfc-4626-b6a6-2b3c0c58081e","parameters":{"options":{}},"typeVersion":1.1},{"id":"fb8191dd-9512-4c62-8199-c4a7b0a2e62f","name":"ICP Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-2760,2140],"parameters":{"options":{"systemMessage":"Your task is to interactively collect an Ideal Customer Profile (ICP) from the user. \n\nIMPORTANT: DO NOT SHOW ANY JSON TO THE USER DURING THE DATA COLLECTION PROCESS. Only communicate in natural language until all data has been collected.\n\nWhen the conversation starts, immediately:\n1. Introduce yourself and explain that you'll be collecting information to build an Ideal Customer Profile\n2. Briefly explain what information you'll be asking for\n3. Ask the FIRST question about current_titles without waiting for further input\n\nData Collection Process:\n1. Initialize an empty object called `icpData` in your memory (do not share this with the user).\n2. Ask the user each of the following questions ONE AT A TIME in natural conversational language, and after each answer, store the response in your internal `icpData` object:\n   - **current_titles**: \"What current titles do your target customers hold? (List comma-separated.)\"\n   - **current_companies**: \"What current companies do they work at? (List comma-separated.)\"\n   - **location**: \"Which geographic regions should we search in? (List cities, regions, or countries.)\"\n   - **industry**: \"Which industries are of interest? (Use LinkedIn's official industry names or describe them as closely as possible.)\"\n   - **company_sizes**: \"Which company sizes do you prefer? (e.g. Self-employed, 1–10, 11–50, 51–200, etc.)\"\n   - **keywords**: \"Are there any additional keywords to refine the search? (e.g. technologies, specialties, skills.)\"\n\nCommunication Guidelines:\n- Begin immediately with your introduction and the first question about current_titles\n- Speak naturally during the conversation, DO NOT show any JSON during the data collection phase\n- Ask only one question at a time\n- After receiving an answer, acknowledge it and ask the next question\n- If a user provides unclear information, ask for clarification\n- If the user explicitly states they want to skip any questions or finish early, respect their request\n- If the user types \"finish\", \"done\", \"complete\", or similar commands at any point, immediately prepare to generate the JSON\n\nFinal Output Requirements:\n- ALWAYS output the complete icpData object in valid JSON format when EITHER:\n  1. All seven fields have been collected, OR\n  2. The user explicitly requests to finish early or skip remaining questions\n- Include all fields in the output, using null for any fields that weren't collected\n- The \"dataComplete\" field must always be set to true in the final JSON output\n- Do not add any additional fields or modify the JSON structure\n- The final JSON MUST follow this exact format and have only JSON:\n{\n  \"icpData\": {\n    \"current_titles\": \"[collected value or null]\",\n    \"current_companies\": \"[collected value or null]\",\n    \"location\": \"[collected value or null]\",\n    \"industry\": \"[collected value or null]\",\n    \"company_sizes\": \"[collected value or null]\",\n    \"keywords\": \"[collected value or null]\",\n    \"count\": \"[collected value or null]\"\n  },\n  \"dataComplete\": true\n}\n\nCRITICAL: Your final response must consist of ONLY the single line \"Thank you for providing the information. Here is your ICP data:\" followed IMMEDIATELY by the JSON object. Do not add ANY other text, explanations, or formatting. The JSON object must be the absolute final thing in your response with nothing after it."}},"typeVersion":1.8},{"id":"dfb24258-8003-4e1e-b27e-cfd6e84c9c49","name":"Merge","type":"n8n-nodes-base.merge","position":[1560,1720],"parameters":{"numberInputs":4},"typeVersion":3.1}],"active":false,"settings":{"executionOrder":"v1"},"versionId":"2960f60b-e6d3-473c-b5e7-54f1180f03d9","connections":{"5s":{"main":[[{"node":"HDW LinkedIn Send Message","type":"main","index":0}]]},"If":{"main":[[{"node":"AI Agent: ICP -> LinkedIn search filters","type":"main","index":0}],[{"node":"Basic LLM Chain","type":"main","index":0}]]},"If2":{"main":[[{"node":"Limit","type":"main","index":0}]]},"If3":{"main":[[{"node":"Loop Over Items8","type":"main","index":0}]]},"If4":{"main":[[{"node":"HDW Get Company Website","type":"main","index":0}],[{"node":"Loop Over Items","type":"main","index":0}]]},"Sort":{"main":[[{"node":"If2","type":"main","index":0}]]},"Limit":{"main":[[{"node":"Loop Over Items7","type":"main","index":0}]]},"Merge":{"main":[[{"node":"Google Sheets11","type":"main","index":0}]]},"Aggregate":{"main":[[{"node":"Summarise user posts","type":"main","index":0}]]},"ICP Agent":{"main":[[{"node":"If","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"HDW LinkedIn SN","type":"main","index":0}]]},"Aggregate1":{"main":[[{"node":"Summarise company news","type":"main","index":0}]]},"Aggregate2":{"main":[[{"node":"Summarise company posts","type":"main","index":0}]]},"HDW Parser":{"ai_tool":[[{"node":"Summarise company website","type":"ai_tool","index":0}]]},"HDW Site-map":{"ai_tool":[[{"node":"Summarise company website","type":"ai_tool","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"ICP Agent","type":"ai_memory","index":0}]]},"Google Sheets2":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"Google Sheets3":{"main":[[{"node":"Website is not empty","type":"main","index":0}]]},"Google Sheets4":{"main":[[{"node":"Post summary is empty","type":"main","index":0}]]},"Google Sheets5":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Google Sheets6":{"main":[[{"node":"Company news is empty","type":"main","index":0}]]},"Google Sheets7":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]},"Google Sheets8":{"main":[[{"node":"Company post is empty","type":"main","index":0}]]},"Google Sheets9":{"main":[[{"node":"Loop Over Items4","type":"main","index":0}]]},"Read companies":{"main":[[{"node":"Company name is not empty","type":"main","index":0}]]},"Google Sheets10":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Google Sheets11":{"main":[[{"node":"Lead Score is empty","type":"main","index":0}]]},"Google Sheets12":{"main":[[{"node":"Loop Over Items6","type":"main","index":0}]]},"Google Sheets13":{"main":[[{"node":"Sort","type":"main","index":0}]]},"Google Sheets14":{"main":[[{"node":"Loop Over Items7","type":"main","index":0}]]},"Google Sheets17":{"main":[[{"node":"Loop Over Items8","type":"main","index":0}]]},"Google Sheets21":{"main":[[{"node":"If3","type":"main","index":0}]]},"HDW LinkedIn SN":{"main":[[{"node":"Save new companies","type":"main","index":0}]]},"Loop Over Items":{"main":[[{"node":"Google Sheets3","type":"main","index":0},{"node":"Google Sheets4","type":"main","index":0},{"node":"Google Sheets6","type":"main","index":0},{"node":"Google Sheets8","type":"main","index":0}],[{"node":"If4","type":"main","index":0}]]},"Loop Over Items1":{"main":[[{"node":"Merge","type":"main","index":0}],[{"node":"Summarise company website","type":"main","index":0}]]},"Loop Over Items2":{"main":[[{"node":"Merge","type":"main","index":1}],[{"node":"HDW Get User Posts","type":"main","index":0}]]},"Loop Over Items3":{"main":[[{"node":"Merge","type":"main","index":2}],[{"node":"HDW Get Company News","type":"main","index":0}]]},"Loop Over Items4":{"main":[[{"node":"Merge","type":"main","index":3}],[{"node":"HDW Get Company Posts","type":"main","index":0}]]},"Loop Over Items6":{"main":[[{"node":"Google Sheets13","type":"main","index":0}],[{"node":"Company Score Analysis","type":"main","index":0}]]},"Loop Over Items7":{"main":[[],[{"node":"HDW Send LinkedIn Connection","type":"main","index":0}]]},"Loop Over Items8":{"main":[[],[{"node":"5s","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Google Sheets13","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent: ICP -> LinkedIn search filters","type":"ai_languageModel","index":0}]]},"Schedule Trigger1":{"main":[[{"node":"HDW Get LinkedIn Profile Connections","type":"main","index":0}]]},"Schedule Trigger3":{"main":[[{"node":"Google Sheets21","type":"main","index":0}]]},"HDW Get User Posts":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"Summarise company website","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model2":{"ai_languageModel":[[{"node":"ICP Agent","type":"ai_languageModel","index":0},{"node":"Basic LLM Chain","type":"ai_languageModel","index":0}]]},"Save new companies":{"main":[[{"node":"Read companies","type":"main","index":0}]]},"Lead Score is empty":{"main":[[{"node":"Loop Over Items6","type":"main","index":0}]]},"HDW Get Company News":{"main":[[{"node":"Aggregate1","type":"main","index":0}]]},"Summarise user posts":{"main":[[{"node":"Google Sheets5","type":"main","index":0}]]},"Website is not empty":{"main":[[{"node":"Loop Over Items1","type":"main","index":0}]]},"Company news is empty":{"main":[[{"node":"Loop Over Items3","type":"main","index":0}]]},"Company post is empty":{"main":[[{"node":"Loop Over Items4","type":"main","index":0}]]},"HDW Get Company Posts":{"main":[[{"node":"Aggregate2","type":"main","index":0}]]},"Post summary is empty":{"main":[[{"node":"Loop Over Items2","type":"main","index":0}]]},"Company Score Analysis":{"main":[[{"node":"Google Sheets12","type":"main","index":0}]]},"Summarise company news":{"main":[[{"node":"Google Sheets7","type":"main","index":0}]]},"HDW Get Company Website":{"main":[[{"node":"Google Sheets2","type":"main","index":0}]]},"Summarise company posts":{"main":[[{"node":"Google Sheets9","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"AI Agent: ICP -> LinkedIn search filters","type":"ai_outputParser","index":0}]]},"Company name is not empty":{"main":[[{"node":"Loop Over Items","type":"main","index":0}]]},"HDW LinkedIn Send Message":{"main":[[{"node":"Google Sheets17","type":"main","index":0}]]},"Summarise company website":{"main":[[{"node":"Google Sheets10","type":"main","index":0}]]},"HDW Send LinkedIn Connection":{"main":[[{"node":"Google Sheets14","type":"main","index":0}]]},"Discourse your ICP with Agent":{"main":[[{"node":"ICP Agent","type":"main","index":0}]]},"HDW Get LinkedIn Profile Connections":{"main":[[{"node":"Google Sheets15","type":"main","index":0}]]},"AI Agent: ICP -> LinkedIn search filters":{"main":[[{"node":"Split Out","type":"main","index":0}]]}}}


