# templates

name: AI-Powered Telegram Task Manager with MCP Server
author_name: Francis Njenga
author_username: gatura
categories: []
created_at: 2025-04-22T04:27:33.277Z
updated_at: 2025-04-22T04:27:33.277Z
url: https://n8n.io/workflows/3656
scraped_at: 2025-07-06 21:16:30
description:
  Detailed Description
  The ToDo App workflow is designed to streamline task management through Telegram and Google Tasks integration. This workflow allows users to create, update, and manage tasks via Telegram messages, leveraging AI capabilities to enhance user interaction. The expected outcome is a seamless experience where users can manage their tasks efficiently without needing to switch between applications.

  Who is this for?
  This workflow is intended for:
  Individuals** looking for an efficient way to manage their tasks directly from Telegram.
  Teams** that require a collaborative task management solution integrated with Google Tasks.
  Developers** interested in automating task management processes using n8n and Telegram.

  What problem does this workflow solve?
  Managing tasks can often be cumbersome, especially when switching between different applications. This workflow addresses the following problems:
  Fragmented Task Management**: Users can manage tasks directly from Telegram, reducing the need to switch to Google Tasks.
  Inefficient Communication**: By integrating AI, users can interact with the task management system in a conversational manner, making it more intuitive.
  Task Updates**: Users can easily update task statuses and details through simple messages, enhancing productivity.

  What this workflow does
  The ToDo App workflow performs the following functions:
  Incoming Message Handling: Listens for messages sent to a Telegram bot.
  Task Creation: Allows users to create new tasks based on their messages.
  Task Updates: Users can update existing tasks by sending specific commands.
  Task Retrieval: Retrieves today's and upcoming tasks from Google Tasks.
  Voice Note Transcription: Supports voice messages, converting them into text for task management.
  AI Assistance: Utilizes an AI agent to assist users in managing their tasks effectively.

  Setup
  Prerequisites
  Before setting up the workflow, ensure you have the following:
  n8n Account**: Sign up for an n8n account if you don't have one.
  Telegram Bot**: Create a Telegram bot and obtain the API token.
  Google Tasks API**: Set up Google Tasks API and obtain OAuth2 credentials.
  OpenAI API Key**: Sign up for OpenAI and obtain an API key for AI functionalities.

  Setup Process
  Upload the JSON for this workflow and setup the authentication for the different tools.

  How to customize this workflow
  To adapt the ToDo App workflow to different needs, consider the following customizations:
  Change Task Management Platform**: If you prefer a different task management tool, replace the Google Tasks nodes with your preferred service's API.
  Modify AI Responses**: Adjust the AI agent's system message to change how it interacts with users.
  Add Additional Commands**: Expand the workflow by adding more commands for different task management functionalities (e.g., deleting tasks).
  Integrate Other Messaging Platforms**: If you want to use a different messaging service, replace the Telegram nodes with the appropriate nodes for that service.

  Conclusion
  The ToDo App workflow provides a powerful solution for managing tasks through Telegram, enhancing productivity and user experience. By following the setup instructions and customization options, users can tailor the workflow to meet their specific needs, making task management more efficient and accessible.

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.openAi","@n8n/n8n-nodes-langchain.mcpClientTool"]

workflow_json:
  {"meta":{"instanceId":"be27b2af86ae3a5dc19ef2a1947644c0aec45fd8c88f29daa7dea6f0ce537691","templateCredsSetupCompleted":true},"nodes":[{"id":"ca8b122d-1739-4377-ac99-e20dd2341342","name":"Incoming Message","type":"n8n-nodes-base.telegramTrigger","position":[-1020,-320],"webhookId":"75921955-c8ed-4ff6-8de2-e436c6bbe69d","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"ayMpCvQ69GjrbPdP","name":"gatu_pa_bot"}},"typeVersion":1.2},{"id":"68f7568b-e677-454b-a1e8-6c07a05e7570","name":"MCP Server Trigger","type":"@n8n/n8n-nodes-langchain.mcpTrigger","position":[-860,240],"webhookId":"562ffc95-cf8e-4d4d-8f5b-29b3ff22d5ee","parameters":{"path":"562ffc95-cf8e-4d4d-8f5b-29b3ff22d5ee"},"typeVersion":1},{"id":"635b8ecc-0f50-477d-8e19-631f868e30f6","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[340,-320],"parameters":{"options":{"systemMessage":"=You are a helpful assistant. Whenever askes to update a task, call the get_tasks tools first to retrieve the appropriate task ids then use that to update the tasks.\n\nToday's date: {{ $now }}\n"}},"typeVersion":1.8},{"id":"ab7740dc-bac2-4044-8317-40d90252d992","name":"MCP Client","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[540,-100],"parameters":{"sseEndpoint":"https://ai.gatuservices.info/mcp/562ffc95-cf8e-4d4d-8f5b-29b3ff22d5ee/sse"},"typeVersion":1},{"id":"5298eee0-747a-496a-a3a2-e395f7c1caa1","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[300,-100],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"lcpI0YZU9bebg3uW","name":"OpenAi account"}},"typeVersion":1.2},{"id":"c5b7e10d-2d7c-403c-bcb5-a10033252f97","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[420,-100],"parameters":{"sessionKey":"={{ $('Incoming Message').item.json.message.from.id }}","sessionIdType":"customKey","contextWindowLength":20},"typeVersion":1.3},{"id":"06d2e8c8-3912-45cd-a074-4eea27c2e5eb","name":"chatInput","type":"n8n-nodes-base.set","position":[80,-220],"parameters":{"options":{},"assignments":{"assignments":[{"id":"ab70dc2d-35d0-4742-988f-ed7077633467","name":"chatInput","type":"string","value":"={{ $json.message.text }}"},{"id":"6439fc2c-dc2d-41fc-b8a3-b33ef80d2878","name":"id","type":"number","value":"={{ $json.message.from.id }}"}]}},"typeVersion":3.4},{"id":"a9309816-8c1d-435c-ad49-2e45053718c1","name":"create_todays_task","type":"n8n-nodes-base.googleTasksTool","position":[-1020,460],"parameters":{"task":"MDg2MzM1OTA5NzI0NzUzNjUwNjc6MDow","title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', `Title summary of the task to be done`, 'string') }}","additionalFields":{"notes":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Notes', `Detailed description of the task`, 'string') }}","dueDate":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Due_Date', `Date the task should be completed`, 'string') }}","completed":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Completion_Date', `Date the task was completed`, 'string') }}"}},"credentials":{"googleTasksOAuth2Api":{"id":"8sBGA2BWJuF6SObU","name":"Connected Account"}},"typeVersion":1},{"id":"ad6cfc1a-7094-434a-98d1-a6f030067091","name":"chatOutput","type":"n8n-nodes-base.set","position":[740,-320],"parameters":{"options":{},"assignments":{"assignments":[{"id":"df6bd510-e63f-41b1-b5b4-d2c612d5b8d0","name":"chatOutput","type":"string","value":"={{ $json.output }}"}]}},"typeVersion":3.4},{"id":"e342066f-3cf8-4926-94df-798e831226be","name":"sendMessage","type":"n8n-nodes-base.telegram","position":[960,-320],"webhookId":"c5eb133f-338f-4918-8e49-83ac339d841b","parameters":{"text":"={{ $json.chatOutput }}","chatId":"={{ $('Incoming Message').item.json.message.chat.id }}","additionalFields":{"appendAttribution":false,"disable_notification":false}},"credentials":{"telegramApi":{"id":"ayMpCvQ69GjrbPdP","name":"gatu_pa_bot"}},"typeVersion":1.2},{"id":"e4a1bc16-549f-46a2-92a8-a06e6023089c","name":"create_upcoming_task","type":"n8n-nodes-base.googleTasksTool","position":[-900,460],"parameters":{"task":"OFVvNlh6ZmhScHVvNll4dw","title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', `Title summary of the task to be done`, 'string') }}","additionalFields":{"notes":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Notes', `Detailed description of the task`, 'string') }}","dueDate":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Due_Date', `Date the task should be completed`, 'string') }}","completed":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Completion_Date', `Date the task was completed`, 'string') }}"}},"credentials":{"googleTasksOAuth2Api":{"id":"8sBGA2BWJuF6SObU","name":"Connected Account"}},"typeVersion":1},{"id":"df71bb02-016d-4d56-b80d-404a60c0e7cf","name":"complete_task","type":"n8n-nodes-base.googleTasksTool","position":[-780,460],"parameters":{"task":"RS1rbkNCS2JsdVFnVl80cg","taskId":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Task_ID', `The task id tom be marked as completed. Get it from the get tasks tool`, 'string') }}","operation":"update","updateFields":{}},"credentials":{"googleTasksOAuth2Api":{"id":"8sBGA2BWJuF6SObU","name":"Connected Account"}},"typeVersion":1},{"id":"a33812bd-986e-4762-87a0-199ff8a7c9aa","name":"get_todays_tasks","type":"n8n-nodes-base.googleTasksTool","position":[-660,460],"parameters":{"task":"MDg2MzM1OTA5NzI0NzUzNjUwNjc6MDow","operation":"getAll","returnAll":true,"additionalFields":{}},"credentials":{"googleTasksOAuth2Api":{"id":"8sBGA2BWJuF6SObU","name":"Connected Account"}},"typeVersion":1},{"id":"dcb3a6c9-5d7c-4fe6-8b52-f07cf74cfa0c","name":"get_upcoming_tasks","type":"n8n-nodes-base.googleTasksTool","position":[-540,460],"parameters":{"task":"OFVvNlh6ZmhScHVvNll4dw","operation":"getAll","returnAll":true,"additionalFields":{}},"credentials":{"googleTasksOAuth2Api":{"id":"8sBGA2BWJuF6SObU","name":"Connected Account"}},"typeVersion":1},{"id":"ce63c24a-ce2f-4e06-8ae5-7de75540d438","name":"Switch","type":"n8n-nodes-base.switch","position":[-800,-320],"parameters":{"rules":{"values":[{"outputKey":"Voice Note","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"8415cc8d-65a2-448e-a106-1ceb54634dfd","operator":{"type":"object","operation":"exists","singleValue":true},"leftValue":"={{ $json.message.voice }}","rightValue":""}]},"renameOutput":true}]},"options":{"fallbackOutput":"extra"}},"typeVersion":3.2},{"id":"a58488c3-38b8-4492-9f13-a900c7697812","name":"audio_id","type":"n8n-nodes-base.set","position":[-580,-420],"parameters":{"options":{},"assignments":{"assignments":[{"id":"eb7f5d62-e4f3-4b4e-9f1b-6c329feafb3e","name":"file_id","type":"string","value":"={{ $json.message.voice.file_id }}"},{"id":"803031b8-6b21-47fa-b339-ad674ccbbb1e","name":"file_unique_id","type":"string","value":"={{ $json.message.voice.file_unique_id }}"}]}},"typeVersion":3.4},{"id":"83c2ecae-b601-4669-b820-b5c35d3f936e","name":"download_audio","type":"n8n-nodes-base.telegram","position":[-360,-420],"webhookId":"c2dbc0eb-0f3a-4f11-9525-804bd5bef4b1","parameters":{"fileId":"={{ $json.file_id }}","resource":"file"},"credentials":{"telegramApi":{"id":"ayMpCvQ69GjrbPdP","name":"gatu_pa_bot"}},"typeVersion":1.2},{"id":"4a496e3a-2e3a-4ce0-9344-192847de1760","name":"transcribeAudio","type":"@n8n/n8n-nodes-langchain.openAi","position":[-140,-420],"parameters":{"options":{},"resource":"audio","operation":"transcribe"},"credentials":{"openAiApi":{"id":"lcpI0YZU9bebg3uW","name":"OpenAi account"}},"typeVersion":1.8},{"id":"38b6aa37-d279-4b1b-be42-7f7cc1bbe688","name":"audioInput","type":"n8n-nodes-base.set","position":[80,-420],"parameters":{"options":{},"assignments":{"assignments":[{"id":"d57b4fc2-10f7-46cd-a89c-0021a92f41d1","name":"chatInput","type":"string","value":"={{ $json.text }}"}]}},"typeVersion":3.4},{"id":"e524f12f-205f-4fc8-b2f0-b308ec4066b7","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1060,-500],"parameters":{"color":4,"width":2180,"height":540,"content":"## Main Function to Receive and Send Telegram Messages\n"},"typeVersion":1},{"id":"709b252a-b5e8-4c7e-8bcd-a7092d588070","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-1060,140],"parameters":{"color":3,"width":640,"height":480,"content":"## MCP Server to Carry Out Actions"},"typeVersion":1}],"pinData":{"Incoming Message":[{"message":{"chat":{"id":6043747866,"type":"private","first_name":"Gatu"},"date":1745294191,"from":{"id":6043747866,"is_bot":false,"first_name":"Gatu","language_code":"en"},"voice":{"file_id":"AwACAgQAAxkBAAMYaAcTb6Sm3bpJ_8Cc2q1q4vC7MLYAAg8ZAAJAOjlQQhWQOxUBqfU2BA","duration":2,"file_size":9854,"mime_type":"audio/ogg","file_unique_id":"AgADDxkAAkA6OVA"},"message_id":24},"update_id":656804764}]},"connections":{"Switch":{"main":[[{"node":"audio_id","type":"main","index":0}],[{"node":"chatInput","type":"main","index":0}]]},"AI Agent":{"main":[[{"node":"chatOutput","type":"main","index":0}]]},"audio_id":{"main":[[{"node":"download_audio","type":"main","index":0}]]},"chatInput":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"MCP Client":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"audioInput":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"chatOutput":{"main":[[{"node":"sendMessage","type":"main","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"complete_task":{"ai_tool":[[{"node":"MCP Server Trigger","type":"ai_tool","index":0}]]},"download_audio":{"main":[[{"node":"transcribeAudio","type":"main","index":0}]]},"transcribeAudio":{"main":[[{"node":"audioInput","type":"main","index":0}]]},"Incoming Message":{"main":[[{"node":"Switch","type":"main","index":0}]]},"get_todays_tasks":{"ai_tool":[[{"node":"MCP Server Trigger","type":"ai_tool","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"create_todays_task":{"ai_tool":[[{"node":"MCP Server Trigger","type":"ai_tool","index":0}]]},"get_upcoming_tasks":{"ai_tool":[[{"node":"MCP Server Trigger","type":"ai_tool","index":0}]]},"create_upcoming_task":{"ai_tool":[[{"node":"MCP Server Trigger","type":"ai_tool","index":0}]]}}}


name: Build a Chatbot, Voice and Phone Agent with Voiceflow, Google Calendar and RAG
author_name: Davide
author_username: n3witalia
categories: []
created_at: 2025-04-22T06:42:30.604Z
updated_at: 2025-04-22T06:42:30.604Z
url: https://n8n.io/workflows/3657
scraped_at: 2025-07-06 21:16:30
description:
  Voiceflow is a no-code platform that allows you to design, prototype, and deploy conversational assistants across multiple channels—such as chat, voice, and phone—with advanced logic and natural language understanding. It supports integration with APIs, webhooks, and even tools like Twilio for phone agents. It's perfect for building customer support agents, voice bots, or intelligent assistants.

  This workflow connects n8n and Voiceflow with tools like Google Calendar, Qdrant (vector database), OpenAI, and an order tracking API to power a smart, multi-channel conversational agent.



  There are 3 main webhook endpoints in n8n that Voiceflow interacts with:

  n8n_order – receives user input related to order tracking, queries an API, and responds with tracking status.
  n8n_appointment – processes appointment booking, reformats date input using OpenAI, and creates a Google Calendar event.
  n8n_rag – handles general product/service questions using a RAG (Retrieval-Augmented Generation) system backed by:
     Google Drive document ingestion,
     Qdrant vector store for search,
     and OpenAI models for context-based answers.

  Each webhook is connected to a corresponding "Capture" block inside Voiceflow, which sends data to n8n and waits for the response.

  How It Works  
  This n8n workflow integrates Voiceflow for chatbot/voice interactions, Google Calendar for appointment scheduling, and RAG (Retrieval-Augmented Generation) for knowledge-based responses. Here’s the flow:  

  Trigger**:  
    Three webhooks (n8n_order, n8n_appointment, n8n_rag) receive inputs from Voiceflow (chat, voice, or phone calls).  
    Each webhook routes requests to specific functions:  
      Order Tracking: Fetches order status via an external API.  
      Appointment Scheduling: Uses OpenAI to parse dates, creates Google Calendar events, and confirms via WhatsApp.  
      RAG System: Queries a Qdrant vector store (populated with Google Drive documents) to answer customer questions using GPT-4.  

  AI Processing**:  
    OpenAI Chains: Convert natural language dates to Google Calendar formats and generate responses.  
    RAG Pipeline: Embeds documents (via OpenAI), stores them in Qdrant, and retrieves context-aware answers.  
    Voiceflow Integration: Routes responses back to Voiceflow for multi-channel delivery (chat, voice, or phone).  

  Outputs**:  
    Confirmation messages (e.g., "Event created successfully").  
    Dynamic responses for orders, appointments, or product support. 

  Setup Steps  

  Prerequisites:  
  APIs**:  
    Google Calendar & Drive OAuth credentials.  
    Qdrant vector database (hosted or cloud).  
    OpenAI API key (for GPT-4 and embeddings).  

  Configuration:  
  Qdrant Setup:  
     Run the "Create collection" and "Refresh collection" nodes to initialize the vector store.  
     Populate it with documents using the Google Drive → Qdrant pipeline (embeddings generated via OpenAI).  

  Voiceflow Webhooks:  
     Link Voiceflow’s "Captures" to n8n’s webhook URLs (n8n_order, n8n_appointment, n8n_rag).  

  Google Calendar:  
     Authenticate the Google Calendar node and set event templates (e.g., summary, description).  

  RAG System:  
     Configure the Qdrant vector store and OpenAI embeddings nodes.  
     Adjust the Retrieve Agent’s system prompt for domain-specific queries (e.g., electronics store support).   

  Optional:  
  Add Twilio for phone-agent capabilities.  
  Customize OpenAI prompts for tone/accuracy.  




  PS. You can import a Twilio number to assign it to your agent for becoming a Phone Agent

  Need help customizing?  
  Contact me for consulting and support or add me on Linkedin

nodes_used:
  ["n8n-nodes-base.httpRequest","n8n-nodes-base.googleDrive","n8n-nodes-base.googleCalendar","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.chainLlm","@n8n/n8n-nodes-langchain.embeddingsOpenAi","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.textSplitterTokenSplitter","@n8n/n8n-nodes-langchain.documentDefaultDataLoader","@n8n/n8n-nodes-langchain.vectorStoreQdrant","@n8n/n8n-nodes-langchain.toolVectorStore"]

workflow_json:
  {"id":"MMDt8lGtac2oU8nI","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462","templateCredsSetupCompleted":true},"name":"Build a Chatbot, Voice Agent and Phone Agent with Voiceflow, Google Calendar and RAG","tags":[],"nodes":[{"id":"20605948-5277-4fd7-9ba0-63f645bf2dcc","name":"n8n_order","type":"n8n-nodes-base.webhook","position":[-340,-140],"webhookId":"9ff7a394-5b4b-4790-a96b-c41c4ba27fa5","parameters":{"path":"9ff7a394-5b4b-4790-a96b-c41c4ba27fa5","options":{},"responseMode":"responseNode"},"typeVersion":2},{"id":"9ef7971e-f679-4d5e-b347-3238d51a06d6","name":"Google Calendar","type":"n8n-nodes-base.googleCalendar","position":[300,280],"parameters":{"end":"={{ $json.output.end }}","start":"={{ $json.output.start }}","calendar":{"__rl":true,"mode":"list","value":"info@n3w.it","cachedResultName":"info@n3w.it"},"additionalFields":{"summary":"=Event title with {{ $('n8n_appointment').item.json.query.Email }}","description":"Event description"}},"credentials":{"googleCalendarOAuth2Api":{"id":"8RFK3u13g2PJEGa9","name":"Google Calendar account"}},"typeVersion":1.3},{"id":"17b9f162-c4a3-43ec-b640-a68ebc67b0c9","name":"OpenAI Chat Model3","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-120,480],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"4zwP0MSr8zkNvvV9","name":"OpenAi account"}},"typeVersion":1.2},{"id":"5b40db3c-6c98-4fea-9c3b-98ba7e13bc30","name":"Concert start date","type":"@n8n/n8n-nodes-langchain.chainLlm","position":[-80,280],"parameters":{"text":"=Convert this date to a compatible format for Google Calendar APIs for the start date, and for the end date add 1 hour to the start date.\n\nHere is the start date:\n{{ $json.query.Appointment_date }}","promptType":"define","hasOutputParser":true},"typeVersion":1.6},{"id":"8931d21a-7c30-40ae-b0b0-1f5f6868b3a3","name":"n8n_appointment","type":"n8n-nodes-base.webhook","position":[-340,280],"webhookId":"f5edfe92-649b-40da-ab35-f818ccb55ad4","parameters":{"path":"f5edfe92-649b-40da-ab35-f818ccb55ad4","options":{},"responseMode":"responseNode"},"typeVersion":2},{"id":"fa3e66ca-de09-496b-be14-483b33386e07","name":"Retrive Qdrant Vector Store","type":"@n8n/n8n-nodes-langchain.vectorStoreQdrant","position":[20,1280],"parameters":{"options":{},"qdrantCollection":{"__rl":true,"mode":"list","value":"scarperia","cachedResultName":"scarperia"}},"credentials":{"qdrantApi":{"id":"iyQ6MQiVaF3VMBmt","name":"QdrantApi account"}},"typeVersion":1},{"id":"ea7be112-1949-47b7-b68b-ae2f3a7b1b71","name":"Embeddings OpenAI2","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[-20,1460],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"4zwP0MSr8zkNvvV9","name":"OpenAi account"}},"typeVersion":1.2},{"id":"e61ff57f-a109-41e0-87f3-522b1fa78dd6","name":"RAG","type":"@n8n/n8n-nodes-langchain.toolVectorStore","position":[180,1080],"parameters":{"name":"company_data","description":"Retrive data about company knowledge from vector store"},"typeVersion":1},{"id":"fce158b8-73a3-42c1-baf3-9f2ae979fe15","name":"OpenAI Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-20,1080],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"4zwP0MSr8zkNvvV9","name":"OpenAi account"}},"typeVersion":1.2},{"id":"e2bcfa68-3642-4e49-89cb-e08faade984c","name":"OpenAI Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[340,1300],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"4zwP0MSr8zkNvvV9","name":"OpenAi account"}},"typeVersion":1.2},{"id":"2a79c66c-040b-4ca2-ad91-a0683d0d2996","name":"Retrive Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[60,860],"parameters":{"text":"={{ $json.query.Question }}","agent":"conversationalAgent","options":{"systemMessage":"You are an AI-powered assistant for an electronics store. Your primary goal is to assist customers by providing accurate and helpful information about products, troubleshooting tips, and general support. Use the provided knowledge base (retrieved documents) to answer questions with precision and professionalism.\n\n**Guidelines**:\n1. **Product Information**:\n   - Provide detailed descriptions of products, including specifications, features, and compatibility.\n   - Highlight key selling points and differences between similar products.\n   - Mention availability, pricing, and promotions if applicable.\n\n2. **Technical Support**:\n   - Offer step-by-step troubleshooting guides for common issues.\n   - Suggest solutions for setup, installation, or configuration problems.\n   - If the issue is complex, recommend contacting the store’s support team for further assistance.\n\n3. **Customer Service**:\n   - Respond politely and professionally to all inquiries.\n   - If a question is unclear, ask for clarification to provide the best possible answer.\n   - For order-related questions (e.g., status, returns, or cancellations), guide customers on how to proceed using the store’s systems.\n\n4. **Knowledge Base Usage**:\n   - Always reference the provided knowledge base (retrieved documents) to ensure accuracy.\n   - If the knowledge base does not contain relevant information, inform the customer and suggest alternative resources or actions.\n\n5. **Tone and Style**:\n   - Use a friendly, approachable, and professional tone.\n   - Avoid technical jargon unless the customer demonstrates familiarity with the topic.\n   - Keep responses concise but informative.\n\n**Example Interactions**:\n1. **Product Inquiry**:\n   - Customer: \"What’s the difference between the XYZ Smartwatch and the ABC Smartwatch?\"\n   - AI: \"The XYZ Smartwatch features a longer battery life (up to 7 days) and built-in GPS, while the ABC Smartwatch has a brighter AMOLED display and supports wireless charging. Both are compatible with iOS and Android devices. Would you like more details on either product?\"\n\n2. **Technical Support**:\n   - Customer: \"My wireless router isn’t connecting to the internet.\"\n   - AI: \"Please try the following steps: 1) Restart your router and modem. 2) Ensure all cables are securely connected. 3) Check if the router’s LED indicators show a stable connection. If the issue persists, you may need to reset the router to factory settings. Would you like a detailed guide for resetting your router?\"\n\n3. **Customer Service**:\n   - Customer: \"How do I return a defective product?\"\n   - AI: \"To return a defective product, please visit our Returns Portal on our website and enter your order number. You’ll receive a return label and instructions. If you need further assistance, our support team is available at support@electronicsstore.com.\"\n\n**Limitations**:\n- If the question is outside the scope of the knowledge base or requires human intervention, inform the customer and provide contact details for the appropriate department.\n- Do not provide speculative or unverified information. Always rely on the knowledge base or direct the customer to official resources."},"promptType":"define"},"typeVersion":1.7},{"id":"be516c9c-d2fb-4dea-9a3b-9674be5ea689","name":"n8n_rag","type":"n8n-nodes-base.webhook","position":[-360,860],"webhookId":"edb1e894-1210-4902-a34f-a014bbdad8d8","parameters":{"path":"edb1e894-1210-4902-a34f-a014bbdad8d8","options":{},"responseMode":"responseNode"},"typeVersion":2},{"id":"2412721d-7353-4a27-8068-5c90872c7a51","name":"Tracking response","type":"n8n-nodes-base.set","position":[360,-140],"parameters":{"options":{},"assignments":{"assignments":[{"id":"86f332ff-7b89-4dd4-8df9-06c081625d33","name":"text","type":"string","value":"=Your order status is: {{ $json.status }}"}]}},"typeVersion":3.4},{"id":"4965d781-1452-42c9-8a84-baacb5abe97f","name":"Calendar response","type":"n8n-nodes-base.set","position":[500,280],"parameters":{"options":{},"assignments":{"assignments":[{"id":"0fe6fe50-9263-479a-ab01-ca1d15ce2412","name":"text","type":"string","value":"L'evento è stato creato con successo"}]}},"typeVersion":3.4},{"id":"5311be28-2878-41ce-a70f-4e4aebcea0f9","name":"Webhook tracking response","type":"n8n-nodes-base.respondToWebhook","position":[700,-140],"parameters":{"options":{}},"typeVersion":1.1},{"id":"84d8558f-e6fd-400e-ae2e-0b5fec309561","name":"API URL Tracking","type":"n8n-nodes-base.httpRequest","position":[20,-140],"parameters":{"url":"URL_TRACKING","options":{},"sendBody":true,"bodyParameters":{"parameters":[{"name":"Order number","value":"={{ $json.Order_number }}"},{"name":"Email","value":"={{ $json.Order_number }}"}]}},"typeVersion":4.2},{"id":"32eb8645-c56e-4db4-8870-f28161cba048","name":"Webhook calendar response","type":"n8n-nodes-base.respondToWebhook","position":[700,280],"parameters":{"options":{}},"typeVersion":1.1},{"id":"72e7f085-d1e7-4967-aaa5-161ff0e83c06","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[140,480],"parameters":{"schemaType":"manual","inputSchema":"{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"start\": {\n\t\t\t\"type\": \"string\"\n\t\t},\n\t\t\"end\": {\n\t\t\t\"type\": \"string\"\n\t\t}\n\t}\n}"},"typeVersion":1.2},{"id":"3822b875-73f0-4700-8fc4-e4d3285f593a","name":"Webhook RAG response","type":"n8n-nodes-base.respondToWebhook","position":[700,860],"parameters":{"options":{}},"typeVersion":1.1},{"id":"0b43f63b-3c00-4db4-8b28-9938add9fdbe","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[1100,-1320],"parameters":{"width":1140,"height":2200,"content":"# STEP 6 - VOICEFLOW\n\n- Register on [Voiceflow](https://www.voiceflow.com/) \n- Create the workflow as shown in the following image\n![image](https://i.postimg.cc/3rSPwMn2/langflow.png)\n- There are 3 \"Captures\":\n-- n8n_order\n-- n8n_appointment\n-- n8n_rag\n- Add in the created functions the url of the corresponding n8n Webhook trigger node\n- Test your Agent\n- Get your projectID\n- In the Widget section choose Chat or Voice and copy the installation script\n![image](https://i.postimg.cc/855gyTZP/voiceflow-agent.png)\n![image](https://i.postimg.cc/5Nn4Sk43/voiceflow-agent2.png)\n\nPS. You can import a Twilio number to assign it to your agent for becoming a Phone Agent\n![image](https://i.postimg.cc/cLymTTFv/voiceflow-agent3.png)\n\n"},"typeVersion":1},{"id":"589165c8-920d-40e3-8e28-50e94dd37555","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-380,-1120],"parameters":{},"typeVersion":1},{"id":"74c314bb-c445-42f8-8f9d-2ab646486044","name":"Qdrant Vector Store","type":"@n8n/n8n-nodes-langchain.vectorStoreQdrant","position":[600,-1000],"parameters":{"mode":"insert","options":{},"qdrantCollection":{"__rl":true,"mode":"id","value":"="}},"credentials":{"qdrantApi":{"id":"iyQ6MQiVaF3VMBmt","name":"QdrantApi account"}},"typeVersion":1},{"id":"01c05ac3-ac5c-4f1a-a756-db8de4a30e56","name":"Create collection","type":"n8n-nodes-base.httpRequest","position":[-80,-1260],"parameters":{"url":"https://QDRANTURL/collections/COLLECTION","method":"POST","options":{},"jsonBody":"{\n  \"filter\": {}\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]}},"credentials":{"httpHeaderAuth":{"id":"qhny6r5ql9wwotpn","name":"Qdrant API (Hetzner)"}},"typeVersion":4.2},{"id":"2d7adb45-aae7-4617-b1d1-5a23f3eb3b20","name":"Refresh collection","type":"n8n-nodes-base.httpRequest","position":[-80,-1000],"parameters":{"url":"https://QDRANTURL/collections/COLLECTION/points/delete","method":"POST","options":{},"jsonBody":"{\n  \"filter\": {}\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]}},"credentials":{"httpHeaderAuth":{"id":"qhny6r5ql9wwotpn","name":"Qdrant API (Hetzner)"}},"typeVersion":4.2},{"id":"5e406bd7-8a93-4db2-8d3d-e92e8c9f4f01","name":"Get folder","type":"n8n-nodes-base.googleDrive","position":[140,-1000],"parameters":{"filter":{"driveId":{"__rl":true,"mode":"list","value":"My Drive","cachedResultUrl":"https://drive.google.com/drive/my-drive","cachedResultName":"My Drive"},"folderId":{"__rl":true,"mode":"id","value":"=test-whatsapp"}},"options":{},"resource":"fileFolder"},"credentials":{"googleDriveOAuth2Api":{"id":"HEy5EuZkgPZVEa9w","name":"Google Drive account (n3w.it)"}},"typeVersion":3},{"id":"f1f883fb-c9d1-42e6-98c2-791ed85e959f","name":"Download Files","type":"n8n-nodes-base.googleDrive","position":[360,-1000],"parameters":{"fileId":{"__rl":true,"mode":"id","value":"={{ $json.id }}"},"options":{"googleFileConversion":{"conversion":{"docsToFormat":"text/plain"}}},"operation":"download"},"credentials":{"googleDriveOAuth2Api":{"id":"HEy5EuZkgPZVEa9w","name":"Google Drive account (n3w.it)"}},"typeVersion":3},{"id":"5fd88e03-3638-4d38-8df4-246e4a5f2bda","name":"Embeddings OpenAI","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[580,-800],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"4zwP0MSr8zkNvvV9","name":"OpenAi account"}},"typeVersion":1.1},{"id":"3740a841-e272-44f9-b76d-51fb90137fd3","name":"Default Data Loader","type":"@n8n/n8n-nodes-langchain.documentDefaultDataLoader","position":[760,-800],"parameters":{"options":{},"dataType":"binary"},"typeVersion":1},{"id":"075d1038-d1fd-4527-8eda-961f20c7869a","name":"Token Splitter","type":"@n8n/n8n-nodes-langchain.textSplitterTokenSplitter","position":[760,-600],"parameters":{"chunkSize":300,"chunkOverlap":30},"typeVersion":1},{"id":"57cc8eaf-26b3-480f-ab5d-c8646519cfa3","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[120,-1320],"parameters":{"color":6,"width":880,"height":220,"content":"# STEP 1\n\n## Create Qdrant Collection\nChange:\n- QDRANTURL\n- COLLECTION"},"typeVersion":1},{"id":"70bc0676-c0ea-4de8-8659-bfb8b0ea653f","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-100,-1060],"parameters":{"color":4,"width":620,"height":400,"content":"# STEP 2\n\n\n\n\n\n\n\n\n\n\n\n\n## Documents vectorization with Qdrant and Google Drive\nChange:\n- QDRANTURL\n- COLLECTION"},"typeVersion":1},{"id":"411c4f55-ae41-49b5-a821-df1a3d8fefec","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-380,660],"parameters":{"color":5,"width":1220,"content":"# STEP 5\nIf required retrive the informations by RAG system"},"typeVersion":1},{"id":"49d1fe78-4c38-4508-84c3-3a571ad9a2b0","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-360,-360],"parameters":{"color":5,"width":1220,"content":"# STEP 3\nIf required retrive the informations by Order system\n- Set your API URL Tracking service"},"typeVersion":1},{"id":"23d42754-0126-4b3a-91b0-b489ef83b36c","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-360,80],"parameters":{"color":5,"width":1220,"content":"# STEP 4\nIf required retrive the informations by Appointment system"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"20a19983-4edb-4179-a2d2-e2f53d0daf85","connections":{"RAG":{"ai_tool":[[{"node":"Retrive Agent","type":"ai_tool","index":0}]]},"n8n_rag":{"main":[[{"node":"Retrive Agent","type":"main","index":0}]]},"n8n_order":{"main":[[{"node":"API URL Tracking","type":"main","index":0}]]},"Get folder":{"main":[[{"node":"Download Files","type":"main","index":0}]]},"Retrive Agent":{"main":[[{"node":"Webhook RAG response","type":"main","index":0}]]},"Download Files":{"main":[[{"node":"Qdrant Vector Store","type":"main","index":0}]]},"Token Splitter":{"ai_textSplitter":[[{"node":"Default Data Loader","type":"ai_textSplitter","index":0}]]},"Google Calendar":{"main":[[{"node":"Calendar response","type":"main","index":0}]]},"n8n_appointment":{"main":[[{"node":"Concert start date","type":"main","index":0}]]},"API URL Tracking":{"main":[[{"node":"Tracking response","type":"main","index":0}]]},"Calendar response":{"main":[[{"node":"Webhook calendar response","type":"main","index":0}]]},"Embeddings OpenAI":{"ai_embedding":[[{"node":"Qdrant Vector Store","type":"ai_embedding","index":0}]]},"Tracking response":{"main":[[{"node":"Webhook tracking response","type":"main","index":0}]]},"Concert start date":{"main":[[{"node":"Google Calendar","type":"main","index":0}]]},"Embeddings OpenAI2":{"ai_embedding":[[{"node":"Retrive Qdrant Vector Store","type":"ai_embedding","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"RAG","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model2":{"ai_languageModel":[[{"node":"Retrive Agent","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model3":{"ai_languageModel":[[{"node":"Concert start date","type":"ai_languageModel","index":0}]]},"Refresh collection":{"main":[[{"node":"Get folder","type":"main","index":0}]]},"Default Data Loader":{"ai_document":[[{"node":"Qdrant Vector Store","type":"ai_document","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"Concert start date","type":"ai_outputParser","index":0}]]},"Retrive Qdrant Vector Store":{"ai_vectorStore":[[{"node":"RAG","type":"ai_vectorStore","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Create collection","type":"main","index":0},{"node":"Refresh collection","type":"main","index":0}]]}}}


name: Publish image & video to multiple social media (X, Instagram, Facebook and more)
author_name: Davide
author_username: n3witalia
nodes_used: ["n8n-nodes-base.httpRequest"]
categories: []
created_at: 2025-04-23T10:11:00.160Z
updated_at: 2025-04-23T10:11:00.160Z
url: https://n8n.io/workflows/3669
scraped_at: 2025-07-06 21:16:30
description:
  This Workflow streamlines the process of publishing posts (image or video) to multiple social media platforms using a unified form and a third-party API service called Upload-Post.

  The automation starts with a form trigger, allowing users to submit content (text and media) through a simple frontend interface. Users select the platform (Instagram, LinkedIn, Facebook, X, TikTok, Threads), choose the profile name, write a caption, and upload a photo or video.

  How It Works  
  Automates cross-platform social media posting via Upload-Post, handling both images (JPEG) and videos (MP4). Here’s the process:  

  Trigger**:  
    A form submission captures user inputs:  
      Platform (Instagram, LinkedIn, Facebook, X, TikTok, Threads).  
      Account (pre-configured profile name).  
      Caption and file (image/video).  
      Optional Facebook Page ID for targeted posting.  

  Routing**:  
    The "Video or Photo?" Switch node checks the file’s MIME type:  
      Image: Routes to the "Post photo" HTTP node (uploads via upload_photos API).  
      Video: Routes to the "Post video" HTTP node (uploads via upload API).  

  API Integration**:  
    Both nodes send data to Upload-Post.com’s API, including:  
      Caption, account name, platform, and file binary.  
      Facebook ID (if provided).  

  Success/Failure Handling**:  
    The "Result Photo/Video" nodes parse the API response.  

  Setup Steps  

  Prerequisites:  
  Upload-Post.com API Key**:  
    Get it from the API Keys dashboard.  
    Free tier allows 10 uploads/month.  

  Configuration:  
  API Authentication:  
     In the HTTP Request nodes (Post photo/Post video), set the Authorization header:  
       Name: Authorization  
       Value: Apikey YOUR_API_KEY_HERE.  

  Form Customization:  
     Adjust the "On form submission" node to:  
       Add/remove platforms (e.g., YouTube when approved).  
       Modify file type restrictions (default: .jpg, .mp4).  

  Account Mapping:  
     Ensure the "Account" field matches profiles configured in Upload-Post.com (e.g., test1, test2).  

  Facebook Page Integration:  
     Optional: Add a Facebook Page ID field for page-specific posts.  

  Testing:  
     Submit test forms with images/videos.  
     Verify API responses and success/failure messages.  

  Optional Enhancements:  
  Add error logging (e.g., save failed attempts to a database).  
  Extend to YouTube once API support is confirmed.  

  Key Features:  
  Multi-Platform**: Post to 6+ social networks simultaneously.  
  User-Friendly**: Simple form interface for non-technical users.  
  Error Handling**: Clear feedback for success/failure cases.  

  Need help customizing?  
  Contact me for consulting and support or add me on Linkedin. 

workflow_json:
  {"id":"r1u4HOJu5j5sP27x","meta":{"instanceId":"a4bfc93e975ca233ac45ed7c9227d84cf5a2329310525917adaf3312e10d5462"},"name":"Social Media Publisher","tags":[],"nodes":[{"id":"f5050652-6170-41c6-b3c3-0f6616c9d575","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[-380,120],"webhookId":"bb578d47-feaa-4973-96df-659089838de5","parameters":{"options":{},"formTitle":"Post Publisher","formFields":{"values":[{"fieldType":"dropdown","fieldLabel":"Platform","fieldOptions":{"values":[{"option":"instagram"},{"option":"linkedin"},{"option":"facebook"},{"option":"x"},{"option":"tiktok"},{"option":"threads"}]},"requiredField":true},{"fieldLabel":"Account","placeholder":"User Profile name set on Upload-post.com","requiredField":true},{"fieldType":"textarea","fieldLabel":"Caption","requiredField":true},{"fieldType":"file","fieldLabel":"Upload","multipleFiles":false,"requiredField":true,"acceptFileTypes":".jpg,.mp4"},{"fieldLabel":"Facebook Id","placeholder":"Facebook page Id (eg. 00000111122222)"}]}},"typeVersion":2.2},{"id":"e9d8b8c9-3e40-420d-98c3-82c92f1c53c7","name":"Post photo","type":"n8n-nodes-base.httpRequest","position":[220,-180],"parameters":{"url":"https://api.upload-post.com/api/upload_photos","method":"POST","options":{},"sendBody":true,"contentType":"multipart-form-data","authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"title","value":"={{ $json.Caption }}"},{"name":"user","value":"={{ $json.Account }}"},{"name":"platform[]","value":"={{ $json.Platform }}"},{"name":"photos[]","parameterType":"formBinaryData","inputDataFieldName":"=Upload"},{"name":"facebook_id","value":"={{ $('On form submission').item.json['Facebook Id'] }}"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"DEE2XGvhGodgbAJh","name":"Upload-post.com API"}},"typeVersion":4.2},{"id":"04103be2-a1d8-4b00-942b-44e13dffa666","name":"Post video","type":"n8n-nodes-base.httpRequest","position":[220,280],"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":"={{ $json.Caption }}"},{"name":"user","value":"={{ $json.Account }}"},{"name":"platform[]","value":"={{ $json.Platform }}"},{"name":"video","parameterType":"formBinaryData","inputDataFieldName":"=Upload"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"DEE2XGvhGodgbAJh","name":"Upload-post.com API"}},"typeVersion":4.2},{"id":"e7803375-20b0-4e12-80a4-b102ba48b6ba","name":"KO Video","type":"n8n-nodes-base.form","position":[880,380],"webhookId":"d03e4286-f252-4a35-a65e-ea8ac96222e4","parameters":{"options":{},"operation":"completion","completionTitle":"=Oops","completionMessage":"There was an error"},"typeVersion":1},{"id":"91f2b501-4021-4ecc-9cc3-4e804d020135","name":"OK Video","type":"n8n-nodes-base.form","position":[880,180],"webhookId":"d03e4286-f252-4a35-a65e-ea8ac96222e4","parameters":{"options":{},"operation":"completion","completionTitle":"=Congratulations!","completionMessage":"Your post has been published correctly"},"typeVersion":1},{"id":"b3eead97-f995-42dc-b937-6d05f284f601","name":"KO Photo","type":"n8n-nodes-base.form","position":[880,-80],"webhookId":"d03e4286-f252-4a35-a65e-ea8ac96222e4","parameters":{"options":{},"operation":"completion","completionTitle":"=Oops","completionMessage":"There was an error"},"typeVersion":1},{"id":"8ead4dfa-cb9e-4ab4-b52c-7a681876269f","name":"OK Photo","type":"n8n-nodes-base.form","position":[880,-280],"webhookId":"d03e4286-f252-4a35-a65e-ea8ac96222e4","parameters":{"options":{},"operation":"completion","completionTitle":"=Congratulations!","completionMessage":"Your post has been published correctly"},"typeVersion":1},{"id":"a5fba676-4e7b-42e2-af36-e9d63458870b","name":"Success Photo?","type":"n8n-nodes-base.if","position":[640,-180],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"47eee8ce-0237-48f2-b67f-04021d3acda2","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.result }}\n","rightValue":"true"}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"310853de-ab7e-481e-8efa-5a681f08032b","name":"Success Video?","type":"n8n-nodes-base.if","position":[660,280],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"and","conditions":[{"id":"47eee8ce-0237-48f2-b67f-04021d3acda2","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.result }}\n","rightValue":"true"}]},"looseTypeValidation":true},"typeVersion":2.2},{"id":"81ec87fc-9298-4cd6-8a46-45ee6cb050b3","name":"Result Photo","type":"n8n-nodes-base.set","position":[440,-180],"parameters":{"options":{},"assignments":{"assignments":[{"id":"551c5179-055a-415e-bf17-61f2a5dd2769","name":"=result","type":"string","value":"={{ $json.results[$('Video or Photo?').item.json.Platform].success.toBoolean() }}"}]}},"typeVersion":3.4},{"id":"936ac765-0e7c-411d-b70d-bdfbe8e180a6","name":"Result Video","type":"n8n-nodes-base.set","position":[440,280],"parameters":{"options":{},"assignments":{"assignments":[{"id":"551c5179-055a-415e-bf17-61f2a5dd2769","name":"=result","type":"string","value":"={{ $json.results[$('Video or Photo?').item.json.Platform].success.toBoolean() }}"}]}},"typeVersion":3.4},{"id":"3a3d66ae-7ecd-43aa-a905-10afdab753b3","name":"Video or Photo?","type":"n8n-nodes-base.switch","position":[-120,120],"parameters":{"rules":{"values":[{"outputKey":"Image","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"879af56a-8979-4d9d-9acd-6009d821f6a7","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $json.Upload.mimetype }}","rightValue":"image/jpeg"}]},"renameOutput":true},{"outputKey":"Video","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"d7ee147d-d775-4b81-b043-0873c535b400","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $json.Upload.mimetype }}","rightValue":"video/mp4"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"76d1cc06-8bb5-43cd-8dcc-2da1656b0335","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-400,-1020],"parameters":{"width":1380,"height":680,"content":"## SETTINGS\n\n- Find your API key in your [Upload-Post Manage Api Keys](https://app.upload-post.com/) 10 FREE uploads per month\n- Set the the \"Auth Header\":\n-- Name: Authorization\n-- Value: Apikey YOUR_API_KEY_HERE\n- Create profiles to manage your social media accounts. The \"Profile\" you choose will be used in the field \"Account\" on form submission (eg. test1 or test2).  \n\n![image](https://i.postimg.cc/N0BHdcQ4/uploadpost.png)\n\nApr-2025: YouTube integration is currently being verified by Google, and may not work as expected.\n"},"typeVersion":1},{"id":"e9b40e23-cde9-459d-b490-8adda6b9253f","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-400,-1240],"parameters":{"color":3,"width":1380,"height":180,"content":"## Upload video and photo on TikTok, X, Facebook, Youtube, Instagram, Threads and Linkedin\n\nSimplify your social media workflow with our powerful platform designed for content creators and marketers.\n\nUpload your video once and let Upload-Post distribute it across all your connected social media accounts effortlessly."},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"ac29ff60-2d87-4646-ae63-ab543f3849de","connections":{"Post photo":{"main":[[{"node":"Result Photo","type":"main","index":0}]]},"Post video":{"main":[[{"node":"Result Video","type":"main","index":0}]]},"Result Photo":{"main":[[{"node":"Success Photo?","type":"main","index":0}]]},"Result Video":{"main":[[{"node":"Success Video?","type":"main","index":0}]]},"Success Photo?":{"main":[[{"node":"OK Photo","type":"main","index":0}],[{"node":"KO Photo","type":"main","index":0}]]},"Success Video?":{"main":[[{"node":"OK Video","type":"main","index":0}],[{"node":"KO Video","type":"main","index":0}]]},"Video or Photo?":{"main":[[{"node":"Post photo","type":"main","index":0}],[{"node":"Post video","type":"main","index":0}]]},"On form submission":{"main":[[{"node":"Video or Photo?","type":"main","index":0}]]}}}


name: Medical Q&A Chatbot for Urology using RAG with Pinecone and GPT-4o
author_name: HoangSP
author_username: hoangsp
categories: []
created_at: 2025-04-23T10:20:39.925Z
updated_at: 2025-04-23T10:20:39.925Z
url: https://n8n.io/workflows/3670
scraped_at: 2025-07-06 21:16:30
description:
  Medical Q&A Chatbot for Urology using RAG with Pinecone and GPT-4o

  This template provides an AI-powered Q&A assistant for the Urology domain using Retrieval-Augmented Generation (RAG). It uses Pinecone for vector search and GPT-4o for conversational responses.

  🧠 Use Case

  This chatbot is designed for clinics or medical pages that want to automate question answering for Urology-related conditions. It uses a vector store of domain knowledge to return verified responses.

  🔧 Requirements

  ✅ OpenAI API key (GPT-4o or GPT-4o-mini)
  ✅ Pinecone account with an active index
  ✅ Verified Urology documents embedded into Pinecone

  ⚙️ Setup Instructions

  Create a Pinecone vector index and connect it using the Pinecone credentials node.
  Upload Urology-related documents to embed using the Create Embeddings for Urology Docs node.
  Customize the chatbot system message to reflect your medical specialty.
  Deploy this chatbot on your website or link it with Telegram via the chat trigger node.

  🛠️ Components

  chatTrigger: Listens for user messages and starts the workflow.
  Medical AI Agent: GPT-based agent guided by domain-specific instructions.
  RAG Tool Vector Store: Fetches relevant documents from Pinecone using vector search.
  Memory Buffer: Maintains conversation context.
  Create Embeddings for Urology Docs: Encodes documents into vector format.

  📝 Customization

  You can replace the knowledge base with any other medical domain by:
  Updating the documents stored in Pinecone.
  Modifying the system prompt in the AI Agent node.

  📣 CTA

  This chatbot is ideal for clinics, medical consultants, or educational websites wanting a reliable AI assistant in Urology.

nodes_used:
  ["@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.embeddingsOpenAi","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.vectorStorePinecone","@n8n/n8n-nodes-langchain.toolVectorStore"]

workflow_json:
  {"id":"q07AalYfXfiMc0p2","meta":{"instanceId":"2b69b24ad1a51b447e1a0d6f8c70b16aca715ccfaf123eb531f92865766fce1c","templateCredsSetupCompleted":true},"name":"Medical Q&A Assistant for Urology using RAG with Pinecone and GPT-4o","tags":[],"nodes":[{"id":"58bf7bd0-00c7-4d7a-98f3-e18d053afa9f","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[100,-20],"webhookId":"27dd7366-236c-4050-9fe0-575818987a21","parameters":{"public":true,"options":{},"initialMessages":"Dr. Hiep - Urologist - Phone: 090xxxxxxx\nInformation provided by a certified urologist\n\n"},"typeVersion":1.1},{"id":"6f689a95-9b4b-45c1-b407-023b05610ed9","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[540,-20],"parameters":{"text":"=Input content: {{ $json.chatInput }}","options":{"systemMessage":"=You are an AI expert specializing in Andrology and Urology.\n\nYour role is to provide user-friendly, medically relevant answers **based entirely on information gathered from the Vector Database**.\n\n⚠️ DO NOT create or assume any outside or fabricated information.\n\n🗣️ Tone & Style:\n- ✅ Clear, simple and informative\n- 🧑‍⚕️ Friendly and easy to understand for non-physician users\n- ❌ Avoid overly clinical or doctor-to-doctor language\n\n📌 Response guidelines:\n- Look at the information content of the previously asked KH for each answer, to synthesize information and make accurate suggestions\n- ❌ Do not speculate or make assumptions\n- ✅ Use only verified vector-based data (collected context)\n- 📝 Format your response with bullet points with emojis/symbols:\n- 📌 Common causes: ...\n- 💊 Symptoms may include: ...\n- ⚠️ Note: ...\n- 🚫 DO NOT provide a treatment plan or prescription medicine\n\n❓After answering, gently ask 1–2 follow-up questions to gather more context for the user. Avoid the stiff Q&A style — use friendly, caring expressions such as:\n- \"Have you tried anything to relieve the discomfort?\"\n- \"Can you share how long you've had this condition?\"\nUse open-ended questions, such as: Are there any other issues that you're concerned about that we'd like you to address.\n\nLeave the customer:\n- Would you like me to summarize the issues you're describing, and send the content back to you...\nWhen the customer wants to see the doctor or make an appointment, send the information:\n👨‍⚕️ To make an appointment, you can:\n\nContact Dr. Hiep directly, CK II - Andrology - Urology. Zalo: 0777471932\nHave information about the symptoms you are experiencing ready to help your doctor better understand your condition.\n\n🚫 If the vector data does not include relevant information:\nReply politely:\n**\"I do not have enough information to answer this question at this time. Please consider consulting another reliable source or a medical professional.\"**\n\n✅ **Always end your response with a professional Call to Action (CTA):\n\nTôi là trợ lý AI. Để được tư vấn chuyên môn, vui lòng liên hệ với:\nBác sĩ Hiệp, CK II Tiết niệu - Nam Khoa\nZalo: 0777471932\n🌐 **Always reply in Vietnamese.**\n"},"promptType":"define"},"typeVersion":1.9},{"id":"8e0a08fa-9063-4cce-b982-650d54b1dd68","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[460,200],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"ScDgXbCy0e7Omp6y","name":"OpenAi account 3"}},"typeVersion":1.2},{"id":"d9399f27-3fa5-499a-89d2-d3b3aa8ff467","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[620,200],"parameters":{"sessionKey":"={{ $json.sessionId }}","sessionIdType":"customKey"},"typeVersion":1.3},{"id":"6af61985-4453-48ac-9e5a-ea7e5482374a","name":"OpenAI Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[1100,480],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"ScDgXbCy0e7Omp6y","name":"OpenAi account 3"}},"typeVersion":1.2},{"id":"034fea52-646f-4146-908c-e6128d1f764f","name":"Answer questions with a vector store","type":"@n8n/n8n-nodes-langchain.toolVectorStore","position":[900,220],"parameters":{"name":"Knowledge","topK":10,"description":"Urology & Andrology Dataset"},"typeVersion":1},{"id":"4ab86662-617a-4592-b008-062ca5f9cfa7","name":"Pinecone Vector Store","type":"@n8n/n8n-nodes-langchain.vectorStorePinecone","position":[700,380],"parameters":{"options":{},"pineconeIndex":{"__rl":true,"mode":"list","value":"namkhoaa2z","cachedResultName":"namkhoaa2z"}},"credentials":{"pineconeApi":{"id":"wB3phIJE9xu2lIvy","name":"PineconeApi account 2"}},"typeVersion":1.1},{"id":"6e14d1c6-7615-4f2c-84e5-67b94d37d8c9","name":"Embeddings OpenAI","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[720,640],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"ScDgXbCy0e7Omp6y","name":"OpenAi account 3"}},"typeVersion":1.2},{"id":"06831eef-7986-4b56-8eef-94180cfe9a57","name":"🟢 Trigger","type":"n8n-nodes-base.stickyNote","position":[-200,-20],"parameters":{"content":"🟢 Trigger: Activated when a user sends a new message to the chatbot.\n"},"typeVersion":1},{"id":"671e8c95-1585-42cb-9fb7-046266b1eef9","name":"🧠 AI Agent Logic","type":"n8n-nodes-base.stickyNote","position":[420,-120],"parameters":{"width":500,"height":260,"content":"🧠 Main AI logic: Receives user input, gathers context, and generates a friendly response.\n"},"typeVersion":1},{"id":"dc0ddbe5-0025-4998-99a8-4d67c954b6da","name":"🤖 GPT-4o Model","type":"n8n-nodes-base.stickyNote","position":[160,200],"parameters":{"content":"🤖 Uses GPT-4o-mini to understand and generate conversation based on context.\n"},"typeVersion":1},{"id":"a58774f9-9b3c-4e8d-b829-77f1ba8763bf","name":"🧠 Session Memory","type":"n8n-nodes-base.stickyNote","position":[1000,360],"parameters":{"content":"💬 Renders final answer using GPT-4o-mini based on retrieved knowledge.\n"},"typeVersion":1},{"id":"2be54256-0caf-4fe5-9dbc-5ac0db5223bc","name":"📚 Vector Store Search","type":"n8n-nodes-base.stickyNote","position":[560,160],"parameters":{"content":"🧠 Stores user session context to support multi-turn dialogue.\n"},"typeVersion":1},{"id":"87e3319f-a466-4e04-942f-bf32d681f32b","name":"🧩 Pinecone Search","type":"n8n-nodes-base.stickyNote","position":[440,380],"parameters":{"content":"📚 Connects to the medical vector database (RAG) to search for relevant documents.\n"},"typeVersion":1},{"id":"fc8c0d2d-9975-41b0-9732-42660e648610","name":"🧬 Embeddings","type":"n8n-nodes-base.stickyNote","position":[440,620],"parameters":{"content":"🧬 Transforms input into embeddings for Pinecone to use in vector search.\n"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"68ff049a-9917-47de-b3a0-2edf29614efb","connections":{"Simple Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"Embeddings OpenAI":{"ai_embedding":[[{"node":"Pinecone Vector Store","type":"ai_embedding","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"Answer questions with a vector store","type":"ai_languageModel","index":0}]]},"Pinecone Vector Store":{"ai_vectorStore":[[{"node":"Answer questions with a vector store","type":"ai_vectorStore","index":0}]]},"When chat message received":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"Answer questions with a vector store":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]}}}


name: MCP Supabase Server for AI Agent with RAG & Multi-Tenant CRUD
author_name: Luciano Gutierrez
author_username: koresoluciones
nodes_used: ["@n8n/n8n-nodes-langchain.embeddingsOpenAi","@n8n/n8n-nodes-langchain.vectorStoreSupabase"]
categories: []
created_at: 2025-04-23T15:41:14.267Z
updated_at: 2025-04-23T15:41:14.267Z
url: https://n8n.io/workflows/3675
scraped_at: 2025-07-06 21:16:30
description:
  Supabase AI Agent with RAG & Multi-Tenant CRUD  
  Version: 1.0.0  
  n8n Version: 1.88.0+  
  Author: Koresolucoes 
  License: MIT  

  Description  
  A stateful AI agent workflow powered by Supabase and Retrieval-Augmented Generation (RAG). Enables persistent memory, dynamic CRUD operations, and multi-tenant data isolation for AI-driven applications like customer support, task orchestration, and knowledge management.  

  Key Features:  
  🧠 RAG Integration: Leverages OpenAI embeddings and Supabase vector search for context-aware responses.  
  🗃️ Full CRUD: Manage agent_messages, agent_tasks, agent_status, and agent_knowledge in real time.  
  📤 Multi-Tenant Ready: Supports per-user/organization data isolation via dynamic table names and webhooks.  
  🔒 Secure: Role-based access control via Supabase Row Level Security (RLS).  

  Use Cases  
  Customer Support Chatbots: Persist conversation history and resolve queries using institutional knowledge.  
  Automated Task Management: Track and update task statuses dynamically.  
  Knowledge Repositories: Store and retrieve domain-specific information for AI agents.  

  Instructions  
  1. Import Template  
  Go to n8n &gt; Templates &gt; Import from File and upload this workflow.  

  2. Configure Credentials  
  Add your Supabase and OpenAI API keys under Settings &gt; Credentials.  

  3. Set Up Multi-Tenancy (Optional)  
  Dynamic Webhook Path**:  
    Replace the default webhook path with /mcp/tool/supabase/:userId to enable per-user routing.  
  Table Names**:  
    Use a Set Node to dynamically generate table names (e.g., agent_messages_{{userId}}).  

  4. Activate & Test  
  Enable the workflow and send test requests to the webhook URL.  

  Tags  
  AI Agent RAG Supabase CRUD Multi-Tenant OpenAI Automation  

  Screenshots  

  License  
  This template is licensed under the MIT License.  

workflow_json:
  {"id":"oowUGM7ey6gWxzEG","meta":{"instanceId":"6d46e25379ef430a7067964d1096b885c773564549240cb3ad4c087f6cf94bd3","templateCredsSetupCompleted":true},"name":"MCP_SUPABASE_AGENT","tags":[],"nodes":[{"id":"135ceeee-77cd-479f-a0b4-dd72abe23ac4","name":"MCP_SUPABASE","type":"@n8n/n8n-nodes-langchain.mcpTrigger","position":[-1460,1180],"webhookId":"affff59c-9c5c-4a07-b531-616c1d631601","parameters":{"path":"affff59c-9c5c-4a07-b531-616c1d631601"},"typeVersion":1},{"id":"b25040a8-2d70-4d3a-ba58-b8c7164d375e","name":"RAG","type":"@n8n/n8n-nodes-langchain.vectorStoreSupabase","position":[1240,760],"parameters":{"mode":"retrieve-as-tool","topK":5,"options":{},"toolName":"ITERACOES","tableName":{"__rl":true,"mode":"list","value":"documents","cachedResultName":"documents"},"toolDescription":"lembra das interacoes e consulta as instrucoes do system como assim tambem vai guardando o que aprende"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1.1},{"id":"081035c0-ecc2-4924-8f07-da4cbb69fb06","name":"Embeddings OpenAI","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[1500,960],"parameters":{"model":"text-embedding-ada-002","options":{}},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.2},{"id":"361e0a74-b386-4e03-9e7b-5f435f0d8c5f","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-260,120],"parameters":{"width":1380,"height":520,"content":"## AGENT_MESSAGE\n"},"typeVersion":1},{"id":"5aafb3a6-edd1-4154-adab-948db9aad8e7","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-260,720],"parameters":{"width":1380,"height":520,"content":"## AGENT_TASK\n"},"typeVersion":1},{"id":"61b75c2e-b472-4597-a12a-f6027caecf4e","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-260,1320],"parameters":{"width":1380,"height":520,"content":"## AGENT_STATUS\n\n\n"},"typeVersion":1},{"id":"7adc4cd9-cbac-4922-b928-f0b556d6f839","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-260,1900],"parameters":{"width":1380,"height":520,"content":"## AGENT_KNOWLEDGE\n\n"},"typeVersion":1},{"id":"7680abd0-d5f1-41db-96ad-d64c1b857032","name":"DELETE_ROW_INSCRICOES_CURSOS","type":"n8n-nodes-base.supabaseTool","position":[260,2020],"parameters":{"tableId":"agent_knowledge","operation":"delete"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"5c752cf4-6dde-49d9-9328-2ed0731c6d7a","name":"GET_ROW_AGENT_MESSAGE","type":"n8n-nodes-base.supabaseTool","position":[80,260],"parameters":{"tableId":"agent_messages","operation":"get"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"f65e9fd3-a656-473c-a7af-217d9b041aa7","name":"CREATE_ROW_AGENT_MESSAGE","type":"n8n-nodes-base.supabaseTool","position":[-100,260],"parameters":{"tableId":"agent_messages"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"61269957-e6ac-4e5b-adb0-fd610cdff8aa","name":"DELETE_ROW_AGENT_MESSAGE","type":"n8n-nodes-base.supabaseTool","position":[260,260],"parameters":{"tableId":"agent_messages","operation":"delete"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"52db9de5-5610-4b2d-9194-e1551b95a4e6","name":"UPDATE_ROW_AGENT_MESSAGE","type":"n8n-nodes-base.supabaseTool","position":[440,260],"parameters":{"tableId":"agent_messages","operation":"update"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"b43aaea6-7841-4848-9228-2be6dd07a03f","name":"GET_MANY_ROW_AGENT_MESSAGE","type":"n8n-nodes-base.supabaseTool","position":[620,260],"parameters":{"limit":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}","tableId":"agent_messages","operation":"getAll"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"c5347c5e-f9cb-40aa-bca5-249e8c220839","name":"CREATE_ROW_AGENT_TASKS","type":"n8n-nodes-base.supabaseTool","position":[-100,840],"parameters":{"tableId":"agent_tasks"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"85e3c8e1-6a75-40ce-a344-4a8fd3a1ae16","name":"GET_ROW_AGENT_TASKS","type":"n8n-nodes-base.supabaseTool","position":[80,840],"parameters":{"tableId":"agent_tasks","operation":"get"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"7dacc138-a3aa-4483-a79c-5f2eee915c72","name":"DELETE_ROW_AGENT_TASKS","type":"n8n-nodes-base.supabaseTool","position":[260,840],"parameters":{"tableId":"agent_tasks","operation":"delete"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"cb942ab1-e7f2-4fd7-bc1e-fa9e559480a1","name":"UPDATE_ROW_AGENT_TASKS","type":"n8n-nodes-base.supabaseTool","position":[440,840],"parameters":{"tableId":"agent_tasks","operation":"update"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"ed9cc573-764c-4cda-82f4-796851b16fba","name":"GET_MANY_ROW_AGENT_TASKS","type":"n8n-nodes-base.supabaseTool","position":[620,840],"parameters":{"limit":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}","tableId":"agent_tasks","operation":"getAll"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"d3412d90-6025-4db5-a845-8b1ea6070ea3","name":"CREATE_ROW_AGENT_STATUS","type":"n8n-nodes-base.supabaseTool","position":[-100,1440],"parameters":{"tableId":"agent_status"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"843a2b92-8fb4-4453-9517-b37e07148f52","name":"GET_ROW_AGENT_STATUS","type":"n8n-nodes-base.supabaseTool","position":[80,1440],"parameters":{"tableId":"agent_status","operation":"get"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"9a075b33-23fa-487c-b139-41e7e4794831","name":"DELETE_ROW_AGENT_STATUS","type":"n8n-nodes-base.supabaseTool","position":[260,1440],"parameters":{"tableId":"agent_status","operation":"delete"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"a066b99d-15f4-4c3e-bab6-4423b749bb74","name":"UPDATE_ROW_AGENT_STATUS","type":"n8n-nodes-base.supabaseTool","position":[440,1440],"parameters":{"tableId":"agent_status","operation":"update"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"be9930a8-4e01-4823-a0be-4adfd06dd29c","name":"GET_MANY_ROW_AGENT_STATUS","type":"n8n-nodes-base.supabaseTool","position":[620,1440],"parameters":{"limit":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}","tableId":"agent_status","operation":"getAll"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"01fbbe34-81e7-4017-a10e-ef7137024d6a","name":"CREATE_ROW_AGENT_KNOWLEDGE","type":"n8n-nodes-base.supabaseTool","position":[-100,2020],"parameters":{"tableId":"agent_knowledge"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"5ba9e5eb-76bb-499c-b93b-5cca7286259b","name":"GET_ROW_AGENT_KNOWLEDGE","type":"n8n-nodes-base.supabaseTool","position":[80,2020],"parameters":{"tableId":"agent_knowledge","operation":"get"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"a25cef14-0cf0-4ded-81f0-cde300f74432","name":"UPDATE_ROW_INSCRICOES_AGENT_KNOWLEDGE","type":"n8n-nodes-base.supabaseTool","position":[440,2020],"parameters":{"tableId":"agent_knowledge","operation":"update"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1},{"id":"1c1fae2e-97f9-449f-913a-8ac730c1f145","name":"GET_MANY_ROW_AGENT_KNOWLEDGE","type":"n8n-nodes-base.supabaseTool","position":[620,2020],"parameters":{"limit":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}","tableId":"agent_knowledge","operation":"getAll"},"credentials":{"supabaseApi":{"id":"yfa6fXRKgmrEx175","name":"Supabase account"}},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"d32edd9b-7508-45a9-adcc-049543647145","connections":{"RAG":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"Embeddings OpenAI":{"ai_embedding":[[{"node":"RAG","type":"ai_embedding","index":0}]]},"GET_ROW_AGENT_TASKS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_ROW_AGENT_STATUS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_ROW_AGENT_MESSAGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"CREATE_ROW_AGENT_TASKS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"DELETE_ROW_AGENT_TASKS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"UPDATE_ROW_AGENT_TASKS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"CREATE_ROW_AGENT_STATUS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"DELETE_ROW_AGENT_STATUS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_ROW_AGENT_KNOWLEDGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"UPDATE_ROW_AGENT_STATUS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"CREATE_ROW_AGENT_MESSAGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"DELETE_ROW_AGENT_MESSAGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_MANY_ROW_AGENT_TASKS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"UPDATE_ROW_AGENT_MESSAGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_MANY_ROW_AGENT_STATUS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"CREATE_ROW_AGENT_KNOWLEDGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_MANY_ROW_AGENT_MESSAGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"DELETE_ROW_INSCRICOES_CURSOS":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"GET_MANY_ROW_AGENT_KNOWLEDGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]},"UPDATE_ROW_INSCRICOES_AGENT_KNOWLEDGE":{"ai_tool":[[{"node":"MCP_SUPABASE","type":"ai_tool","index":0}]]}}}


name: AI-Powered Gmail Email Organization with Auto-Archiving and Priority Labels
author_name: Junichiro Tobe
author_username: junichiro
categories: []
created_at: 2025-04-24T06:03:12.578Z
updated_at: 2025-04-24T06:03:12.578Z
url: https://n8n.io/workflows/3686
scraped_at: 2025-07-06 21:16:30
description:
  Who is this for?  
  This workflow is perfect for busy professionals, students, or anyone who struggles to keep their Gmail inbox organized and clutter-free.

  What problem is this workflow solving?  
  It helps you avoid email overload by automating the process of organizing your Gmail inbox. Unnecessary emails are archived, while important emails are categorized into "MustRead" or "NotNeed" for better prioritization.

  What this workflow does  
  Connects to your Gmail inbox.  
  Automatically archives emails that are unnecessary or irrelevant.  
  Sorts remaining emails into two categories:  
    MustRead: Emails that require immediate attention.  
    NotNeed: Less critical emails for review later.  

  Setup  
  Connect your Gmail account to the workflow.  
  Define the criteria for "MustRead" and "NotNeed" emails by updating the filter rules in the nodes.  
  Activate the workflow to start organizing your inbox.

  How to customize this workflow to your needs  
  Adjust the filters for archiving emails based on your specific preferences.  
  Modify the sorting rules for "MustRead" and "NotNeed" categories to match your workflow.  
  Add additional actions, such as sending notifications for "MustRead" emails.

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

workflow_json:
  {"meta":{"instanceId":"6af2f94153ea0551e6264b16187490bd4c4739c7f5f3d7adab90c5cf186e22a1","templateCredsSetupCompleted":true},"nodes":[{"id":"43e68fe1-7f48-4bc9-b19a-66d39bee5bbd","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-520,20],"parameters":{},"typeVersion":1},{"id":"32aa401a-60c3-4436-94d5-5ba09d3be6ae","name":"OpenRouter Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[80,0],"parameters":{"model":"openai/gpt-4.1-nano","options":{}},"credentials":{"openRouterApi":{"id":"eQmkAlMDYm8oEtBL","name":"OpenRouter account"}},"typeVersion":1},{"id":"f6d325b4-ff87-4bba-9f27-b68590c8a533","name":"Telegram Trigger","type":"n8n-nodes-base.telegramTrigger","position":[-520,-220],"webhookId":"e61d3286-920e-406c-b787-d330cf897ef4","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"ZOl2ZojetuN1uFiX","name":"My Mail Agent Bot via Telegram"}},"typeVersion":1.1},{"id":"8e10c622-9bf8-414b-8364-185c5c4808a0","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-600,-480],"parameters":{"width":1660,"height":680,"content":"## Mail Agent\nFor emails in the inbox, archive those that are completely unnecessary, and label the rest based on their relevance.\n\n"},"typeVersion":1},{"id":"2e664cd4-37af-4b8f-84a5-ff07911b8aaa","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-560,-380],"parameters":{"color":5,"width":180,"height":360,"content":"### Trigger\nRun by communicating with Telegram"},"typeVersion":1},{"id":"966af8d0-bfca-40fa-b97c-ec1bb7de82d2","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-360,-380],"parameters":{"color":4,"width":180,"height":360,"content":"### Get Mail via Gmail\nRetrieve all emails in the Gmail inbox.\n(Inbox = Label: INBOX)"},"typeVersion":1},{"id":"07dabeda-a075-4e45-9ecf-9a0e6d0df0b2","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-160,-380],"parameters":{"color":4,"width":180,"height":360,"content":"### Filter\nFilter out emails that have already been processed to avoid unnecessary work for the AI.\n\n"},"typeVersion":1},{"id":"b9a96646-283e-4328-8c79-57befa97bb69","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[40,-380],"parameters":{"color":3,"width":980,"height":540,"content":"### AI Agent\nCheck each email one by one, categorize them as necessary or unnecessary according to the provided prompt, and instruct Gmail to apply the appropriate labels."},"typeVersion":1},{"id":"32c73c57-61b5-430b-a011-f0b44fa2b226","name":"mail_label_setter","type":"n8n-nodes-base.gmailTool","position":[360,0],"webhookId":"37bb94d2-6aeb-4038-afc7-e25a330e7860","parameters":{"labelIds":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Label_Names_or_IDs', ``, 'string') }}","messageId":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message_ID', ``, 'string') }}","operation":"addLabels"},"credentials":{"gmailOAuth2":{"id":"5GhcPqZ48DrfujWd","name":"Gmail account"}},"typeVersion":2.1},{"id":"7cf38850-939c-4c8e-af62-1f730d5b7e34","name":"mail_archiver","type":"n8n-nodes-base.gmailTool","position":[220,0],"webhookId":"81956225-38dd-4acf-b97a-8e68f332f56a","parameters":{"labelIds":["INBOX"],"messageId":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Message_ID', ``, 'string') }}","operation":"removeLabels"},"credentials":{"gmailOAuth2":{"id":"5GhcPqZ48DrfujWd","name":"Gmail account"}},"typeVersion":2.1},{"id":"5fab497e-a632-4565-8048-7ae9b209728d","name":"Aggregate","type":"n8n-nodes-base.aggregate","position":[380,-220],"parameters":{"options":{},"aggregate":"aggregateAllItemData"},"typeVersion":1},{"id":"f7144884-6ba6-4e97-be35-f5f8b27d56ad","name":"Telegram","type":"n8n-nodes-base.telegram","position":[820,-220],"webhookId":"6324ebbf-b2c3-42c3-b4ee-849184380b4f","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Telegram Trigger').item.json.message.chat.id }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"ZOl2ZojetuN1uFiX","name":"My Mail Agent Bot via Telegram"}},"typeVersion":1.2},{"id":"9236fbc1-ffad-4bf0-b3a1-5d389e5b422c","name":"OpenRouter Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[520,0],"parameters":{"model":"openai/gpt-4.1-nano","options":{}},"credentials":{"openRouterApi":{"id":"eQmkAlMDYm8oEtBL","name":"OpenRouter account"}},"typeVersion":1},{"id":"e0ec10ca-ad72-4784-891e-5bd5bcff7082","name":"Reporter","type":"@n8n/n8n-nodes-langchain.agent","position":[520,-220],"parameters":{"text":"=Summarize data\n```\n{{ $json.data.map(item => item.output + '\\n\\n') }}\n```\n","options":{"systemMessage":"=# persona\n* You are a helpful assistant.\n"},"promptType":"define"},"typeVersion":1.8},{"id":"9b4f8e14-7b9c-45b3-97cb-32f2fe756440","name":"Get mails in INBOX","type":"n8n-nodes-base.gmail","position":[-320,-220],"webhookId":"f4c95906-916d-4c94-8e35-cb37c9472043","parameters":{"filters":{"labelIds":["INBOX"]},"operation":"getAll","returnAll":true},"credentials":{"gmailOAuth2":{"id":"5GhcPqZ48DrfujWd","name":"Gmail account"}},"typeVersion":2.1},{"id":"13088de9-6f96-463e-bcb6-92f97d7144d9","name":"Filter processed","type":"n8n-nodes-base.filter","position":[-120,-220],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"1091eba0-3d75-47b6-92c5-404f93e263ae","operator":{"type":"array","operation":"notContains","rightType":"any"},"leftValue":"={{ $json.labels.map(item => item.name)}}","rightValue":"NotNeed"},{"id":"31160689-98ce-43ac-8c7b-116cd7da5ebc","operator":{"type":"array","operation":"notContains","rightType":"any"},"leftValue":"={{ $json.labels.map(item => item.name)}}","rightValue":"MustRead"}]}},"typeVersion":2.2},{"id":"317ea413-e8fd-4148-8115-8b4d2b9a7fe4","name":"Categoriser","type":"@n8n/n8n-nodes-langchain.agent","position":[80,-220],"parameters":{"text":"=<task>\nProcess mail\n</task>\n<mail>\n<id>{{ $json.id }}</id>\n<from>{{ $json.From }}</from>\n<subject>{{ $json.Subject }}</subject>\n<body>{{ $json.snippet }}</body>\n</mail>","options":{"systemMessage":"=<persona>\nYou are an email processing assistant.\n</persona>\n<task>\nLook at the content of the email and decide whether to apply a label or archive it, processing it only once. First, archive those that are absolutely unnecessary using the mail_archiver tool. This judgment is the top priority. After that, if it does not fall into that category, determine whether it should be read based on the following criteria and use the mail_label_setter tool to apply the label.\n<case>Absolutely unnecessary: Archive using the mail_archiver tool</case>\n<case>Needs to be read: Apply \"Label_[label_id]\" using the mail_label_setter tool</case>\n<case>Other: Apply \"Label_[label_id]\" using the mail_label_setter tool</case>\nReport the processing results carefully.\n</task>\n<rules>\n<Archive>\nEmails that are absolutely unnecessary and will be archived\n<item>[list up your rule1]</item>\n<item>[list up your rule2]</item>\n</Archive><MustRead>\nEmails that need to be read\n<item>[list up your rule1]</item>\n<item>[list up your rule2]</item>\n</MustRead>\n<Other>\nEmails that are not necessary to read but will not be archived\n<item>[list up your rule1]</item>\n<item>[list up your rule2]</item>\n</Other>\n</rules>"},"promptType":"define"},"typeVersion":1.7}],"pinData":{},"connections":{"Reporter":{"main":[[{"node":"Telegram","type":"main","index":0}]]},"Aggregate":{"main":[[{"node":"Reporter","type":"main","index":0}]]},"Categoriser":{"main":[[{"node":"Aggregate","type":"main","index":0}]]},"mail_archiver":{"ai_tool":[[{"node":"Categoriser","type":"ai_tool","index":0}]]},"Filter processed":{"main":[[{"node":"Categoriser","type":"main","index":0}]]},"Telegram Trigger":{"main":[[{"node":"Get mails in INBOX","type":"main","index":0}]]},"mail_label_setter":{"ai_tool":[[{"node":"Categoriser","type":"ai_tool","index":0}]]},"Get mails in INBOX":{"main":[[{"node":"Filter processed","type":"main","index":0}]]},"OpenRouter Chat Model":{"ai_languageModel":[[{"node":"Categoriser","type":"ai_languageModel","index":0}]]},"OpenRouter Chat Model1":{"ai_languageModel":[[{"node":"Reporter","type":"ai_languageModel","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Get mails in INBOX","type":"main","index":0}]]}}}


name: Generate AI News LinkedIn Posts with GPT-4o-mini, NewsAPI, and Qdrant
author_name: Lucien
author_username: lucien
categories: []
created_at: 2025-04-24T13:49:23.022Z
updated_at: 2025-04-24T13:49:23.022Z
url: https://n8n.io/workflows/3691
scraped_at: 2025-07-06 21:16:30
description:
  Overview
  Automated LinkedIn content generator that:

  Fetches trending AI news using NewsAPI
  Enhances content with Qdrant vector store context
  Generates professional LinkedIn posts using GPT-4o-mini
  Tracks email interactions in Google Sheets
  🛠️ Prerequisites
  API Keys : NewsAPI, OpenAI (GPT-4o-mini), Qdrant
  Accounts : Gmail Oauth, Google Sheets, LinkedIn developer API
  Environment Variables :
  OPENAI_API_KEY
  NEWSAPI_KEY
  QDRANT_URL/QDRANT_API_KEY
  📁 Google Sheets Setup
  Create a spreadsheet with these columns:

  ISO date
  Email address
  Unique ID
  "Approve" or "Reject"

  ⚙️ Setup Instructions
  Pre-populate Qdrant :
  Create collection "posts" with LinkedIn post examples
  Add 10+ example posts for style reference
  Node Configuration :
  Update Gmail credentials (OAuth2)
  Set fromEmail/toEmail in email nodes
  Configure Google Sheets document IDs
  Test Workflow :
  Run Schedule Trigger manually first
  Verify email notifications work
  Check Qdrant vector store connectivity

  🎨 Customization Options
  Tone Adjustment : Modify system message in "AI Agent"
  Post Style : Update prompt in "Generate LinkedIn Post"
  Filter Criteria : Edit NewsAPI URL parameters
  Scheduling : Change interval in Schedule Trigger

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

workflow_json:
  {"id":"O3BJdDDZbAtT74VZ","meta":{"instanceId":"c38f1c83d09df87fdce6caf4eb6204b32cc91142d36e3d9bc700e4c57cb53d17","templateCredsSetupCompleted":true},"name":"newsapi without credentials","tags":[],"nodes":[{"id":"f12fb93e-7d7d-4f99-9e30-112e02237cd3","name":"Notes","type":"n8n-nodes-base.stickyNote","position":[-360,-1340],"parameters":{"width":580,"height":100,"content":"# AI Article Generator with Qdrant\n1. Edit 'Set Input Data' node with your topic, company, and tone.\n2. Retrieves company data from Qdrant using RAG.\n3. Fetches recent news using NewsAPI.\n4. Generates a 500-word article using OpenAI.\n5. Sends the article via Gmail.\n\n**Setup**:\n- Add credentials: Qdrant, Gmail SMTP.\n- Set env vars: OPENAI_API_KEY, NEWSAPI_KEY.\n- Pre-populate Qdrant collection 'company_data' with documents.\n- Update `fromEmail` and `toEmail` in Send Article via Gmail."},"typeVersion":1},{"id":"d17ff0dc-914f-4c9b-b984-5179fb688b81","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[-560,-620],"parameters":{"rule":{"interval":[{}]}},"typeVersion":1.2},{"id":"1ce01576-ef29-41ed-a97e-cdc296917239","name":"Split Articles","type":"n8n-nodes-base.code","position":[120,-660],"parameters":{"jsCode":"// Access the articles array from the current node's input\nconst articles = $input.first().json.articles || [];\n\n// Log the number of articles for debugging\nconsole.log(`Found ${articles.length} articles`);\n\n// Aggregate the articles into an HTML-formatted string\nconst emailBody = `\n  \n  <hr style=\"border: 1px solid #ddd;\">\n  ${articles.map((article, index) => `\n    <div style=\"margin-bottom: 20px;\">\n      <h2 style=\"color: #1a73e8;\">Article ${index + 1}: ${article.title}</h2>\n      <p><strong>Description:</strong> ${article.description}</p>\n    </div>\n    <hr style=\"border: 1px solid #ddd;\">\n  `).join('')}\n`;\n\n// Output a single item with the HTML email body\nconst output = [{\n  json: {\n    email_subject: \"Latest News Articles\",\n    email_body: emailBody\n  }\n}];\n\n// Log the final output for debugging\nconsole.log('Output item:', JSON.stringify(output, null, 2));\n\n// Return the single item\nreturn output;"},"typeVersion":2},{"id":"8bdb2b9a-a57b-4d64-ad17-aaf2bbcd1119","name":"News API","type":"n8n-nodes-base.httpRequest","position":[-60,-660],"parameters":{"url":"=https://newsapi.org/v2/everything?q={{ encodeURIComponent($json.keyword) }}&sortBy=publishedAt&language=en&pageSize=5&from={{ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] }}","options":{},"authentication":"genericCredentialType","genericAuthType":"httpQueryAuth"},"credentials":{"httpQueryAuth":{"id":"opOG4qr6WHzexWe9","name":"newsapiAuth"}},"typeVersion":4.2},{"id":"4dface60-cd99-48d6-9b6a-49b8dcc5c552","name":"Gmail Trigger","type":"n8n-nodes-base.gmailTrigger","position":[-900,-100],"parameters":{"filters":{"sender":"lucien.razafindraibe@islandaiforge.us","readStatus":"unread"},"pollTimes":{"item":[{"mode":"everyMinute"}]}},"credentials":{"gmailOAuth2":{"id":"E5NlCEZdHk1Kr5us","name":"workinggmail"}},"typeVersion":1.2},{"id":"4014f595-46fd-4fa2-8771-61027cdcfe16","name":"Gmail1","type":"n8n-nodes-base.gmail","position":[-380,-240],"webhookId":"519ccf94-8cfe-4603-b33a-a7f78f48c2e5","parameters":{"simple":false,"options":{},"messageId":"={{ $json.id }}","operation":"get"},"credentials":{"gmailOAuth2":{"id":"3OQ62RdXe5PYLtgq","name":"Gmail account Bob"}},"typeVersion":2.1},{"id":"fdaf2818-d4f0-4108-b598-96ea88e89a09","name":"Edit Fields1","type":"n8n-nodes-base.set","position":[-740,-280],"parameters":{"options":{},"assignments":{"assignments":[{"id":"d0552f56-1c1c-4c33-b633-d5cf3b73007a","name":"content","type":"string","value":"={{ $json.text }}"}]}},"typeVersion":3.4},{"id":"9182a1ad-49d5-4fc2-b55d-8633dd0e9834","name":"confirmation","type":"n8n-nodes-base.gmail","position":[-460,320],"webhookId":"56000c65-d828-40c5-9e70-500be978f417","parameters":{"messageId":"={{ $json.id }}","operation":"get"},"credentials":{"gmailOAuth2":{"id":"E5NlCEZdHk1Kr5us","name":"workinggmail"}},"typeVersion":2.1},{"id":"251e95a1-3bfe-4ef1-b105-0a3d9b36c1cb","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[140,120],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"WY6OFYeKPcT2Pvxt","name":"OpenAi account"}},"typeVersion":1.2},{"id":"db8c4c3f-f2bf-4a2a-a5ed-4d5243b59185","name":"Merge","type":"n8n-nodes-base.merge","position":[60,-60],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3},{"id":"e7b449b3-53d6-449b-9772-c0925b553e91","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[800,-20],"parameters":{"jsonSchemaExample":"{\n  \"commentary\": \"🚀 Great news for developers! PyDantic-AI-Examples 0.1.2 is out, offering practical examples to implement PydanticAI and build robust apps with ease. Check it out! 💻 #AI #TechInnovation #Developers\"\n}"},"typeVersion":1.2},{"id":"fbe9396a-66f7-411a-a19d-44425dccf8c0","name":"If","type":"n8n-nodes-base.if","position":[80,-60],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"4257fd89-716a-43e5-91b8-0fe63a23080f","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"= {{ $json.decision }}","rightValue":""},{"id":"55c996ae-9990-4642-901f-21e5fbee263e","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.content }}","rightValue":""}]}},"typeVersion":2.2},{"id":"0092d297-df30-4ca3-96ed-f5dded80926a","name":"Unread","type":"n8n-nodes-base.gmail","position":[-440,20],"webhookId":"8111ed2a-6a10-4b2f-b785-7cb25701cf05","parameters":{"messageId":"={{ $('Gmail Trigger').item.json.id }}","operation":"markAsRead"},"credentials":{"gmailOAuth2":{"id":"E5NlCEZdHk1Kr5us","name":"workinggmail"}},"typeVersion":2.1},{"id":"3b59e60e-45df-4de5-82a0-592e3d609c75","name":"Set Input Data (Topic/Company/Tone)","type":"n8n-nodes-base.set","position":[-320,-620],"parameters":{"options":{},"assignments":{"assignments":[{"id":"649f3dcc-f800-49f2-9a47-806d11ba819b","name":"=keyword","type":"string","value":"ai"}]}},"typeVersion":3.4},{"id":"ae60f9ec-fdf8-40f0-b73b-c9c3c2fe55fd","name":"Send Email with News Articles","type":"n8n-nodes-base.gmail","position":[360,-660],"webhookId":"82457c0a-4a38-43ba-b580-99d2be577842","parameters":{"sendTo":"lucien.razafindraibe@islandaiforge.us","message":"=Latest articles {{ $json.email_subject }}{{ $json.email_body }}","options":{},"subject":"Latest Ai news"},"credentials":{"gmailOAuth2":{"id":"E5NlCEZdHk1Kr5us","name":"workinggmail"}},"typeVersion":2.1},{"id":"55940722-dfbd-4807-99f7-d6d32d05d20a","name":"Log Email Activity","type":"n8n-nodes-base.googleSheets","position":[580,-660],"parameters":{"columns":{"value":{"Recipient":"luaina.mada@gmail.com","Timestamp":"={{ new Date().toISOString() }}","Message-ID":"={{ $json.id }}"},"schema":[{"id":"Timestamp","type":"string","display":true,"required":false,"displayName":"Timestamp","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Message-ID","type":"string","display":true,"required":false,"displayName":"Message-ID","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Recipient","type":"string","display":true,"required":false,"displayName":"Recipient","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ/edit?usp=drivesdk","cachedResultName":"email-n8n"}},"credentials":{"googleSheetsOAuth2Api":{"id":"H9mpH4Tgcw0ZyQZQ","name":"veo3-credentials"}},"typeVersion":4.5},{"id":"ab44e274-8c67-493f-8968-2f6d841e79fc","name":"Capture Email Decision","type":"n8n-nodes-base.set","position":[-180,140],"parameters":{"options":{},"assignments":{"assignments":[{"id":"e8acea05-1b3f-405b-8adb-2604f17d0e4f","name":"decision","type":"string","value":"={{ $json.snippet }}"}]}},"typeVersion":3.4},{"id":"865cf8c6-565c-4a9b-b976-417ae7165d84","name":"Retrieve the message","type":"n8n-nodes-base.googleSheets","position":[-680,-100],"parameters":{"options":{},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1Ypiv9KQrW-7tc4iJ8b0YmcLUKotXDrEAobZDXMcUGUQ/edit?usp=drivesdk","cachedResultName":"email-n8n"}},"credentials":{"googleSheetsOAuth2Api":{"id":"H9mpH4Tgcw0ZyQZQ","name":"veo3-credentials"}},"typeVersion":4.5},{"id":"3120723e-7bf8-4896-8fb3-93d526765461","name":"Generate Linkedin Posts","type":"@n8n/n8n-nodes-langchain.agent","position":[800,-240],"parameters":{"text":"=You are a social media expert specializing in tech and AI content, tasked with generating a professional LinkedIn post. Use the \"linkedin_posts\" tool to retrieve example LinkedIn posts, which will provide the style, tone, and structure you should follow.\n\nSteps:\n1. Use the \"linkedin_posts\" tool to retrieve example LinkedIn posts.\n2. Analyze the style, tone, and structure of the retrieved posts (e.g., use of emojis, hashtags, bullet points, or engaging questions).\n3. Based on the news provided in {{ $json.content }}, generate a professional LinkedIn post to share key insights or updates relevant to tech and AI.\n4. Ensure the post aligns with the user’s decision from the email confirmation: {{ $json.decision }}.\n5. Make the post engaging, professional, and suitable for a LinkedIn audience. Include hashtags, emojis, or other elements if they are present in the example posts.\n\nGenerate the LinkedIn post now.","options":{"systemMessage":"You are a skilled social media content creator specializing in tech and AI news. Your role is to craft engaging and professional LinkedIn posts based on provided news content and user decisions. Follow the user’s instructions to generate posts in the specified JSON . Return the post as a JSON object in the format: {\"Text\": \"your generated post content\"}"},"promptType":"define","hasOutputParser":true},"executeOnce":true,"typeVersion":1.8},{"id":"dfb952de-546d-4541-9bf7-d62ca6f5544e","name":"Generate Vector Embeddings","type":"@n8n/n8n-nodes-langchain.embeddingsOpenAi","position":[1100,140],"parameters":{"options":{}},"credentials":{"openAiApi":{"id":"WY6OFYeKPcT2Pvxt","name":"OpenAi account"}},"typeVersion":1.2},{"id":"efd07f78-e8a3-4d82-a355-f200be1f4b0b","name":"Publish LinkedIn Post","type":"n8n-nodes-base.httpRequest","position":[1560,-100],"parameters":{"url":"https://api.linkedin.com/rest/posts","method":"POST","options":{},"jsonBody":"={\n  \"author\": \"{{ $json.author }}\",\n  \"commentary\":\"{{ $json.commentary }}\",\n  \"visibility\": \"PUBLIC\",\n  \"lifecycleState\": \"PUBLISHED\",\n  \"distribution\": {\n    \"feedDistribution\": \"MAIN_FEED\",\n    \"targetEntities\": [],\n    \"thirdPartyDistributionChannels\": []\n  }\n}","sendBody":true,"contentType":"=json","sendHeaders":true,"specifyBody":"json","authentication":"predefinedCredentialType","bodyParameters":{"parameters":[{}]},"headerParameters":{"parameters":[{"name":"LinkedIn-Version","value":"202503"},{"name":"Content-Type","value":"application/json"},{"name":"X-Restli-Protocol-Version","value":"2.0.0"}]},"nodeCredentialType":"linkedInOAuth2Api"},"credentials":{"linkedInOAuth2Api":{"id":"ozCD99hAUVEDVd0o","name":"LinkedIn account 4"}},"typeVersion":4.2},{"id":"ec510882-812b-4b4e-8a29-3e8b799f3424","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-940,-780],"parameters":{"color":5,"width":1940,"height":320,"content":"# News digest with article summaries\n"},"typeVersion":1},{"id":"9ee79293-12d6-4542-9a31-444d8ed8a7da","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-920,-380],"parameters":{"width":1640,"height":900,"content":"# Get decision and the articles from email\n"},"typeVersion":1},{"id":"cba603cb-7d72-46d0-82cb-474c1a29a3d8","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[700,-380],"parameters":{"color":3,"width":1000,"height":820,"content":"# Generate the Linkedin Post"},"typeVersion":1},{"id":"8e22b721-99f5-4dda-96ad-d9e9a258ed12","name":"RetrievePostExamples","type":"@n8n/n8n-nodes-langchain.vectorStoreQdrant","position":[1100,-20],"parameters":{"mode":"retrieve-as-tool","topK":10,"options":{},"toolName":"linkedin_posts","toolDescription":"Examples of LinkedIn posts. Use these to generate new posts in a similar style and tone.\n\n","qdrantCollection":{"__rl":true,"mode":"list","value":"posts","cachedResultName":"posts"}},"credentials":{"qdrantApi":{"id":"3d3IhGNVwofxMLLQ","name":"QdrantApi account"}},"typeVersion":1},{"id":"3ade436d-a77b-4d01-87f8-1186a93cc1a5","name":"ExtractLatestEmail2","type":"n8n-nodes-base.code","position":[-120,-280],"parameters":{"jsCode":"return [$input.all().slice(-1)[0]];"},"typeVersion":2},{"id":"19c15ab2-5be6-433c-9cbb-ddbcbef6720d","name":"FormatLinkedInPayload","type":"n8n-nodes-base.code","position":[1200,-200],"parameters":{"jsCode":"// Helper function to escape special characters for JSON\nfunction escapeJsonString(str) {\n  if (typeof str !== 'string') {\n    return String(str || 'Default commentary');\n  }\n  return str\n    .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n    .replace(/\"/g, '\\\\\"')   // Escape double quotes\n    .replace(/\\n/g, '\\\\n')  // Escape newlines\n    .replace(/\\t/g, '\\\\t'); // Escape tabs\n}\n\n// Get all input items\nconst items = $input.all();\n\n// Check if there are any items\nif (!items.length) {\n  console.log(\"No input items found\");\n  return [{ json: { error: \"No input items\" } }];\n}\n\n// Take the first item's json.output.commentary (adjust if you need a different item)\nconst commentary = items[0].json.output?.commentary;\n\nconst linkedInProfileId = 'urn:li:person:default-id';\n\n\n\n// Construct the JSON payload\nconst payload = {\n  author: linkedInProfileId,\n\n\n  commentary: escapeJsonString(commentary),\n  visibility: \"PUBLIC\",\n  lifecycleState: \"PUBLISHED\",\n  distribution: {\n    feedDistribution: \"MAIN_FEED\",\n    targetEntities: [],\n    thirdPartyDistributionChannels: []\n  }\n};\n\n// Log for debugging\nconsole.log(\"Dynamic JSON:\", JSON.stringify(payload, null, 2));\nconsole.log(\"Raw Commentary:\", commentary);\nconsole.log(\"Escaped Commentary:\", payload.commentary);\nconsole.log(\"Commentary Type:\", typeof commentary);\n\nreturn [{ json: payload }];"},"typeVersion":2},{"id":"7e3aa544-9db6-462d-a6a7-284c206064c5","name":"Set Linkedin Id","type":"n8n-nodes-base.set","position":[1320,-380],"parameters":{"options":{},"assignments":{"assignments":[{"id":"81da58bf-b0bd-4c73-8895-243a8953fbce","name":"author","type":"string","value":"urn:li:person"}]}},"typeVersion":3.4},{"id":"14cd9288-9687-4b82-816b-cd8ab3127e17","name":"Merge1","type":"n8n-nodes-base.merge","position":[1460,-220],"parameters":{"mode":"combine","options":{},"combineBy":"combineAll"},"typeVersion":3}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"58392ebf-f703-450d-aabd-6a630b0b3578","connections":{"If":{"main":[[{"node":"Generate Linkedin Posts","type":"main","index":0}]]},"Merge":{"main":[[{"node":"If","type":"main","index":0}]]},"Gmail1":{"main":[[{"node":"Edit Fields1","type":"main","index":0}]]},"Merge1":{"main":[[{"node":"Publish LinkedIn Post","type":"main","index":0}]]},"Unread":{"main":[[{"node":"Gmail1","type":"main","index":0}]]},"News API":{"main":[[{"node":"Split Articles","type":"main","index":0}]]},"Edit Fields1":{"main":[[{"node":"ExtractLatestEmail2","type":"main","index":0}]]},"confirmation":{"main":[[{"node":"Capture Email Decision","type":"main","index":0}]]},"Gmail Trigger":{"main":[[{"node":"Retrieve the message","type":"main","index":0},{"node":"confirmation","type":"main","index":0}]]},"Split Articles":{"main":[[{"node":"Send Email with News Articles","type":"main","index":0}]]},"Set Linkedin Id":{"main":[[{"node":"Merge1","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"Set Input Data (Topic/Company/Tone)","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Generate Linkedin Posts","type":"ai_languageModel","index":0}]]},"ExtractLatestEmail2":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Retrieve the message":{"main":[[{"node":"Unread","type":"main","index":0}]]},"RetrievePostExamples":{"ai_tool":[[{"node":"Generate Linkedin Posts","type":"ai_tool","index":0}]]},"FormatLinkedInPayload":{"main":[[{"node":"Merge1","type":"main","index":1}]]},"Publish LinkedIn Post":{"main":[[]]},"Capture Email Decision":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Generate Linkedin Posts":{"main":[[{"node":"FormatLinkedInPayload","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"Generate Linkedin Posts","type":"ai_outputParser","index":0}]]},"Generate Vector Embeddings":{"ai_embedding":[[{"node":"RetrievePostExamples","type":"ai_embedding","index":0}]]},"Send Email with News Articles":{"main":[[{"node":"Log Email Activity","type":"main","index":0}]]},"Set Input Data (Topic/Company/Tone)":{"main":[[{"node":"News API","type":"main","index":0}]]}}}


name: Multi-Agent AI Clinic Management with WhatsApp, Telegram, and Google Calendar
author_name: Luciano Gutierrez
author_username: koresoluciones
categories: []
created_at: 2025-04-24T15:30:54.772Z
updated_at: 2025-04-24T15:30:54.772Z
url: https://n8n.io/workflows/3694
scraped_at: 2025-07-06 21:16:30
description:
  Healthcare Clinic Assistant with WhatsApp and Telegram Integration
  Version: 1.1.0  
  n8n Version: 1.88.0+  
  License: MIT  

  📋 Description
  A comprehensive and modular automation workflow designed for healthcare clinics.  
  It manages patient communication, appointment scheduling, confirmations, rescheduling, internal tasks, and media processing by integrating WhatsApp, Telegram, Google Calendar, and Google Tasks, combined with AI-powered agents for maximum efficiency.

  This system guarantees proactive communication with patients, streamlined internal clinic management, and consistent data synchronization across platforms.

  🌟 Key Features
  🤖 AI-Powered Specialized Agents:  
    Distinct agents handle WhatsApp patient support, appointment confirmations, and internal rescheduling tasks.

  📱 Omnichannel Communication:  
    Handles patient interactions via WhatsApp and staff commands via Telegram.

  📅 Google Calendar Appointment Management:  
    Full synchronization for creating, updating, canceling, and confirming appointments.

  📋 Task Management with Google Tasks:  
    Manages shopping lists and administrative tasks efficiently through staff Telegram requests.

  🔔 Automated Appointment Reminders:  
    Daily-triggered system proactively sends WhatsApp confirmations to patients for next-day appointments.

  🖼️ Intelligent Media Processing:  
    Transcribes audios, extracts text from images, and processes documents using OpenAI and OpenRouter AI models.

  🛡️ Escalation to Human Support:  
    Automatically detects sensitive or urgent cases and escalates them to a human agent when needed.

  🏥 Use Cases
  Patient Communication:**  
    Respond to inquiries, schedule, reschedule, and confirm appointments seamlessly via WhatsApp.

  Internal Clinic Operations:**  
    Allow staff to modify appointments or add shopping list reminders directly from Telegram.

  Appointment Confirmation System:**  
    Automatically contacts patients one day prior to appointments for confirmation or rescheduling.

  Task and Reminder Management:**  
    Keeps clinic operations organized through automatic task management with Google Tasks.

  🛠️ Technical Implementation

  WhatsApp Patient Interaction Flow
  Webhook Reception:** Incoming WhatsApp messages captured via Evolution API webhook.
  Message Classification:** Intelligent routing of messages based on content type (text, image, audio, document).
  Media Content Processing:**  
    Audios: Download, convert, and transcribe via OpenAI Whisper.  
    Images: Analyze and extract text/descriptions with OpenAI Vision model.
  Patient Request Handling:** Specialized WhatsApp assistant responds appropriately using AI prompts.
  Outbound Message Formatting:** Ensures messages comply with WhatsApp format standards.
  Message Delivery:** Sends responses back via Evolution API.

  Telegram Staff Management Flow
  Telegram Webhook Reception:** Captures messages from authorized staff accounts.
  Internal Assistant Processing:**  
    Appointment Rescheduling: Identifies and updates appointments through MCP Google Calendar.  
    Task Creation: Adds new entries to the clinic's shopping list using Google Tasks.
  Notifications and Confirmations:** Sends confirmations back to staff through Telegram.

  Appointment Reminder System
  Daily Trigger Activation:** Fires every weekday at 08:00 AM.
  Calendar Scraping:** Lists next day's appointments from Google Calendar.
  Patient Contact:** Sends WhatsApp confirmation messages for each appointment.
  Response Management:** Redirects confirmation or rescheduling replies to appropriate agents.

  ⚙️ Setup Instructions

  Import the Workflow  
     n8n → Workflows → Import from File → Upload this JSON file.

  Configure Credentials  
     Evolution API (WhatsApp Communication)  
     Telegram Bot API (Staff Communication)  
     Google Calendar OAuth2 (Appointment Management)  
     Google Tasks OAuth2 (Task Management)  
     OpenAI and OpenRouter APIs (AI Agents)  
     PostgreSQL Database (Chat Memory)

  Set Sensitive Variables
     Replace placeholder values:
       {sua instância aqui} → Evolution API instance name
       {número_whatsapp} → WhatsApp numbers
       {url_do_servidor} → Server URLs
       {a sua apikey aqui} → API keys
       {seu_calendario} → Google Calendar ID

  Customize AI Prompts
     Adjust system prompts to fit your clinic’s tone, service style, and patient communication guidelines.
     Set clinic operating hours, escalation rules, and cancellation procedures in AI prompts.

  Activate and Test
     Simulate patient messages via WhatsApp.
     Test Telegram commands from staff members.
     Validate daily appointment reminders using the scheduled trigger.

  🏷️ Tags
  Healthcare Clinic Management WhatsApp Integration Telegram Bot Appointment Scheduling Google Calendar Google Tasks AI Agents n8n Automation  

  📚 Technical Notes
  PostgreSQL is used for persistent chat memory across sessions.
  Multiple AI Models Used:
    OpenAI GPT-4.1-nano
    OpenAI GPT-4.1-mini
    Google Gemini 2.0 and 2.5
  Full media content processing supported (audio, image, text).
  Compliant escalation workflows ensure patient safety and proper handoff to human staff when necessary.
  All sensitive patient data are securely stored inside calendar event descriptions for easy retrieval by agents.

  📜 License
  This workflow is provided under the MIT License.  
  Feel free to adapt and customize it for your clinic’s specific needs.

nodes_used:
  ["n8n-nodes-base.telegram","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.toolWorkflow","@n8n/n8n-nodes-langchain.openAi","@n8n/n8n-nodes-langchain.memoryPostgresChat","@n8n/n8n-nodes-langchain.lmChatOpenRouter","@n8n/n8n-nodes-langchain.mcpClientTool"]

workflow_json:
  {"id":"6LeAm5UyENgTdwkv","meta":{"instanceId":"6d46e25379ef430a7067964d1096b885c773564549240cb3ad4c087f6cf94bd3","templateCredsSetupCompleted":true},"name":"agente","tags":[],"nodes":[{"id":"84ce6905-4416-4721-8627-f8c303730a4f","name":"OpenAI Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[8260,2260],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1-nano-2025-04-14","cachedResultName":"gpt-4.1-nano-2025-04-14"},"options":{}},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.2},{"id":"a6e9358a-a873-49f3-af38-21ca545b2bfc","name":"Assistente clinica interno","type":"@n8n/n8n-nodes-langchain.agent","position":[8380,2020],"parameters":{"text":"={{ $json.message.text }}","options":{"systemMessage":"=Hoje é {{$now}}\nPAPEL:  \nVocê é um assistente interno de reagendamento na clínica, acionado diretamente por um profissional via Telegram para gerenciar situações de remarcação de consultas ou incluir lembretes na lista de compras.\n\nOBJETIVO GERAL:  \n1. Reagendar consultas a pedido do profissional.  \n2. Adicionar lembretes na lista de compras quando solicitado.  \n\nRESUMO DE RESPONSABILIDADES:  \n1. Reagendamento de pacientes  \n   - Acesse o Google Calendar por meio da ferramenta \"MCP Google Calendar\" para identificar as consultas afetadas.  \n   - Extraia o número de telefone na descrição do evento.  \n   - Use a ferramenta \"Reagendar no WhatsApp\" para enviar mensagens de reagendamento aos pacientes.  \n   - Lembre-se de que você apenas envia a mensagem; a resposta do paciente é tratada por outro agente.  \n\n2. Lista de compras da clínica  \n   - Se o profissional solicitar pelo Telegram a inclusão de um item na lista de compras, utilize a ferramenta \"Google Tasks\" para adicionar o lembrete.  \n\nORIENTAÇÕES DE LINGUAGEM E PROCEDIMENTO:  \n- Use uma abordagem empática, profissional e acolhedora.  \n- Nunca envie mensagens para pacientes sem autorização explícita do profissional.  \n- Quando listar eventos ou tarefas, seja objetivo e organizado.  \n- Mantenha clareza e concisão em todas as interações.  \n\nFERRAMENTAS DISPONÍVEIS:  \n- Reagendar no WhatsApp  \n- Google Tasks  \n- MCP Google Calendar  \n\nINSTRUÇÕES FINAIS:  \n- Atenda exclusivamente às solicitações de reagendamento e inclusão de lembretes.  \n- A remarcação de consultas ocorre somente quando o profissional pede, utilizando o MCP Google Calendar para identificar os pacientes e o \"Reagendar no WhatsApp\" para enviar a mensagem.  \n- Para a lista de compras, sempre registre no \"Google Tasks\".  \n"},"promptType":"define"},"typeVersion":1.8},{"id":"d674fb31-cf45-47ac-b33b-4abe1920e352","name":"Google Tasks","type":"n8n-nodes-base.googleTasksTool","position":[8720,2320],"parameters":{"task":"bDQ5ZlNVV2lPQ3pYT3NsNA","title":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Title', ``, 'string') }}","additionalFields":{"notes":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Notes', ``, 'string') }}","status":"needsAction"}},"credentials":{"googleTasksOAuth2Api":{"id":"3SQEwHb0AR81JO8y","name":"Google Tasks account"}},"typeVersion":1},{"id":"dff00a3c-6496-4104-afc4-a0556f3cabfa","name":"MCP Google Calendar","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[8560,2320],"parameters":{"sseEndpoint":"https://engaging-seahorse-19.rshare.io/mcp/ceb17fa5-1937-405f-8000-ea3be7d2b032/mcp/:tool/calendar/sse"},"typeVersion":1},{"id":"10a0bda3-94b3-487a-98a1-1e7badcc8775","name":"Receber Mensagem Telegram","type":"n8n-nodes-base.telegramTrigger","position":[8100,2020],"webhookId":"f2b29356-d5d3-4f5d-9ef1-273001c0a820","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"TAVUHrFXuDIMInWe","name":"Telegram account"}},"typeVersion":1.2},{"id":"46cfa6be-f896-4e33-be3d-b4ef676c043b","name":"Postgres Chat Memory","type":"@n8n/n8n-nodes-langchain.memoryPostgresChat","position":[8420,2300],"parameters":{"sessionKey":"100","sessionIdType":"customKey","contextWindowLength":10},"credentials":{"postgres":{"id":"t8gw5Kie6Oxy5TcK","name":"Postgres account"}},"typeVersion":1.3},{"id":"c79c44f6-94fa-4e56-9d94-49185f83bfb4","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[5860,3980],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1-mini-2025-04-14","cachedResultName":"gpt-4.1-mini-2025-04-14"},"options":{}},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.2},{"id":"5e7ac239-6ba1-414c-b11d-d637361e8f77","name":"Assistente Clínica","type":"@n8n/n8n-nodes-langchain.agent","position":[5960,3760],"parameters":{"text":"={{ $json.text }}{{ $json.output}}","options":{"systemMessage":"=HOJE É: {{ $now }}\nCONTATO DA CLÍNICA: \n{ coloque o seu contato aqui }\n\nINSTRUÇÃO IMPORTANTE:\n\nAo criar ou editar qualquer evento via MCP_CALENDAR, inclua na descrição do agendamento:\n\nTelefone do paciente\n\nNome completo\n\nData de nascimento\n\nInformações adicionais (convênio, condição de saúde etc.)\n\nPAPEL:\nVocê é uma atendente do WhatsApp da Clínica Moreira, especializada em atendimento humanizado. Sua missão:\n\nAtender pacientes de forma ágil e eficiente\n\nResponder dúvidas sobre clínica e serviços\n\nAgendar, remarcar e cancelar consultas pelo MCP_CALENDAR\n\nPERSONALIDADE E TOM DE VOZ:\n\nSimpática, acolhedora e respeitosa\n\nFormal, sem emojis ou gírias\n\nFERRAMENTAS DISPONÍVEIS:\n\nMCP_CALENDAR (trigger /mcp/:tool/calendar)\n\nAVALIABILITY_CALENDAR: verifica horários livres entre Start_Time e End_Time\n\nGET_ALL_CALENDAR: lista todos os eventos entre After e Before\n\nCREATE_CALENDAR: cria novo evento com start, end e Description (inclua sempre telefone, nome e data de nascimento)\n\nUPDATE_CALENDAR: atualiza campos de um evento existente (Event_ID)\n\nDELETE_CALENDAR: remove evento (Event_ID)\n\nGET_CALENDAR: obtém detalhes de um evento específico (Event_ID)\n\nCallToHuman (workflow id A95kslcW4H82nJuR)\n\nEncaminha atendimento humano via EvolutionAPI em n8n\n\nDisparar IMEDIATAMENTE quando:\n\nUrgência ou mal-estar grave\n\nPedido de diagnóstico/opinião médica\n\nInsatisfação expressa do paciente\n\nAssuntos fora do escopo da clínica\n\nExemplo de chamada:\n\n{\n  \"tool\": \"CallToHuman\",\n  \"telefone\": \"<telefone>\",\n  \"nome\": \"<nome completo>\",\n  \"ultima_mensagem\": \"<texto da última mensagem>\"\n}\n\nEnviar telegram cancelamento\n\nApós DELETE_CALENDAR, envie ao gestor via Telegram: nome, data, hora\n\nSOP (Fluxo de Atendimento):\n\nInício e coleta de dados\n\nCumprimente e informe o link da agenda: https://calendar.google.com/calendar/embed?src=a57a3781407f42b1ad7fe24ce76f558dc6c86fea5f349b7fd39747a2294c1654%40group.calendar.google.com&ctz=America%2FArgentina%2FBuenos_Aires\n\nPeça: nome completo, data de nascimento e confirme o telefone\n number: {{ $('Webhook1').item.json.body.data.key.remoteJid.replaceAll(\"@s.whatsapp.net\",\"\") }}\n\nVerificação de disponibilidade\n\nPergunte data e turno preferidos\n\nChame AVALIABILITY_CALENDAR com Start_Time 08:00 e End_Time 19:00 (ou turno)\n\nInforme horários livres\n\nAgendamento\n\nApós escolha do paciente, use CREATE_CALENDAR com start, end e Description\n\nAguarde retorno para confirmar criação antes de responder\n\nRemarcação\n\nSolicite dados e nova preferência de data/turno\n\nLocalize evento antigo via GET_ALL_CALENDAR\n\nUse DELETE_CALENDAR no Event_ID antigo\n\nCrie novo com CREATE_CALENDAR\n\nConfirme após sucesso\n\nCancelamento\n\nSolicite dados do paciente\n\nIdentifique Event_ID via GET_ALL_CALENDAR ou GET_CALENDAR\n\nExecute DELETE_CALENDAR\n\nUse Enviar telegram cancelamento\n\nConfirme cancelamento ao paciente\n\nConfirmação de consulta (follow-up)\n\nSe paciente responder “Confirmar, ID”: use UPDATE_CALENDAR para prefixar título com [Confirmado]\n\nSe “Reagendar, ID”: DELETE_CALENDAR e oriente para usar link da agenda\n\nREGRAS DE ESCALONAMENTO:\n\nUse CallToHuman IMEDIATAMENTE em situações de:\n\nUrgência/mal-estar\n\nPedidos de diagnóstico/opinião médica\n\nInsatisfação ou reclamações\n\nAssuntos fora do escopo\n\nMANTENHA SEMPRE:\n\nTom profissional e respeitoso\n\nLinguagem clara e objetiva\n\nAgendamentos apenas em datas futuras\n\nNunca confirmar sem retorno do MCP_CALENDAR\n\nHORÁRIOS DE FUNCIONAMENTO:\n\nSeg–Sáb: 08h–19h | Dom e feriados: fechado\n\nLOCALIZAÇÃO:\nRua Rio Casca, 417 – Belo Horizonte, MG\n\nLINK DA AGENDA:\nhttps://calendar.google.com/calendar/embed?src=a57a3781407f42b1ad7fe24ce76f558dc6c86fea5f349b7fd39747a2294c1654%40group.calendar.google.com&ctz=America%2FArgentina%2FBuenos_Aires\n\n"},"promptType":"define"},"retryOnFail":true,"typeVersion":1.8,"waitBetweenTries":1000},{"id":"2f0a6ea1-7654-4ae7-884e-d5b8ff47d4f9","name":"Enviar alerta de cancelamento","type":"n8n-nodes-base.telegramTool","position":[6400,3980],"webhookId":"d045a8c1-ec1b-4d20-8226-457aa18934af","parameters":{"text":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Text', ``, 'string') }}","chatId":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Chat_ID', ``, 'string') }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"TAVUHrFXuDIMInWe","name":"Telegram account"}},"typeVersion":1.2},{"id":"8ddaa14f-7d2f-4364-8ff7-f87e0a428e37","name":"Gatilho diário","type":"n8n-nodes-base.scheduleTrigger","position":[8060,2780],"parameters":{"rule":{"interval":[{"field":"cronExpression","expression":"0 8 * * 1-5"}]}},"typeVersion":1.2},{"id":"0784753d-123d-4259-abcc-8abf39e7fc07","name":"Assistente de confirmação","type":"@n8n/n8n-nodes-langchain.agent","position":[8280,2680],"parameters":{"text":"=Hoje é {{ $now }}. Você é um agente especializado em **confirmação de consultas** para a clínica. Sua função principal é:\n\n1. **Listar os eventos** agendados para o próximo dia no MCP Calendar.\n2. **Obter o numero** na descrição de cada evento.\n3. **Enviar uma mensagem de confirmação** usando a ferramenta “relembraAGENDAMENTO”, perguntando se o paciente confirma a consulta ou prefere reagendar.\n\nImportante:\n- Você **não recebe respostas** diretamente; o retorno do paciente é tratado por outro agente.\n\n","options":{"systemMessage":""},"promptType":"define"},"typeVersion":1.8},{"id":"afa90e86-0f44-4069-976b-ca302b0d828a","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[5840,4460],"parameters":{"text":"={{ $json.output }}","options":{"systemMessage":"=Você é especialista em formatação de mensagem para whataspp, trabalhando somente na formatação e não alterando o conteúdo da menssagem.\n\n- Substitua ** por *\n- Remova #"},"promptType":"define"},"typeVersion":1.8},{"id":"13179a70-85b6-4e18-8736-eb2cdd252591","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[6960,2580],"parameters":{"color":5,"width":1940,"height":600,"content":"# \"Appointment Confirmation Assistant\"\nDescription:\n\nPurpose:\nThis section contains the configuration for the Appointment Confirmation Assistant, an agent specialized in confirming scheduled appointments with patients.\n\nInstructions for Use:\n\nIt is triggered automatically every weekday (Monday to Friday) at 08:00 AM via the Daily Trigger (Gatilho diário).\n\nThe agent retrieves all appointments scheduled for the next day using MCP Google Calendar.\n\nIt extracts each patient's phone number from the event description field.\n\nA confirmation message is sent to each patient using the relembraAGENDAMENTO tool, asking for confirmation or rescheduling.\n\nImportant: This agent does not handle responses from patients; another agent or workflow is responsible for follow-ups.\n\nMake sure event descriptions in Google Calendar are correctly filled to avoid errors.\n\n"},"typeVersion":1},{"id":"4111432b-2ddc-4e96-ba6d-d25e003e2688","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[4760,3620],"parameters":{"color":3,"width":1780,"height":640,"content":"# \"Agent Core Components (Tools, MCP, Memory, LLM Model)\"\nDescription:\n\nPurpose:\n\nThis sticky note represents the essential structure of any intelligent agent: it includes access to external tools,\n persistent memory, the MCP system for calendar management, and a Language Model (LLM) to process natural language tasks.\n\nInstructions for Use:\n\nLanguage Model nodes (OpenAI, OpenRouter) are responsible for natural language understanding and generation.\n\nMemory nodes (Postgres Chat Memory) maintain conversation context over multiple interactions.\n\nMCP Tools interact with Google Calendar and other services to perform real-world actions.\n\nAlways ensure memory synchronization between the agent's context and actions performed.\n\nIf new tools are added, they must be connected both to the agent and properly described in the system message.\n\n"},"typeVersion":1},{"id":"4b59f903-07c2-4e66-9ea1-0727beb0d85c","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[4640,4300],"parameters":{"color":4,"width":1800,"height":640,"content":"# \"Processing and Sending WhatsApp Responses\"\nDescription:\n\nPurpose:\nThis section is responsible for processing, formatting, and sending outbound WhatsApp messages to patients through the Evolution API.\n\nInstructions for Use:\n\nMessages received from the assistant agent are first reformatted by the AI Agent node to comply with WhatsApp markdown syntax (e.g., replacing **bold** with *bold*).\n\nOnce formatted, the messages are forwarded to WhatsApp using the Evolution API2 node.\n\nEnsure proper formatting before sending to maintain a professional communication tone and avoid delivery errors.\n\nAny future text-processing improvements should be implemented here."},"typeVersion":1},{"id":"274f7f66-7613-4e9e-868d-a5705156dde6","name":"Postgres Chat Memory1","type":"@n8n/n8n-nodes-langchain.memoryPostgresChat","position":[6000,3980],"parameters":{"sessionKey":"= {{ $('Webhook1').item.json.body.data.key.id }}","sessionIdType":"customKey","contextWindowLength":50},"credentials":{"postgres":{"id":"t8gw5Kie6Oxy5TcK","name":"Postgres account"}},"typeVersion":1.3},{"id":"654ed617-df1a-48db-b9bc-833b2c1ecb80","name":"MCP Google Calendar2","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[6120,3980],"parameters":{"sseEndpoint":"https://engaging-seahorse-19.rshare.io/mcp/ceb17fa5-1937-405f-8000-ea3be7d2b032/mcp/:tool/calendar/sse"},"typeVersion":1},{"id":"b11aeec6-b446-4c02-a0b0-7f9239628df3","name":"MCP GMAIL","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[8540,3000],"parameters":{"sseEndpoint":"https://engaging-seahorse-19.rshare.io/mcp/82a7a338-618c-44f5-a1c3-f2e32b6b4833/mcp/:tool/gmail/sse"},"typeVersion":1},{"id":"f5a38b34-499e-4bbc-9282-ce5f4a3b85a3","name":"MCP CALENDAR","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[8380,3000],"parameters":{"sseEndpoint":"https://engaging-seahorse-19.rshare.io/mcp/ceb17fa5-1937-405f-8000-ea3be7d2b032/mcp/:tool/calendar/sse"},"typeVersion":1},{"id":"cd6a6147-fd18-4cd4-8aab-fcb454ab76b7","name":"Telegram","type":"n8n-nodes-base.telegram","position":[8740,2020],"webhookId":"5bba05fc-2859-4225-aa85-7c4bc5ff532d","parameters":{"text":"={{ $json.output }}","chatId":"={{ $('Receber Mensagem Telegram').item.json.message.chat.id }}","additionalFields":{}},"credentials":{"telegramApi":{"id":"TAVUHrFXuDIMInWe","name":"Telegram account"}},"typeVersion":1.2},{"id":"900b8c1a-f987-4898-9fc1-bfc673773e06","name":"OpenRouter Chat Model1","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[5760,4680],"parameters":{"model":"google/gemini-2.0-flash-exp:free","options":{}},"credentials":{"openRouterApi":{"id":"eGPA8rbskZCfFPBn","name":"OpenRouter account"}},"typeVersion":1},{"id":"1584b448-d8f5-4bab-ad9a-9b07edb8e102","name":"Webhook1","type":"n8n-nodes-base.webhook","position":[5760,2100],"webhookId":"405dab7c-a0ea-4f5b-a6cc-ede9d5ba78a0","parameters":{"path":"evolutionAPIKORE","options":{},"httpMethod":"POST"},"typeVersion":2},{"id":"74b5179f-502c-45d6-88e9-2c2d492603cd","name":"Edit Fields1","type":"n8n-nodes-base.set","position":[6000,2100],"parameters":{"options":{},"assignments":{"assignments":[{"id":"3e6335ae-74c3-4655-b68f-cdf0c68b864f","name":"number","type":"string","value":"={{ $json.body.data.key.remoteJid }}"},{"id":"15f399cf-a98e-45e7-91ce-61b4fad340fd","name":"name","type":"string","value":"={{ $json.body.data.pushName }}"},{"id":"b1943003-1f47-40e1-b418-6a52557ec44e","name":"key_id","type":"string","value":"={{ $json.body.data.key.id }}"},{"id":"ed23194b-22ca-455b-a085-7dae706d0569","name":"text","type":"string","value":"={{ $json.body.data.message.conversation }}"},{"id":"b35f8b61-da15-42e3-a078-4cd901e1f273","name":"type","type":"string","value":"={{ $json.body.data.message.imageMessage.mimetype }}"},{"id":"a62bf96a-51aa-44c3-9e5d-f592e32a31d6","name":"image.url","type":"string","value":"={{ $json.body.data.message.imageMessage.url }}"},{"id":"b004987d-3527-4040-a5e6-5fe06b25c9b9","name":"audio.url","type":"string","value":"={{ $json.body.data.message.audioMessage.url }}"},{"id":"4c2cc03a-c104-4a87-9d31-6a7c256890ad","name":"document.url","type":"string","value":"={{ $json.body.data.message.documentMessage.url }}"}]}},"typeVersion":3.4},{"id":"ce22f5bc-f0e1-463d-9b9a-5112f8d91f00","name":"Switch","type":"n8n-nodes-base.switch","position":[6240,2080],"parameters":{"rules":{"values":[{"outputKey":"text","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2f9854ac-26b3-446c-9d0d-ae25157c61bb","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.text }}","rightValue":"="}]},"renameOutput":true},{"outputKey":"image","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"73b7d93a-928e-42ec-9c8e-ae8e9b97a867","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.image.url }}","rightValue":"="}]},"renameOutput":true},{"outputKey":"audio","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2f9915b9-e2b4-4528-ad36-515a848ab1be","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.audio.url }}","rightValue":"[null]"}]},"renameOutput":true},{"outputKey":"document","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9fcbe89a-c9d7-4dc6-bb6f-27c1cacbfddc","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.document.url }}","rightValue":"[null]"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"c78ee758-fb71-4a4f-9450-0ffcd67a2af2","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[4960,1840],"parameters":{"color":6,"width":1580,"height":640,"content":"# Incoming WhatsApp Webhook and Message Type Handling\"\nDescription:\n\nPurpose:\nManages the initial reception and classification of incoming WhatsApp messages from patients via the webhook system.\n\nInstructions for Use:\n\nThe Webhook1 node captures incoming messages.\n\nEdit Fields1 extracts structured fields such as text, image URL, audio URL, and document URL.\n\nSwitch node analyzes which type of content was received and directs the flow accordingly:\n\nText → Forwarded to the assistant for handling.\n\nImage → Sent for OCR analysis.\n\nAudio → Sent for transcription.\n\nDocument → (Currently unused, but ready for future workflows).\n\nKeep webhook credentials updated to ensure system reliability.\n\n"},"typeVersion":1},{"id":"83abbf61-91e2-4d1c-a42a-4f05b18583e7","name":"OpenAI","type":"@n8n/n8n-nodes-langchain.openAi","position":[6380,3260],"parameters":{"options":{},"resource":"audio","operation":"transcribe","binaryPropertyName":"=data"},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.8},{"id":"4c2dcefc-fb65-42ca-8c63-8636f2906654","name":"Evolution API","type":"n8n-nodes-evolution-api.evolutionApi","position":[5860,3260],"parameters":{"resource":"chat-api","messageId":"={{ $json.key_id }}","operation":"get-media-base64","convertToMp4":true,"instanceName":"={{ $('Webhook1').item.json.body.instance }}"},"credentials":{"evolutionApi":{"id":"fPKdX0EITLV8HI89","name":"Evolution account"}},"typeVersion":1},{"id":"85909834-7564-478b-bce8-0c3fe7bf4159","name":"Convert to File","type":"n8n-nodes-base.convertToFile","position":[6100,3260],"parameters":{"options":{},"operation":"toBinary","sourceProperty":"data.base64"},"typeVersion":1.1},{"id":"3e200157-fbcc-4225-b982-2dfaea54cc23","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[4980,3100],"parameters":{"width":1760,"height":480,"content":"## \"Download Audio and Convert to MP4\"\nDescription:\n\nPurpose:\nHandles retrieval, conversion, and transcription of audio files sent by patients via WhatsApp.\n\nInstructions for Use:\n\nEvolution API downloads the audio in base64 format.\n\nConvert to File transforms base64 into a binary file compatible with transcription engines.\n\nOpenAI Whisper API (via OpenAI node) transcribes the audio into text, preparing it for natural language processing.\n\nEnsure audio formats are correctly handled (e.g., MP4/MP3) to avoid conversion or transcription failures.\n\nMonitor for potential heavy file size issues (>25MB) which may impact performance."},"typeVersion":1},{"id":"5862d5f1-2df4-40ee-881f-a6d6e302602f","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[4920,2540],"parameters":{"width":1820,"height":480,"content":"# \"Extract Text from Images\"\nDescription:\n\nPurpose:\nProcesses images received via WhatsApp to extract text (OCR) and describe their visual content for further contextual analysis.\n\nInstructions for Use:\n\nThe OpenAI1 node uses a Vision model to transcribe and describe any text or scene from incoming images.\n\nThe resulting data is interpreted by the AI Agent2, which prepares insights and recommends appropriate responses.\n\nImage-to-text extraction is especially useful for handling prescriptions, notes, or medical documents sent by patients.\n\nMaintain quality standards: images must be clear and high-resolution for best transcription results."},"typeVersion":1},{"id":"8dbd4e6d-8b38-44d8-ba45-5cac2713f6ca","name":"OpenAI1","type":"@n8n/n8n-nodes-langchain.openAi","position":[5980,2620],"parameters":{"text":"TRANSCRIBE OS TEXTOS e describe a imagem","modelId":{"__rl":true,"mode":"list","value":"chatgpt-4o-latest","cachedResultName":"CHATGPT-4O-LATEST"},"options":{},"resource":"image","imageUrls":"={{ $json.image }}","operation":"analyze"},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.8},{"id":"19e8d50d-4f87-408e-96f0-236932c1d120","name":"AI Agent2","type":"@n8n/n8n-nodes-langchain.agent","position":[6200,2620],"parameters":{"text":"={{$json.output}}","options":{"systemMessage":"voce e encarregado de analizar o texto proveniente do analisis de uma iamgem ela pode conter texto, a ideia e que voce explique ao proximo agente como debe responder as mensagens"},"promptType":"define"},"typeVersion":1.9},{"id":"0d2f9842-b011-49f5-9594-24a917dee60e","name":"OpenRouter Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[6100,2860],"parameters":{"model":"google/gemini-2.5-pro-exp-03-25:free","options":{}},"credentials":{"openRouterApi":{"id":"eGPA8rbskZCfFPBn","name":"OpenRouter account"}},"typeVersion":1},{"id":"58f7f9c7-6f86-40ff-bfad-5467e5b3a9e4","name":"Evolution API2","type":"n8n-nodes-evolution-api.evolutionApi","position":[6200,4460],"parameters":{"resource":"messages-api","remoteJid":"={{ $('Webhook1').item.json.body.data.key.remoteJid }}","messageText":"={{$json.output}}","instanceName":"={{ $('Webhook1').item.json.body.instance }}","options_message":{}},"credentials":{"evolutionApi":{"id":"fPKdX0EITLV8HI89","name":"Evolution account"}},"typeVersion":1},{"id":"2b529ab1-2a7e-44e0-b7c8-ed05e07c6def","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[6960,1840],"parameters":{"width":1960,"height":680,"content":"## \"Internal Clinic Assistant\"\nDescription:\n\nPurpose:\nRepresents the Internal Assistant for the clinic, used exclusively by the internal team via Telegram to manage patient rescheduling and manage a purchasing reminder list.\n\nInstructions for Use:\n\nTriggered by staff messages sent via Telegram.\n\nRescheduling tasks:\n\nAccess the MCP Google Calendar to locate and manage appointments.\n\nExtract patient contact from the event description.\n\nSend rescheduling messages through WhatsApp using the dedicated tool.\n\nShopping list tasks:\n\nInsert shopping list reminders into Google Tasks based on the staff's instructions.\n\nAlways maintain professional and empathetic tone when interacting with patients, even if the communication is indirect.\n\nAvoid unauthorized direct patient contact without staff permission."},"typeVersion":1},{"id":"a4a51bd1-48a6-4e32-b696-0ae77a0e05fe","name":"CallToHuman","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[6240,4000],"parameters":{"name":"escalar_humano","workflowId":{"__rl":true,"mode":"list","value":"A95kslcW4H82nJuR","cachedResultName":"callToHuman"},"description":"=Use essa ferramenta ao perceber que o paciente fala de:\n- Situações urgentes (sentindo-se mal, etc.)\n- Assuntos não relacionados à clínica\n- Insatisfação extrema ou pedidos de falar com um humano\n","workflowInputs":{"value":{"nome":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('nome', ``, 'string') }}","telefone":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('telefone', ``, 'string') }}","ultima_mensagem":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('ultima_mensagem', ``, 'string') }}"},"schema":[{"id":"telefone","type":"string","display":true,"required":false,"displayName":"telefone","defaultMatch":false,"canBeUsedToMatch":true},{"id":"nome","type":"string","display":true,"required":false,"displayName":"nome","defaultMatch":false,"canBeUsedToMatch":true},{"id":"ultima_mensagem","type":"string","display":true,"required":false,"displayName":"ultima_mensagem","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"674c5c75-a954-4306-8a02-71bdda89293c","name":"OpenAI Chat Model2","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[8260,2840],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1-mini","cachedResultName":"gpt-4.1-mini"},"options":{}},"credentials":{"openAiApi":{"id":"zUnIUrOWA279vAoC","name":"OpenAi account"}},"typeVersion":1.2},{"id":"b398627e-2fbe-44e4-ac2f-523b03871eda","name":"REMINDER","type":"n8n-nodes-evolution-api.evolutionApi","position":[8640,2700],"parameters":{"resource":"messages-api","remoteJid":"5511111111111@s.whatsapp.net","messageText":"={{$fromAI(\"reminder\")}}","instanceName":"instance name","options_message":{}},"credentials":{"evolutionApi":{"id":"fPKdX0EITLV8HI89","name":"Evolution account"}},"typeVersion":1}],"active":false,"pinData":{"Webhook1":[{"json":{"body":{"data":{"key":{"id":"05D218BDE5BFC8378B5AA50BA87FDAFE","fromMe":false,"remoteJid":"5491169701682@s.whatsapp.net"},"source":"android","status":"DELIVERY_ACK","message":{"conversation":"Sim","messageContextInfo":{"messageSecret":"RdahuRio1gbaHLsCeV24k8yFFyJWGpAJ5zHYRc2QysU=","deviceListMetadata":{"recipientKeyHash":"KgcEIs2I9kXQgQ==","recipientTimestamp":"1745501413"},"deviceListMetadataVersion":2}},"pushName":"Luciano","instanceId":"317a031e-567d-4c2e-9bc4-146616fe4db7","messageType":"conversation","messageTimestamp":1745501855},"event":"messages.upsert","apikey":"59BA76B6BD78-403B-A0CC-8735B6A7ED3A","sender":"553191282843@s.whatsapp.net","instance":"kore","date_time":"2025-04-24T10:37:35.514Z","server_url":"http://localhost:8080","destination":"https://engaging-seahorse-19.rshare.io/webhook/evolutionAPIKORE"},"query":{},"params":{},"headers":{"host":"host.docker.internal:5678","x-scheme":"https","forwarded":"by=_exposr;for=179.0.72.34;host=engaging-seahorse-19.rshare.io;proto=https","x-real-ip":"179.0.72.34","connection":"keep-alive","exposr-via":"b9e7ef031eb8fe005896193e59b1d6f6d8743b1e","user-agent":"axios/1.7.9","content-type":"application/json","x-request-id":"91360975101096aa10d12cb5b8925b55","content-length":"821","accept-encoding":"gzip, compress, deflate, br","x-forwarded-for":"179.0.72.34","x-forwarded-host":"engaging-seahorse-19.rshare.io","x-forwarded-port":"443","x-forwarded-proto":"https","x-forwarded-scheme":"https"},"webhookUrl":"https://engaging-seahorse-19.rshare.io/webhook/evolutionAPIKORE","executionMode":"production"}}],"Gatilho diário":[{"json":{"Hour":"10","Year":"2025","Month":"April","Minute":"13","Second":"11","Timezone":"America/New_York (UTC-04:00)","timestamp":"2025-04-24T10:13:11.035-04:00","Day of week":"Thursday","Day of month":"24","Readable date":"April 24th 2025, 10:13:11 am","Readable time":"10:13:11 am"}}]},"settings":{"executionOrder":"v1"},"versionId":"3044ad5c-d14e-4562-a454-0ad87f26dc68","connections":{"OpenAI":{"main":[[{"node":"Assistente Clínica","type":"main","index":0}]]},"Switch":{"main":[[{"node":"Assistente Clínica","type":"main","index":0}],[{"node":"OpenAI1","type":"main","index":0}],[{"node":"Evolution API","type":"main","index":0}],[]]},"OpenAI1":{"main":[[{"node":"AI Agent2","type":"main","index":0}]]},"AI Agent":{"main":[[{"node":"Evolution API2","type":"main","index":0}]]},"Webhook1":{"main":[[{"node":"Edit Fields1","type":"main","index":0}]]},"AI Agent2":{"main":[[{"node":"Assistente Clínica","type":"main","index":0}]]},"MCP GMAIL":{"ai_tool":[[{"node":"Assistente de confirmação","type":"ai_tool","index":0}]]},"CallToHuman":{"ai_tool":[[{"node":"Assistente Clínica","type":"ai_tool","index":0}]]},"Edit Fields1":{"main":[[{"node":"Switch","type":"main","index":0}]]},"Google Tasks":{"ai_tool":[[{"node":"Assistente clinica interno","type":"ai_tool","index":0}]]},"MCP CALENDAR":{"ai_tool":[[{"node":"Assistente de confirmação","type":"ai_tool","index":0}]]},"Evolution API":{"main":[[{"node":"Convert to File","type":"main","index":0}]]},"Convert to File":{"main":[[{"node":"OpenAI","type":"main","index":0}]]},"Gatilho diário":{"main":[[{"node":"Assistente de confirmação","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Assistente Clínica","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model1":{"ai_languageModel":[[{"node":"Assistente clinica interno","type":"ai_languageModel","index":0}]]},"OpenAI Chat Model2":{"ai_languageModel":[[{"node":"Assistente de confirmação","type":"ai_languageModel","index":0}]]},"Assistente Clínica":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"MCP Google Calendar":{"ai_tool":[[{"node":"Assistente clinica interno","type":"ai_tool","index":0}]]},"MCP Google Calendar2":{"ai_tool":[[{"node":"Assistente Clínica","type":"ai_tool","index":0}]]},"Postgres Chat Memory":{"ai_memory":[[{"node":"Assistente clinica interno","type":"ai_memory","index":0}]]},"Postgres Chat Memory1":{"ai_memory":[[{"node":"Assistente Clínica","type":"ai_memory","index":0}]]},"OpenRouter Chat Model1":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"OpenRouter Chat Model2":{"ai_languageModel":[[{"node":"AI Agent2","type":"ai_languageModel","index":0}]]},"Receber Mensagem Telegram":{"main":[[{"node":"Assistente clinica interno","type":"main","index":0}]]},"Assistente clinica interno":{"main":[[{"node":"Telegram","type":"main","index":0}]]},"Assistente de confirmação":{"main":[[{"node":"REMINDER","type":"main","index":0}]]},"Enviar alerta de cancelamento":{"ai_tool":[[{"node":"Assistente Clínica","type":"ai_tool","index":0}]]}}}


name: Generate Custom AI Images with OpenAI GPT-Image-1 Model
author_name: Max aka Mosheh
author_username: aiwithapex
nodes_used: ["n8n-nodes-base.httpRequest"]
categories: []
created_at: 2025-04-25T07:23:43.257Z
updated_at: 2025-04-25T07:23:43.257Z
url: https://n8n.io/workflows/3705
scraped_at: 2025-07-06 21:16:30
description:
  How it works  
  Trigger the workflow manually via the n8n UI.  
  Define key parameters like the image prompt, number of images, size, quality, and model.  
  Send a POST request to OpenAI’s image generation API using those inputs.  
  Split the API response to handle multiple images.  
  Convert the base64 image data into downloadable binary files.

  Set up steps  
  Initial setup takes around 5–10 minutes. You’ll need an OpenAI API key, a configured HTTP Request node with credentials, and to customize the prompt/parameter fields in the “Set Variables” node. No advanced config or external services needed.

  Important Note
  You have to make sure to complete OpenAI's new verification requirements to use their new image API:
  https://help.openai.com/en/articles/10910291-api-organization-verification

  It only takes a few minutes and does not cost any money.

workflow_json:
  {"id":"FyoPGDh8r3pxcGxo","meta":{"instanceId":"bcc0fe85b176c2837affb21bb7d7397fad2549880e73dc1f7a42e76ae94fd996"},"name":"New OpenAI Image Generation","tags":[{"id":"SGTGlhD84tHTcai7","name":"image gen","createdAt":"2025-04-07T09:41:10.936Z","updatedAt":"2025-04-07T09:41:10.936Z"}],"nodes":[{"id":"6b5f9234-351f-4f6b-a0ab-f0d30897f60a","name":"Convert to File","type":"n8n-nodes-base.convertToFile","position":[320,400],"parameters":{"options":{},"operation":"toBinary","sourceProperty":"b64_json"},"typeVersion":1.1},{"id":"9c60f827-bf37-486b-9026-0cbe97fd83b6","name":"OpenAI - Generate Image","type":"n8n-nodes-base.httpRequest","position":[-120,400],"parameters":{"url":"https://api.openai.com/v1/images/generations","method":"POST","options":{},"jsonBody":"={\n  \"model\": \"{{ $json.openai_image_model }}\",\n  \"prompt\": \"{{ $json.image_prompt }}\",\n  \"n\": {{ $json.number_of_images }},\n  \"size\": \"{{ $json.size_of_image }}\",\n  \"quality\": \"{{ $json.quality_of_image }}\"\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","authentication":"predefinedCredentialType","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]},"nodeCredentialType":"openAiApi"},"credentials":{"openAiApi":{"id":"KzjXYSuzUOCnnvzB","name":"OpenAi account"}},"typeVersion":4.2},{"id":"2dd04b96-5faf-48ec-a7b0-66a31866388d","name":"When clicking ‘Test workflow’","type":"n8n-nodes-base.manualTrigger","position":[-560,400],"parameters":{},"typeVersion":1},{"id":"629799c0-d2ff-4c5a-95d8-54d5afd3ac66","name":"Set Variables","type":"n8n-nodes-base.set","position":[-340,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2a5d52c2-5af1-4796-acba-4e1807fc7d7b","name":"image_prompt","type":"string","value":"a 4-frame cartoon strip telling a joke about AI"},{"id":"c41a8091-d952-4f5a-ae24-3b0691bbce57","name":"number_of_images","type":"number","value":2},{"id":"00feec5a-19c8-43af-bf93-e0729d1391f8","name":"quality_of_image","type":"string","value":"high"},{"id":"1b359a11-c05a-49c8-aa27-402b145fcbc1","name":"size_of_image","type":"string","value":"1024x1024"},{"id":"6cf4ba85-d11a-48bb-9eaf-4084c9538d87","name":"openai_image_model","type":"string","value":"=gpt-image-1"}]}},"typeVersion":3.4},{"id":"5f4e4bbe-7331-42dc-86a3-5d9de658ea07","name":"Separate Image Outputs","type":"n8n-nodes-base.splitOut","position":[100,400],"parameters":{"options":{},"fieldToSplitOut":"data"},"typeVersion":1},{"id":"0c0310a4-f354-4810-a967-ea002be09cc4","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-600,580],"parameters":{"width":1140,"height":220,"content":"## [CLICK HERE to Watch Video](https://youtu.be/YmDezgolqzU?si=BgMjRm55-T_CYAs7)\n\nOpenAI just dropped API access for their new image generation — and it changes everything. In this quick walkthrough, I show you exactly how to integrate it with n8n using an HTTP request node. Learn how to send prompts, convert base64 to binary, and automate image handling. This is a big one. Don’t miss it.\n\n🔗 Official API Overview: https://openai.com/index/image-generation-api/\n🔗 API Reference – Create Image: https://platform.openai.com/docs/api-reference/images/create\n\n### *New:  Make.com scenario here: https://drive.google.com/file/d/1Uz-mA0LnUZ_tnUWBR2AAlVxs3LBlGKfk/view?usp=sharing\n"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"c7fef832-b7ba-4cb1-ad36-7a82f81a7f90","connections":{"Set Variables":{"main":[[{"node":"OpenAI - Generate Image","type":"main","index":0}]]},"Separate Image Outputs":{"main":[[{"node":"Convert to File","type":"main","index":0}]]},"OpenAI - Generate Image":{"main":[[{"node":"Separate Image Outputs","type":"main","index":0}]]},"When clicking ‘Test workflow’":{"main":[[{"node":"Set Variables","type":"main","index":0}]]}}}


name: Automated Instagram Comment Replies using Gemini AI with Context-Aware Responses
author_name: Luciano Gutierrez
author_username: koresoluciones
categories: []
created_at: 2025-04-25T18:37:26.955Z
updated_at: 2025-04-25T18:37:26.955Z
url: https://n8n.io/workflows/3713
scraped_at: 2025-07-06 21:16:30
description:
  Instagram Auto-Comment Responder with AI Agent Integration

  Version: 1.1.0 ‧ n8n Version: 1.88.0+ ‧ License: MIT

  A fully automated workflow for managing and responding to Instagram comments using AI agents. Designed to improve engagement and save time, this system listens for new Instagram comments, verifies and filters them, fetches relevant post data, processes valid messages with a natural language AI, and posts context-aware replies directly on the original post.

  Key Features

  💬 AI-Driven Engagement: Intelligent responses to comments via a GPT-powered agent.
  ✅ Webhook Verification: Handles Instagram webhook handshake to ensure secure integration.
  📦 Data Extraction: Maps incoming payload fields (user ID, username, message text, media ID) for processing.
  🚫 Self-Comment Filtering: Automatically skips comments made by the account owner to prevent loops.
  📡 Post Data Retrieval: Fetches the media’s id and caption from the Graph API (v22.0) before generating a reply.
  🧠 Natural Language Processing: Uses a custom system prompt to maintain brand tone and context.
  🔁 Automated Replies: Posts the AI-generated message back to the comment thread using Instagram’s API.
  🧩 Modular Architecture: Clear separation of steps via sticky notes and dedicated HTTP Request and Agent nodes.

  Use Cases

  Social Media Automation**: Keep followers engaged 24/7 with instant, relevant replies.
  Community Building**: Maintain a consistent voice and tone across all interactions.
  Brand Reputation Management**: Ensure no valid comment goes unanswered.
  AI Customer Support**: Triage simple questions and direct followers to resources or support.

  Technical Implementation

  Webhook Verification  
     Node: Webhook + Respond to Webhook  
     Echoes hub.challenge to confirm subscription and secure incoming events.

  Data Extraction  
     Node: Set  
     Maps payload fields into structured variables: conta.id, usuario.id, usuario.name, usuario.message.id, usuario.message.text, usuario.media.id, endpoint.

  User Validation  
     Node: Filter  
     Skips processing if conta.id equals usuario.id (self-comments).

  Post Data Retrieval  
     Node: HTTP Request (Get post data)  
     GET https://graph.instagram.com/v22.0/{{ $json.usuario.media.id }}?fields=id,caption&access_token={{ credentials }}  
     Captures the media’s caption for richer context in replies.

  AI Response Generation  
     Nodes: AI Agent + OpenRouter Chat Model  
     Uses a detailed system prompt with:
       Profile persona (expert in AI & automations, friendly tone).  
       Input data (username, comment text, post caption).  
       Filtering logic (spam, praise, questions, vague comments).  
     Returns either the reply text or [IGNORE] for irrelevant content.

  Posting the Reply  
     Node: HTTP Request (Post comment)  
     POST {{ $json.endpoint }}/{{ $json.usuario.message.id }}/replies with message={{ $json.output }}  
     Sends the AI answer back under the original comment.

  Instructions for Setup

  Import Workflow  
     In n8n &gt; Workflows &gt; Import from File, upload the provided .json template.

  Configure Credentials  
     Instagram Graph API (Header Auth or FacebookGraphApi) with instagram_basic, instagram_manage_comments scopes.  
     OpenRouter/OpenAI API key for AI agent.

  Customize System Prompt  
     Edit the AI Agent’s prompt to adjust brand tone, language (Brazilian Portuguese), length, or emoji usage.

  Test & Activate  
     Publish a test comment on an Instagram post.  
     Verify each node’s execution, ensuring the webhook, filter, data extraction, HTTP requests, and AI Agent respond as expected.

  Extend & Monitor  
     Add sentiment analysis or lead capture nodes as needed.  
     Monitor execution logs for errors or rate-limit events.

  Tags

  Social Media • Instagram Automation • Webhook Verification • AI Agent • HTTP Request • Auto Reply • Community Management

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

workflow_json:
  {"id":"4rXRDurF4mQKrHyB","meta":{"instanceId":"6d46e25379ef430a7067964d1096b885c773564549240cb3ad4c087f6cf94bd3","templateCredsSetupCompleted":true},"name":"comentarios automaticos","tags":[],"nodes":[{"id":"5c5322a4-10cf-43a1-8286-101c96d8c356","name":"Webhook","type":"n8n-nodes-base.webhook","position":[40,100],"webhookId":"ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","parameters":{"path":"ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","options":{},"responseMode":"responseNode"},"typeVersion":2},{"id":"c281b25f-4f5a-46a3-b2ca-c9fba1cf98e1","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-980,0],"parameters":{"width":1440,"height":320,"content":"# Webhook Verification\nDescription:\nHandles the initial verification handshake with Instagram's Webhook API.\nInstructions:\n\nEnsure the hub.verify_token matches the token configured in your Instagram App settings.\n\nThe response should echo the hub.challenge parameter to confirm the webhook setup.​\n\n"},"typeVersion":1},{"id":"f890a4d2-f897-4103-a52f-48fa3555f9a6","name":"Respond to Webhook","type":"n8n-nodes-base.respondToWebhook","position":[260,100],"parameters":{"options":{},"respondWith":"text","responseBody":"={{ $json.query['hub.challenge'] }}"},"typeVersion":1.1},{"id":"4afb4f9b-7f0f-41b8-afd0-d5c134a6a622","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[140,1200],"parameters":{"text":"=### CONTEXTO E PERSONA ###\nVocê é um assistente de IA especialista, responsável por gerenciar os comentários de um perfil no Instagram focado em Inteligência Artificial e Automações. O objetivo do perfil é educar e engajar a comunidade sobre esses temas. Seu tom deve ser amigável, acessível, mas também demonstrar conhecimento e profissionalismo. Responda sempre em português brasileiro.\n\n### DADOS DE ENTRADA ###\n- Nome de Usuário: {{ $('data').item.json.usuario.name }}\n- Texto do Comentário:{{ $('data').item.json.usuario.message.text }}\n- Contexto da Publicacao\n\n### TAREFA ###\nAnalise o comentário fornecido e gere uma resposta apropriada, seguindo estas diretrizes:\n\n1.  **Análise e Filtragem:**\n    * **Identifique a Intenção:** É uma pergunta técnica? Uma dúvida simples? Um elogio? Uma crítica construtiva? Um pedido de ajuda? Spam? Conteúdo irrelevante?\n    * **Relevância:** O comentário está relacionado a IA, automação ou ao conteúdo do perfil?\n\n2.  **Geração da Resposta:**\n    * **Personalização:** Comece a resposta mencionando o nome de usuário (ex: \"Olá @{{ $('data').item.json.usuario.name }},\").\n    * **Perguntas Relevantes:** Se for uma pergunta sobre IA/automação que você pode responder, forneça uma resposta clara e útil. Se for muito complexa, agradeça a pergunta e sugira buscar um post específico no perfil, ou diga que o tema é interessante para um futuro conteúdo.\n    * **Elogios:** Agradeça sinceramente o elogio e, se possível, conecte-o a um aspecto do perfil ou do conteúdo sobre IA/automação.\n    * **Críticas Construtivas:** Agradeça o feedback, mostre que ele foi considerado e responda polidamente.\n    * **Pedidos de Ajuda Específicos (não relacionados a conteúdo):** Se for um pedido de suporte técnico não relacionado ao tema central, direcione para o canal adequado ou explique educadamente que não pode ajudar com isso ali.\n    * **Comentários Vagos ou de Engajamento Simples (ex: \"Legal!\", \"👍\"):** Responda de forma curta e amigável, talvez com um emoji relevante ou incentivando a continuar acompanhando.\n    * **Spam ou Irrelevante:** Se o comentário for claramente spam, promocional não solicitado, ofensivo ou totalmente fora do tópico de IA/automação, NÃO gere uma resposta. Neste caso, retorne APENAS a palavra `[IGNORE]`.\n\n3.  **Tom e Estilo:**\n    * Mantenha o tom amigável, útil e alinhado com um perfil de tecnologia/educação.\n    * Evite respostas genéricas demais quando uma específica for possível.\n    * Mantenha as respostas relativamente concisas, adequadas para comentários do Instagram.\n\n### SAÍDA ESPERADA ###\nRetorne APENAS o texto da resposta a ser publicada no Instagram. Se o comentário for classificado como spam/irrelevante conforme a regra 2.7, retorne APENAS a palavra `[IGNORE]`. Não inclua nenhuma outra explicação ou texto adicional fora da resposta ou da palavra `[IGNORE]`.","options":{},"promptType":"define"},"typeVersion":1.8},{"id":"e56a220b-f4aa-4505-9157-31980ccb547b","name":"OpenRouter Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","position":[60,1340],"parameters":{"model":"google/gemini-2.0-flash-exp:free","options":{}},"credentials":{"openRouterApi":{"id":"eGPA8rbskZCfFPBn","name":"OpenRouter account"}},"typeVersion":1},{"id":"9f318cf1-d99f-482d-a6d4-03ec4f603c05","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-980,380],"parameters":{"color":5,"width":1440,"height":320,"content":"# Data Extraction\nDescription:\nExtracts relevant data from the incoming webhook payload.\nInstructions:\n\nVerify that all necessary fields (e.g., entry.id, from.id, from.username, message.id, message.text, media.id) are correctly mapped.\n\nThis data will be used in subsequent steps for processing and responding.\n"},"typeVersion":1},{"id":"a413c839-fa19-44b9-ae33-2638dd45436e","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-980,780],"parameters":{"color":6,"width":1440,"height":320,"content":"# User Validation\nDescription:\nChecks if the comment originates from a user other than the account owner.\nInstructions:\n\nCompare conta.id with usuario.id.\n\nProceed only if they differ, indicating the comment is from another user."},"typeVersion":1},{"id":"b19d4891-5f7e-478b-9458-464af1fd409c","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-980,1160],"parameters":{"color":2,"width":1440,"height":320,"content":"# AI Response Generation\nDescription:\nUtilizes an AI agent to generate a context-aware response to the user's comment.\nInstructions:\n\nEnsure the AI model is properly configured and has access to the necessary input data.\n\nThe prompt should guide the AI to produce responses that are friendly, informative, and aligned with the profile's focus on AI and automation."},"typeVersion":1},{"id":"1f8b05ee-0380-4dc7-8671-f0ae87a7d08f","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-980,1560],"parameters":{"color":3,"width":1440,"height":320,"content":"# Sending the Response\nDescription:\nSends the AI-generated reply back to the user via Instagram's API.\nInstructions:\n\nConfirm that the HTTP request is correctly formatted with the appropriate endpoint and authentication headers.\n\nHandle any potential errors or exceptions that may arise during the API call."},"typeVersion":1},{"id":"ff54a7c0-40b9-4ad8-a3de-47a8a20cd3e1","name":"Get post data","type":"n8n-nodes-base.httpRequest","position":[-80,880],"parameters":{"url":"=https://graph.instagram.com/v22.0/{{ $json.usuario.media.id }}?fields=id,caption","options":{},"authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"6H4syU3wzaoNBy2k","name":"Header Auth account"},"facebookGraphApi":{"id":"z7CU24qbafckHljY","name":"Facebook Graph account"}},"typeVersion":4.2},{"id":"d7a66f78-83f2-4173-8602-c34210364149","name":"get_new_comments","type":"n8n-nodes-base.webhook","position":[40,480],"webhookId":"ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","parameters":{"path":"ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","options":{},"httpMethod":"POST"},"typeVersion":2},{"id":"0924d70a-45a2-49c9-9459-eb6e7261005e","name":"data","type":"n8n-nodes-base.set","position":[280,480],"parameters":{"options":{},"assignments":{"assignments":[{"id":"1a3c5a2e-115d-4072-9d27-9baa47e84d6f","name":"endpoint","type":"string","value":"https://graph.instagram.com/v22.0"},{"id":"ae83344d-abe5-43d6-991f-e757965e4557","name":"conta.id","type":"string","value":"={{ $json.body.entry[0].id }}"},{"id":"d18887fa-b882-4d69-a1c0-d161291fe5fb","name":"usuario.id","type":"string","value":"={{ $json.body.entry[0].changes[0].value.from.id }}"},{"id":"000f2d0e-6fbf-4e58-ae9c-cac4a3c54b33","name":"usuario.name","type":"string","value":"={{ $json.body.entry[0].changes[0].value.from.username }}"},{"id":"d6fa2b24-abbe-48f7-96ff-2fc69f17b61b","name":"usuario.message.id","type":"string","value":"={{ $json.body.entry[0].changes[0].value.id }}"},{"id":"605e9c4c-f2fc-49eb-8639-573c60ef33bb","name":"usuario.message.text","type":"string","value":"={{ $json.body.entry[0].changes[0].value.text }}"},{"id":"198afc5d-3fd1-4d9d-aa5a-8baf75f06d29","name":"usuario.media.id","type":"string","value":"={{ $json.body.entry[0].changes[0].value.media.id }}"}]}},"typeVersion":3.4},{"id":"2836ec33-b19f-4875-bfeb-08d9f9feae49","name":"its me?","type":"n8n-nodes-base.filter","position":[200,880],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"54c0a2d1-f812-4d6a-b50b-c272cfbba772","operator":{"type":"string","operation":"notEquals"},"leftValue":"={{ $('data').item.json.conta.id }}","rightValue":"={{ $('data').item.json.usuario.id }}"}]}},"typeVersion":2.2},{"id":"fdf8ff5e-9c17-43f3-a747-79228ca68e03","name":"Post comment","type":"n8n-nodes-base.httpRequest","position":[260,1660],"parameters":{"url":"={{ $('data').item.json.endpoint }}/{{ $('data').item.json.usuario.message.id }}/replies","method":"POST","options":{},"sendBody":true,"authentication":"genericCredentialType","bodyParameters":{"parameters":[{"name":"message","value":"={{ $json.output }}"}]},"genericAuthType":"httpHeaderAuth"},"credentials":{"httpHeaderAuth":{"id":"6H4syU3wzaoNBy2k","name":"Header Auth account"}},"typeVersion":4.2}],"active":true,"pinData":{"get_new_comments":[{"json":{"body":{"entry":[{"id":"17841458749050638","time":1745696027,"changes":[{"field":"comments","value":{"id":"17992882022637707","from":{"id":"1797582914152092","username":"luchiogutierrez"},"text":"😍","media":{"id":"17969449379894182","media_product_type":"FEED"}}}]}],"object":"instagram"},"query":{},"params":{},"headers":{"host":"host.docker.internal:5678","accept":"*/*","x-scheme":"https","forwarded":"by=_exposr;for=173.252.95.16;host=engaging-seahorse-19.rshare.io;proto=https","x-real-ip":"173.252.95.16","connection":"keep-alive","exposr-via":"77940acbe1755f6fca18880bd02e462ee55d0cde,0374ae5bede6d70d299155239dbb7e045533e1f4","user-agent":"Webhooks/1.0 (https://fb.me/webhooks)","content-type":"application/json","x-request-id":"b0c4e9d6dd2baa18bab7eab283ad4788","content-length":"316","x-forwarded-for":"173.252.95.16","x-hub-signature":"sha1=b3d396ac784244a020268dd9599e708b21688b75","x-forwarded-host":"engaging-seahorse-19.rshare.io","x-forwarded-port":"443","x-forwarded-proto":"https","x-forwarded-scheme":"https","x-hub-signature-256":"sha256=40e1e91b67c7fa82afca10c81ff4b1200d9561384ee5ba690bf9bc22814cb09b"},"webhookUrl":"https://engaging-seahorse-19.rshare.io/webhook/ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","executionMode":"production"}}],"Respond to Webhook":[{"json":{"body":{},"query":{"hub.mode":"subscribe","hub.challenge":"219585499","hub.verify_token":"teste"},"params":{},"headers":{"host":"host.docker.internal:5678","accept":"*/*","x-scheme":"https","forwarded":"by=_exposr;for=173.252.107.25;host=actual-beagle-88.rshare.io;proto=https","x-real-ip":"173.252.107.25","connection":"keep-alive","exposr-via":"b37bd560bd173ee1195fceaef48a1468e8fa83f0,f06a3ed204e476a5915fc6fff7228b77c1c9e1d3","user-agent":"facebookplatform/1.0 (+http://developers.facebook.com)","x-request-id":"037b358cf28db9e3bffdf52703fd9069","accept-encoding":"deflate, gzip","x-forwarded-for":"173.252.107.25","x-forwarded-host":"actual-beagle-88.rshare.io","x-forwarded-port":"443","x-forwarded-proto":"https","x-forwarded-scheme":"https"},"webhookUrl":"http://localhost:5678/webhook-test/ea7d37ac-9e82-40d7-bbb3-e9b7ce180fc9","executionMode":"test"}}]},"settings":{"executionOrder":"v1"},"versionId":"2a39918c-36c8-486e-acb3-3420a4a8b8b1","connections":{"data":{"main":[[{"node":"Get post data","type":"main","index":0}]]},"Webhook":{"main":[[{"node":"Respond to Webhook","type":"main","index":0}]]},"its me?":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"AI Agent":{"main":[[{"node":"Post comment","type":"main","index":0}]]},"Get post data":{"main":[[{"node":"its me?","type":"main","index":0}]]},"get_new_comments":{"main":[[{"node":"data","type":"main","index":0}]]},"OpenRouter Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]}}}


name: Extract & Classify Invoices & Receipts with Gmail, OpenAI and Google Drive
author_name: Tom
author_username: devpeer-tom
categories: []
created_at: 2025-04-26T15:03:19.387Z
updated_at: 2025-04-26T15:03:19.387Z
url: https://n8n.io/workflows/3719
scraped_at: 2025-07-06 21:16:30
description:
  Who is it for?
  Anyone who wants to automatically aggregate their invoices or receipts. Main beneficiaries: small business owners and freelancers.

  How it works
  Creates a folder in Google Drive for uploading invoices and receipts. Responds (Webhook response) with URL to the created folder.
  Gets all emails with attachments from a Gmail mailbox.
  (Optional) Filters emails, e.g. exclude emails sent to specific address.
  Filters only PDF attachments.
  Classifies all PDF attachment contents with an AI model (is it a receipt or an invoice?).
  Uploads receipts and invoices to the created Google Drive folder and optionally sends an email with the attachments to, e.g., your accountant.

  Pre-conditions/Requirements
  Gmail and Google Drive accounts
  A Google Cloud OAuth 2.0 Client ID or a service account with Google Drive and Gmail APIs enabled
  OpenAI API account and API key

  Set up steps
  Provide credentials for the nodes: Gmail, Google Drive, OpenAI.
  Configure parameters in the "Configure" node. Most importantly:
      "sendInvoicesTo" for the email address where invoices/receipts should be sent.
  It uses a Webhook node trigger. It expects a body with a schema such as:
  {
    "name": "getInvoicesAndReceiptsFromEmails",
    "description": "Finds and uploads to Google Drive all receipts and invoices from emails within a specified date range.",
    "parameters": {
      "type": "object",
      "properties": {
        "startDate": {
          "type": "string",
          "format": "date-time",
          "description": "The start date of the range to search for emails. Must be in ISO 8601 format."
        },
        "endDate": {
          "type": "string",
          "format": "date-time",
          "description": "The end date of the range to search for emails. Must be in ISO 8601 format."
        },
        "sendEmail": {
          "type": "boolean",
          "description": "Indicates whether to send an email with all receipts and invoices after processing. Must be true or false."
        }
      },
      "required": [
        "startDate",
        "endDate"
      ]
    }
  }
  Example body:
  {
    "startDate": "2025-03-01T00:00:00Z",
    "endDate": "2025-04-01T00:00:00Z",
    "sendEmail": true
  }
  How to use with AI chat

  You can trigger the workflow with an AI chat that supports tool use, such as BrowseWiz. For setup instructions, read the blog post.

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

workflow_json:
  {"meta":{"instanceId":"d1b60f1865ef6504ee3af5be4ef9a7387762b4132615a52de808456d52e8d336","templateCredsSetupCompleted":true},"nodes":[{"id":"c84f3a9a-66b3-4a09-b06a-9b399ea574b8","name":"OpenAI","type":"@n8n/n8n-nodes-langchain.openAi","position":[420,-240],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4.1-mini","cachedResultName":"GPT-4.1-MINI"},"options":{},"messages":{"values":[{"content":"=Does this PDF file look like a {{ $(\"Configure\").first().json[\"Match on\"] }}? Return \"true\" if it is a {{ $(\"Configure\").first().json[\"Match on\"] }} and \"false\" if not. Only reply with lowercase letters \"true\" or \"false\".\n\nThis is the PDF filename:\n```\n{{ $binary.data.fileName }}\n```\n\nThis is the PDF text content:\n```\n{{ $json.text }}\n```"}]}},"credentials":{"openAiApi":{"id":"prYAbsQvWl1pPbdL","name":"OpenAi account"}},"typeVersion":1.8},{"id":"ea1fbc5b-1859-4d65-8401-30baa95fcc52","name":"Configure","type":"n8n-nodes-base.set","position":[-700,0],"parameters":{"values":{"number":[{"name":"maxTokenSize","value":8000},{"name":"replyTokenSize","value":50}],"string":[{"name":"Match on","value":"receipt or invoice that can be considered a software engineering business cost"},{"name":"Google Drive folder to upload matched PDFs","value":"https://drive.google.com/drive/folders/[put_folder_id_here]"},{"name":"sendInvoicesTo"}],"boolean":[{"name":"sendEmail","value":"={{ $('Webhook').item.json.body.sendEmail === \"true\" }}"}]},"options":{}},"typeVersion":1},{"id":"3ee63612-c1e7-40e6-a38f-f77f5ee3efa4","name":"Iterate over email attachments","type":"n8n-nodes-base.code","position":[-200,0],"parameters":{"jsCode":"// https://community.n8n.io/t/iterating-over-email-attachments/13588/3\nlet results = [];\n\nfor (const item of $input.all()) {\n  console.log(item);\n  for (const key of Object.keys(item.binary)) {\n    results.push({\n        json: {},\n        binary: {\n            data: item.binary[key],\n        }\n    });\n  }\n}\n\nreturn results;"},"typeVersion":1},{"id":"3e638471-c1c5-4bab-aa2a-12a1777225ec","name":"Not a PDF","type":"n8n-nodes-base.noOp","position":[120,80],"parameters":{},"typeVersion":1},{"id":"b5af902b-2d59-49ee-b6d8-e387c59b89fd","name":"Is text within token limit?","type":"n8n-nodes-base.if","position":[300,-100],"parameters":{"conditions":{"boolean":[{"value1":"={{ $json.text.length() / 4 <= $('Configure').first().json.maxTokenSize - $('Configure').first().json.replyTokenSize }}","value2":true}]}},"typeVersion":1},{"id":"a0a8895c-ef8b-44e7-9294-1bcf629d0973","name":"Merge","type":"n8n-nodes-base.merge","position":[720,-120],"parameters":{"mode":"combine","options":{"clashHandling":{"values":{"resolveClash":"preferInput1"}}},"combinationMode":"mergeByPosition"},"typeVersion":2},{"id":"7565118a-6d44-4583-a19f-cb4177378d33","name":"Is matched","type":"n8n-nodes-base.if","position":[880,-120],"parameters":{"conditions":{"string":[{"value1":"={{ $json.message.content }}","value2":"true"}]}},"typeVersion":1},{"id":"074ffb7a-f83e-44b8-84fe-7b85f7245bb0","name":"Upload file to folder","type":"n8n-nodes-base.googleDrive","position":[1100,-140],"parameters":{"name":"={{ $binary.data.fileName }}","options":{},"parents":["={{ $('Create folder').first().json.id }}"],"binaryData":true},"credentials":{"googleDriveOAuth2Api":{"id":"xXHySx4T77sDdTqY","name":"Google Drive account"}},"typeVersion":2},{"id":"7681eb62-ba86-4c89-9b88-3ce6fc438bd4","name":"Webhook","type":"n8n-nodes-base.webhook","position":[-1080,0],"webhookId":"cded3af3-31df-47c2-a826-ff84eb4a41df","parameters":{"path":"cded3af3-31df-47c2-a826-ff84eb4a41df","options":{},"httpMethod":"POST","responseMode":"responseNode","authentication":"headerAuth"},"credentials":{"httpHeaderAuth":{"id":"90SsOYPPIe3Qv5Rq","name":"Header Auth account"}},"typeVersion":2},{"id":"aab3d940-55c2-40d3-917a-83412d4e378d","name":"Respond to Webhook","type":"n8n-nodes-base.respondToWebhook","position":[-720,-240],"parameters":{"options":{"responseCode":202},"respondWith":"json","responseBody":"={\n  \"status\": \"Accepted\",\n  \"driveFolderUrl\": \"{{ \"https://drive.google.com/drive/folders/\" + $json.id }}\"\n}"},"typeVersion":1.1},{"id":"29a4122f-0112-4157-a50d-0a6cf83ab7fd","name":"Create folder","type":"n8n-nodes-base.googleDrive","position":[-920,0],"parameters":{"name":"={{ \"invoices_\" + $json.body.startDate.split('T')[0] }}","driveId":{"__rl":true,"mode":"list","value":"My Drive"},"options":{},"folderId":{"__rl":true,"mode":"list","value":"root","cachedResultName":"/ (Root folder)"},"resource":"folder"},"credentials":{"googleDriveOAuth2Api":{"id":"xXHySx4T77sDdTqY","name":"Google Drive account"}},"typeVersion":3},{"id":"df86428f-7e63-4fd9-944c-f48af72af495","name":"Aggregate attachments","type":"n8n-nodes-base.code","position":[1200,-340],"parameters":{"jsCode":"// \"items\" is the array coming from the previous node (14 items)\nconst merged = { json: {}, binary: {} };\n\nfor (const item of $input.all()) {\n  const data = {\n    [item.binary.data.fileName]: item.binary.data\n  };\n  Object.assign(merged.binary, data); // copy every file property\n}\n\nreturn [merged];     // one single item goes out"},"typeVersion":2},{"id":"72a21bfa-6e3b-421a-a4ca-dea9e09a5b0b","name":"Send email with invoices?","type":"n8n-nodes-base.if","position":[1000,-320],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"63caf3d8-39bd-4300-aa7e-8c0ecfc87576","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{ $('Configure').first().json.sendEmail }}","rightValue":""}]}},"typeVersion":2.2},{"id":"bb038635-eb69-447b-a85b-e9c3caebfe3a","name":"Send to my accountant","type":"n8n-nodes-base.gmail","position":[1360,-280],"webhookId":"3ea4dac1-58fe-4d0e-811b-065ecaef77df","parameters":{"sendTo":"test@example.com","message":"Hello, here are my invoices and receipts.","options":{"attachmentsUi":{"attachmentsBinary":[{"property":"={{ Object.keys($binary).join(',') }}"}]}},"subject":"={{ \n  (() => {\n    const startDate = $node['Webhook'].json.body.startDate.split('T')[0];\n    const endDate = $node['Webhook'].json.body.endDate.split('T')[0];\n    return `Dokumenty kosztowe za okres od ${startDate} do ${endDate}`;\n  })() \n}}","emailType":"text"},"credentials":{"gmailOAuth2":{"id":"PPgHF95PrpAMBlbG","name":"Gmail account"}},"typeVersion":2.1},{"id":"7b2e5c6c-0a95-4347-97a9-c9ffbc0e3af2","name":"Get emails with attachments","type":"n8n-nodes-base.gmail","position":[-500,0],"webhookId":"6e2ca9f7-6d22-4d94-86bc-8a299bc8e752","parameters":{"simple":false,"filters":{"q":"has:attachment","sender":"","receivedAfter":"={{ $('Webhook').item.json.body.startDate }}","receivedBefore":"={{ $('Webhook').item.json.body.endDate }}"},"options":{"downloadAttachments":true,"dataPropertyAttachmentsPrefixName":"attachment_"},"operation":"getAll","returnAll":true},"credentials":{"gmailOAuth2":{"id":"PPgHF95PrpAMBlbG","name":"Gmail account"}},"typeVersion":2.1},{"id":"6d5b2c1b-657d-44bf-980d-fd428fd8d832","name":"Read PDF email attachments","type":"n8n-nodes-base.readPDF","onError":"continueErrorOutput","position":[120,-80],"parameters":{},"notesInFlow":false,"typeVersion":1},{"id":"3166f45c-306f-483a-b2c6-6768abc916a0","name":"Is attachment a PDF?","type":"n8n-nodes-base.if","position":[-40,0],"parameters":{"conditions":{"string":[{"value1":"={{ $binary.data.fileExtension }}","value2":"pdf"}]}},"typeVersion":1},{"id":"866b286a-7b9b-4506-aa6b-d2049b249991","name":"Optional filter for emails","type":"n8n-nodes-base.filter","position":[-360,0],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"687c4cd0-ada5-4dc1-8707-1a9c3b551251","operator":{"type":"string","operation":"notEquals"},"leftValue":"={{ $json.to.value[0].address }}","rightValue":""}]}},"typeVersion":2.2},{"id":"56133dba-bc93-4f65-be42-995164a45c03","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-1600,-340],"parameters":{"width":440,"height":880,"content":"## Gmail PDF Invoice/Receipt Classifier & Google Drive Uploader (via n8n & OpenAI)\n\n_**DISCLAIMER**: AI classification isn't perfect. Always double-check that the correct documents were identified and uploaded._\n\nThis n8n workflow, triggered via a webhook, scans your Gmail for emails within a specified date range, extracts PDF attachments, and uses OpenAI to determine if each PDF matches a defined category (defaulting to \"receipt or invoice\"). Matched PDFs are then uploaded to a uniquely named Google Drive folder based on the date range. You can customize the classification term (e.g., change \"receipt or invoice\" to \"contract\") and optionally have the workflow email the collected PDFs to a specified address.\n\n### How it works\n1.  Triggers via a `Webhook` receiving a start date, end date, and an optional flag to send an email.\n2.  Creates a dated folder in `Google Drive` (e.g., `invoices_YYYY-MM-DD_YYYY-MM-DD`).\n3.  Fetches emails with attachments from `Gmail` within the specified date range.\n4.  Iterates through each attachment, filtering specifically for `PDF` files.\n5.  Extracts text from each PDF (skipping if the text exceeds token limits set in the `Configure` node).\n6.  Uses the `OpenAI` node to ask if the PDF content and filename look like the item defined in the `Configure` node's \"Match on\" field (e.g., \"receipt or invoice\").\n7.  If OpenAI responds with \"true\", the original `PDF` file is uploaded to the `Google Drive` folder created in step 2.\n8.  If the initial webhook request included the flag to send an email, it aggregates all successfully matched PDFs and sends them via `Gmail` to the address specified in the `Configure` node.\n\nWorkflow written by [Tom](https://browsewiz.com)\n"},"typeVersion":1},{"id":"aa5d8126-e2ec-4476-886d-c46379f1c6e2","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-780,-40],"parameters":{"width":260,"height":1000,"content":"## Parameters\n\n\n\n\n\n\n\n\n\n* **`maxTokenSize`** (Number)\n    *   **Limits PDF text length** (estimated input tokens) sent to OpenAI for classification. Prevents errors/high costs on long documents.\n    *   *Default: 8000*\n\n*   **`replyTokenSize`** (Number)\n    *   **Reserves tokens for OpenAI's reply** ('true'/'false'). Ensures total tokens stay within limits.\n    *   *Default: 50*\n\n*   **`Match on`** (String)\n    *   **The keyword/phrase OpenAI uses** to identify the desired document type (e.g., \"receipt or invoice\", \"contract\"). Defines what you're searching for.\n    *   *Default: \"receipt or invoice\"*\n\n*   **`sendInvoicesTo`** (String)\n    *   **Recipient email address** for the final collection of matched PDFs. Used only if `sendEmail` is true.\n    *   *Example: \"accounting@example.com\"*\n\n*   **`sendEmail`** (Boolean)\n    *   **Turns the final email step on (`true`) or off (`false`)**. Set via the initial webhook trigger. If false, files are only uploaded to Drive.\n    *   *Example: `true` or `false`*"},"typeVersion":1}],"pinData":{},"connections":{"Merge":{"main":[[{"node":"Is matched","type":"main","index":0}]]},"OpenAI":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Webhook":{"main":[[{"node":"Create folder","type":"main","index":0}]]},"Configure":{"main":[[{"node":"Get emails with attachments","type":"main","index":0}]]},"Is matched":{"main":[[{"node":"Upload file to folder","type":"main","index":0},{"node":"Send email with invoices?","type":"main","index":0}]]},"Create folder":{"main":[[{"node":"Configure","type":"main","index":0},{"node":"Respond to Webhook","type":"main","index":0}]]},"Is attachment a PDF?":{"main":[[{"node":"Read PDF email attachments","type":"main","index":0}],[{"node":"Not a PDF","type":"main","index":0}]]},"Aggregate attachments":{"main":[[{"node":"Send to my accountant","type":"main","index":0}]]},"Send to my accountant":{"main":[[]]},"Upload file to folder":{"main":[[]]},"Send email with invoices?":{"main":[[{"node":"Aggregate attachments","type":"main","index":0}]]},"Optional filter for emails":{"main":[[{"node":"Iterate over email attachments","type":"main","index":0}]]},"Read PDF email attachments":{"main":[[{"node":"Is text within token limit?","type":"main","index":0}]]},"Get emails with attachments":{"main":[[{"node":"Optional filter for emails","type":"main","index":0}]]},"Is text within token limit?":{"main":[[{"node":"OpenAI","type":"main","index":0},{"node":"Merge","type":"main","index":1}],[]]},"Iterate over email attachments":{"main":[[{"node":"Is attachment a PDF?","type":"main","index":0}]]}}}


name: Automated SEO Performance Collection from Google Search Console to NocoDB
author_name: Martech Mafia
author_username: martechmafia
nodes_used: ["n8n-nodes-base.httpRequest","n8n-nodes-base.nocoDb","n8n-nodes-base.code"]
categories: []
created_at: 2025-04-26T17:15:33.687Z
updated_at: 2025-04-26T17:15:33.687Z
url: https://n8n.io/workflows/3721
scraped_at: 2025-07-06 21:16:30
description:
  Problem

  Monitoring SEO performance from Google Search Console (GSC) manually is repetitive and prone to human error. For marketers or analysts managing multiple domains, checking reports manually and copying data into spreadsheets or databases is time-consuming. There is a strong need for an automated solution that collects, stores, and updates SEO metrics regularly for easier analysis and dashboarding.

  Solution

  This workflow automatically pulls performance metrics from Google Search Console — including queries, pages, CTR, impressions, positions, and devices — and stores them in a structured format inside a NocoDB table. It’s ideal for SEO specialists, marketing teams, or data analysts who need to automate SEO reporting and centralize data for analytics or dashboards (like Superset or Metabase).

  Setup Instructions

  Authorize your Google Search Console account  
     Connect via OAuth2 (requires GSC API access).

  Create a NocoDB table  
     Define fields to match GSC response:
     query (text)
     page (URL)
     device (text)
     clicks (number)
     impressions (number)
     ctr (percentage)
     position (number)

  Add credentials in n8n  
     Use credential nodes for both:
     Google OAuth2
     NocoDB API Token

  Customize schedule trigger  
     Set the frequency (e.g., weekly) and adjust the domain/date range as needed.

  Generalize domains  
     Replace specific domains like martechmafia.net with your-domain.com before submission.

  NocoDB Table Structure

  The NocoDB table must match the fields coming from GSC's Search Analytics API. Here's a sample schema:
  {
    "query": "string",
    "page": "string",
    "device": "string",
    "clicks": "number",
    "impressions": "number",
    "ctr": "number",
    "position": "number"
  }

workflow_json:
  {"meta":{"instanceId":"9eba46583e664f4e60eb70b8e083a53d02c91877555abd09dad5884237b9d117","templateCredsSetupCompleted":true},"nodes":[{"id":"29f876d8-6376-4c30-b090-d98e0b19efb7","name":"NocoDB1","type":"n8n-nodes-base.nocoDb","position":[1060,160],"parameters":{"table":"muc0kmjqos1invc","operation":"create","projectId":"p97b9jham4uh16u","dataToSend":"autoMapInputData","workspaceId":"wko8iu8c","authentication":"nocoDbApiToken"},"credentials":{"nocoDbApiToken":{"id":"6KFDjDVwitwT3Icj","name":"NocoDB Token account"}},"typeVersion":3},{"id":"adbf93b4-0174-41b0-a4b3-b38407df2d1e","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[0,0],"parameters":{"color":4,"width":260.6598393933048,"height":313.71656632131885,"content":"📌 Node: Schedule Trigger\nRuns the automation on a fixed schedule (e.g., daily). Used to trigger SEO data collection from Google Search Console automatically."},"typeVersion":1},{"id":"f4c79269-74dd-4918-b7a8-bb5b22b8af57","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[320,0],"parameters":{"color":4,"width":260.6598393933048,"height":313.71656632131885,"content":"📌  Node: HTTP Request\nMakes a POST request to GSC API (Search Analytics endpoint). Authenticated with OAuth2. Retrieves performance data like clicks, impressions, CTR."},"typeVersion":1},{"id":"536e2048-dcf5-4309-90d6-62de2a26cc8f","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[640,0],"parameters":{"color":4,"width":260.6598393933048,"height":313.71656632131885,"content":"📌 Node: Code\nParses and restructures the raw GSC API response. Extracts fields like query, page, date, device, clicks, CTR, and position for database insertion.\n"},"typeVersion":1},{"id":"9f1cda9a-97c5-499d-836a-a7b69a4af6a5","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[980,0],"parameters":{"color":4,"width":260.6598393933048,"height":313.71656632131885,"content":"\n📌 Node: NocoDB1 (create: row)\nPushes parsed SEO data into NocoDB (`gsc_data` table). This builds a structured, queryable database of daily SEO performance.\n"},"typeVersion":1},{"id":"b56613ed-ffb0-4082-90ce-b748ee58abfc","name":"Schedule Trigger1","type":"n8n-nodes-base.scheduleTrigger","position":[80,160],"parameters":{"rule":{"interval":[{"field":"weeks","triggerAtDay":[1],"triggerAtHour":1}]}},"typeVersion":1.2},{"id":"9ebb1a98-4913-496f-9f97-b57886d01bc7","name":"HTTP Request1","type":"n8n-nodes-base.httpRequest","position":[400,160],"parameters":{"url":"https://searchconsole.googleapis.com/webmasters/v3/sites/sc-domain:martechmafia.net/searchAnalytics/query","method":"POST","options":{},"jsonBody":"={\n  \"startDate\": \"{{ new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0] }}\",\n  \"endDate\": \"{{ new Date().toISOString().split('T')[0] }}\",\n  \"dimensions\": [\"query\", \"page\", \"device\", \"date\"],\n  \"rowLimit\": 1000\n}","sendBody":true,"specifyBody":"json","authentication":"predefinedCredentialType","nodeCredentialType":"googleOAuth2Api"},"credentials":{"googleOAuth2Api":{"id":"lLujWAcqKzXHkHvw","name":"Google account"}},"typeVersion":4.2},{"id":"e65f93e1-715d-451a-b205-7c1c2ff1f6ca","name":"Code1","type":"n8n-nodes-base.code","position":[720,160],"parameters":{"jsCode":"return $json.rows.map(row => ({\n  json: {\n    date: row.keys[3],\n    query: row.keys[0],\n    page: row.keys[1],\n    device: row.keys[2],\n    clicks: row.clicks,\n    impressions: row.impressions,\n    ctr: row.ctr,\n    position: row.position\n  }\n}));"},"typeVersion":2}],"pinData":{},"connections":{"Code1":{"main":[[{"node":"NocoDB1","type":"main","index":0}]]},"HTTP Request1":{"main":[[{"node":"Code1","type":"main","index":0}]]},"Schedule Trigger1":{"main":[[{"node":"HTTP Request1","type":"main","index":0}]]}}}


name: Real-time Crypto News & Sentiment Analysis via Telegram with GPT-4o
author_name: Don Jayamaha Jr
author_username: don-the-gem-dealer
categories: []
created_at: 2025-04-27T02:48:10.901Z
updated_at: 2025-04-27T02:48:10.901Z
url: https://n8n.io/workflows/3751
scraped_at: 2025-07-06 21:16:30
description:
  Stay on top of the latest crypto news and market sentiment instantly, all inside Telegram!  
  This workflow aggregates articles from the top crypto news sources, filters for your topic of interest, and summarizes key news and market sentiment using GPT-4o AI. Ideal for crypto traders, investors, analysts, and market watchers needing fast, intelligent news briefings.

  &gt; 💬 Just type a coin name (e.g., "Bitcoin", "Solana", "DeFi") into your Telegram AI Agent—and get a smart news digest.

  How It Works

  Telegram Bot Trigger  
     User sends a keyword (e.g., "Ethereum") of questions to the Telegram AI Agent.

  Keyword Extraction (AI-Powered)  
     An AI agent identifies the main topic for better targeting.

  News Aggregation  
     Pulls articles from 9 major crypto news RSS feeds:  
     
       Cointelegraph  
       Bitcoin Magazine  
       CoinDesk  
       Bitcoinist  
       NewsBTC  
       CryptoPotato  
       99Bitcoins  
       CryptoBriefing  
       Crypto.news  

  Filtering  
     Finds and merges articles relevant to the user's keyword.

  AI Summarization  
     GPT-4o generates a 3-part summary:
       News Summary  
       Market Sentiment Analysis  
       List of Article Links

  Telegram Response  
     Sends a structured, easy-to-read digest back to the user.

  🔍 What You Can Do with This Workflow

  🔹 Summarize breaking news for any crypto project or keyword  
  🔹 Monitor real-time market sentiment on Bitcoin, DeFi, NFTs, and more  
  🔹 Stay ahead of FUD, bullish trends, and major news events  
  🔹 Quickly brief yourself or your team via Telegram  
  🔹 Use it as a foundation for more advanced crypto alert bots

  ✅ Example User Inputs

  ✅ "Bitcoin" → Latest Bitcoin news and sentiment summary  
  ✅ "Solana" → Updates on Solana projects, price movements, and community trends  
  ✅ "NFT" → Aggregated news about NFT markets and launches  
  ✅ "Layer 2" → Insights on Optimism, Arbitrum, and other L2s  

  🛠️ Setup Instructions

  Create a Telegram Bot  
     Use @BotFather and obtain the Bot Token.

  Configure Telegram Credentials in n8n  
     Add your bot token under Telegram API Credentials.

  Configure OpenAI API  
     Add your OpenAI credentials for GPT-4o access.

  Update Telegram Send Node  
     In the Telegram Send node, replace the placeholder chatId with your real Telegram user or group chat ID.

  Deploy and Test  
     Start chatting with your bot: e.g., "Ethereum" or "DeFi".

  📌 Workflow Highlights

  9 major crypto news sources combined**
  Smart keyword matching** with AI query parsing
  Summarized insights** in human-readable format
  Reference links** included for deeper reading
  Instant delivery** via Telegram

  🚀 Get ahead of the crypto market—automate your news and sentiment monitoring with AI inside Telegram!

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

workflow_json:
  {"id":"8v4dynjkHSLVGJSG","meta":{"instanceId":"a5283507e1917a33cc3ae615b2e7d5ad2c1e50955e6f831272ddd5ab816f3fb6","templateCredsSetupCompleted":true},"name":"Crypto News & Sentiment","tags":[],"nodes":[{"id":"e10ed4da-ab3e-4ff0-b489-a3ed9e88e042","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-1340,1520],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o-mini"},"options":{}},"credentials":{"openAiApi":{"id":"yUizd8t0sD5wMYVG","name":"OpenAi account"}},"typeVersion":1.2},{"id":"edb76989-766a-43e6-bf49-3896a1d257dd","name":"Set Query","type":"n8n-nodes-base.set","position":[-780,1340],"parameters":{"options":{},"assignments":{"assignments":[{"id":"9128e9e7-d1b8-4e89-8422-849b8dd519d8","name":"query","type":"string","value":"={{ $json.output }}"},{"id":"b6adc989-7d3c-4dbb-a659-603591cf1f58","name":"sessionId","type":"string","value":"={{ $('Adds the sessionId').item.json.sessionId }}"}]}},"typeVersion":3.4},{"id":"0ef0571a-d0c2-4f05-898e-1aed56b02d56","name":"Crypto News & Sentiment Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-1280,1340],"parameters":{"text":"={{ $('Send Crypto or Company Name for Analysis').item.json.message.text }}","options":{"systemMessage":"Your job is to analyze the keyword of the question and output it as a single word."},"promptType":"define"},"typeVersion":1.8},{"id":"8f7859fa-e80c-4c0e-b8b5-5593d5108f5f","name":"RSS Cointelegraph","type":"n8n-nodes-base.rssFeedRead","position":[-160,500],"parameters":{"url":"https://cointelegraph.com/rss","options":{}},"typeVersion":1.1},{"id":"5ce9dc61-de8e-4b3a-a0e2-4c077a28e0d4","name":"RSS Bitcoinmagazine","type":"n8n-nodes-base.rssFeedRead","position":[-160,660],"parameters":{"url":"https://bitcoinmagazine.com/.rss/full/","options":{}},"typeVersion":1.1},{"id":"d2491728-8a51-4384-adfa-8636f8d8cacd","name":"RSS Coindesk","type":"n8n-nodes-base.rssFeedRead","position":[-160,820],"parameters":{"url":"https://www.coindesk.com/arc/outboundfeeds/rss/","options":{}},"typeVersion":1.1},{"id":"60b17a68-b7b0-444f-8bbc-4d9ccfba6892","name":"RSS Bitcoinist","type":"n8n-nodes-base.rssFeedRead","position":[-160,980],"parameters":{"url":"https://bitcoinist.com/feed/","options":{}},"typeVersion":1.1},{"id":"82b50de0-68a7-4660-b6d9-fa01922c2492","name":"RSS Newsbtc","type":"n8n-nodes-base.rssFeedRead","position":[-160,1140],"parameters":{"url":"https://www.newsbtc.com/feed/","options":{}},"typeVersion":1.1},{"id":"90f9a5be-8eb2-4073-9c18-50478ba4890b","name":"RSS Cryptopotato","type":"n8n-nodes-base.rssFeedRead","position":[-160,1500],"parameters":{"url":"https://cryptopotato.com/feed/","options":{}},"typeVersion":1.1},{"id":"6428c19d-c66c-4577-b6ca-8c0c82a757fa","name":"RSS 99bitcoins","type":"n8n-nodes-base.rssFeedRead","position":[-160,1680],"parameters":{"url":"https://99bitcoins.com/feed/","options":{}},"typeVersion":1.1},{"id":"b2fc6584-cd64-4b90-91cf-b9bfdc483203","name":"RSS Cryptobriefing","type":"n8n-nodes-base.rssFeedRead","position":[-160,1860],"parameters":{"url":"https://cryptobriefing.com/feed/","options":{}},"typeVersion":1.1},{"id":"8be5859b-bb82-4ece-9aa5-5bfbc27e4cca","name":"RSS Crypto.news","type":"n8n-nodes-base.rssFeedRead","position":[-160,2020],"parameters":{"url":"https://crypto.news/feed/","options":{}},"typeVersion":1.1},{"id":"b5f393de-a3da-47a4-8a19-ebf53c29051d","name":"Merge All Articles","type":"n8n-nodes-base.merge","position":[520,1180],"parameters":{"numberInputs":10},"typeVersion":3.1},{"id":"ce4da50f-ecff-4d13-a90d-e62db6bc3ef9","name":"Filter by Query","type":"n8n-nodes-base.code","position":[760,1320],"parameters":{"jsCode":"const term = $node[\"Set Query\"].json.query.toLowerCase();\nreturn items.filter(item => {\n  const j            = item.json;\n  const title        = (j.title || \"\").toLowerCase();\n  const snippet      = (j.contentSnippet || j.description || \"\").toLowerCase();\n  const fullContent  = (j.content || \"\").toLowerCase();\n  return title.includes(term)\n      || snippet.includes(term)\n      || fullContent.includes(term);\n});"},"typeVersion":2},{"id":"566e842f-8e2c-491c-87b5-5f1d322a9de8","name":"Build Prompt","type":"n8n-nodes-base.code","position":[1080,1320],"parameters":{"jsCode":"const q   = $node[\"Set Query\"].json.query;\nconst list = items\n  .map(i => `- ${i.json.title} (${i.json.link})`)\n  .join(\"\\n\");\nconst prompt = `\nYou are a crypto-industry news analyst.\nSummarize current news and market sentiment for **${q}** based on these articles:\n${list}\n\nAnswer in 3 parts:\n1. Summary of News\n2. Market Sentiment\n3. Links to reference news articles\n`;\nreturn [{ json: { prompt } }];"},"typeVersion":2},{"id":"2f5b2eb5-bc2e-432d-b0c8-44c6822b831b","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[2080,1020],"parameters":{"color":3,"width":300,"height":580,"content":"## Send Telegram Response\n\nSends the final AI-generated summary to the user.\n⚠️ Replace chatId with a dynamic value like << Telegram ID here >> to ensure it sends to the right user."},"typeVersion":1},{"id":"d9f178d6-b834-4a18-b8a5-ab1261b99ca6","name":"Adds the sessionId","type":"n8n-nodes-base.set","position":[-1740,1340],"parameters":{"options":{},"assignments":{"assignments":[{"id":"87c63e75-94e4-432c-b15f-8762aa340215","name":"sessionId","type":"string","value":"={{ $json.message.chat.id }}"}]}},"typeVersion":3.4},{"id":"4dd3e531-ab2a-4930-a127-08adb5bde409","name":"Summarize News & Sentiment (GPT-4o)","type":"@n8n/n8n-nodes-langchain.openAi","position":[1360,1320],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"content":"={{ $node[\"Build Prompt\"].json.prompt }}"},{"role":"assistant","content":"You are a crypto‐industry news analyst. Summarize sentiment clearly and concisely."}]}},"credentials":{"openAiApi":{"id":"yUizd8t0sD5wMYVG","name":"OpenAi account"}},"typeVersion":1.8},{"id":"b0da1d25-9c17-49a1-85f4-82425e7c9f91","name":"Prepare Telegram Message","type":"n8n-nodes-base.set","position":[1780,1320],"parameters":{"options":{},"assignments":{"assignments":[{"id":"565fb705-ac83-4a96-9343-2e29e348cc4f","name":"summary","type":"string","value":"={{ $json.message.content }}"}]}},"typeVersion":3.4},{"id":"95cb909b-51f4-4661-9db5-e8181a7efffe","name":"Sends Response","type":"n8n-nodes-base.telegram","position":[2180,1320],"webhookId":"8018c16f-426e-4a8b-8fbf-55cc013d1226","parameters":{"text":"={{ $json.summary }}","chatId":"<< Add Telegram ID here >>","additionalFields":{"appendAttribution":false}},"credentials":{"telegramApi":{"id":"YDlV4LtcNcmNqk4y","name":"Crypto_News_and_Sentiment_bot"}},"typeVersion":1.2},{"id":"a783bddf-7d70-4345-88f3-c474a50bdea0","name":"Send Crypto or Company Name for Analysis","type":"n8n-nodes-base.telegramTrigger","position":[-2180,1340],"webhookId":"37a1f055-1670-472d-9850-d89555b7ed47","parameters":{"updates":["message"],"additionalFields":{}},"credentials":{"telegramApi":{"id":"YDlV4LtcNcmNqk4y","name":"Crypto_News_and_Sentiment_bot"}},"typeVersion":1.2},{"id":"d847a178-c0f2-482b-8773-ac0362435dfd","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-2320,1200],"parameters":{"color":4,"width":380,"height":360,"content":"## Telegram Setup \nThis bot listens for incoming messages in Telegram. To use it, create a bot with @BotFather and paste your bot token into the credentials."},"typeVersion":1},{"id":"75ee14cf-6236-4f45-b864-b422f18c8214","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-1860,1220],"parameters":{"width":360,"height":320,"content":"## Initialize Chat Session\nStores the user's chat ID as sessionId, which is used to manage conversation memory across steps."},"typeVersion":1},{"id":"674f2555-752d-4ffc-894c-efd705f32887","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-1440,1200],"parameters":{"color":6,"width":600,"height":460,"content":"##  Extract Keyword \nThis AI agent parses the user input and returns a single-word keyword to help match relevant news articles."},"typeVersion":1},{"id":"bece27b1-bc60-44f7-bdc9-6ec61f7a2e5b","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-320,300],"parameters":{"color":5,"width":460,"height":1980,"content":"## News Aggregators\nPulls articles from major crypto news sources. You can add more RSS feeds here to expand coverage."},"typeVersion":1},{"id":"7f7a2949-4147-4ab9-bb52-99c1bb2205ed","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[440,980],"parameters":{"color":2,"width":480,"height":760,"content":"## Merge & Filter News\nCombines all RSS articles and filters them using the extracted keyword to match only relevant results."},"typeVersion":1},{"id":"d19d53c0-7d23-4ccb-9a68-dc2855e5b73d","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[1000,1140],"parameters":{"color":7,"width":260,"height":360,"content":"## Prepare AI Prompt\nConstructs the input prompt for GPT-4o with a list of filtered articles. Output includes summary, sentiment, and article links."},"typeVersion":1},{"id":"17607891-ed84-4cca-ad3d-c398e5652a8c","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[1320,1100],"parameters":{"color":3,"width":340,"height":440,"content":"## Summarize News & Sentiment (GPT-4o)\nUses OpenAI GPT-4o to generate a concise summary of the news, analyze market sentiment, and return formatted results.\n\n"},"typeVersion":1},{"id":"9d47eb56-4469-4f42-84a1-6f76bb7fa598","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[1720,1060],"parameters":{"color":6,"height":460,"content":"## Format for Telegram\n\nExtracts the AI summary and prepares it for Telegram delivery. Change the variable if you want to include other data.\n\n\n"},"typeVersion":1},{"id":"7c02860b-f865-4ff9-baeb-0903a76278d9","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[1140,320],"parameters":{"width":520,"content":"## ✅ How to Use This Template\n \n🛠 1. Connect your Telegram bot\n🤖 2. Add your OpenAI credentials\n📰 3. Customize the RSS feeds (optional)\n✅ 4. Start your bot and send a query like “Bitcoin” or “NFT”"},"typeVersion":1}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"ae250264-5df8-4341-b198-5272baeadc38","connections":{"Set Query":{"main":[[{"node":"RSS Cointelegraph","type":"main","index":0},{"node":"RSS Bitcoinmagazine","type":"main","index":0},{"node":"RSS Coindesk","type":"main","index":0},{"node":"RSS Bitcoinist","type":"main","index":0},{"node":"RSS Newsbtc","type":"main","index":0},{"node":"RSS Cryptopotato","type":"main","index":0},{"node":"RSS 99bitcoins","type":"main","index":0},{"node":"RSS Cryptobriefing","type":"main","index":0},{"node":"RSS Crypto.news","type":"main","index":0}]]},"RSS Newsbtc":{"main":[[{"node":"Merge All Articles","type":"main","index":4}]]},"Build Prompt":{"main":[[{"node":"Summarize News & Sentiment (GPT-4o)","type":"main","index":0}]]},"RSS Coindesk":{"main":[[{"node":"Merge All Articles","type":"main","index":2}]]},"RSS 99bitcoins":{"main":[[{"node":"Merge All Articles","type":"main","index":7}]]},"RSS Bitcoinist":{"main":[[{"node":"Merge All Articles","type":"main","index":3}]]},"Filter by Query":{"main":[[{"node":"Build Prompt","type":"main","index":0}]]},"RSS Crypto.news":{"main":[[{"node":"Merge All Articles","type":"main","index":9}]]},"RSS Cryptopotato":{"main":[[{"node":"Merge All Articles","type":"main","index":6}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"Crypto News & Sentiment Agent","type":"ai_languageModel","index":0}]]},"RSS Cointelegraph":{"main":[[{"node":"Merge All Articles","type":"main","index":0}]]},"Adds the sessionId":{"main":[[{"node":"Crypto News & Sentiment Agent","type":"main","index":0}]]},"Merge All Articles":{"main":[[{"node":"Filter by Query","type":"main","index":0}]]},"RSS Cryptobriefing":{"main":[[{"node":"Merge All Articles","type":"main","index":8}]]},"RSS Bitcoinmagazine":{"main":[[{"node":"Merge All Articles","type":"main","index":1}]]},"Prepare Telegram Message":{"main":[[{"node":"Sends Response","type":"main","index":0}]]},"Crypto News & Sentiment Agent":{"main":[[{"node":"Set Query","type":"main","index":0}]]},"Summarize News & Sentiment (GPT-4o)":{"main":[[{"node":"Prepare Telegram Message","type":"main","index":0}]]},"Send Crypto or Company Name for Analysis":{"main":[[{"node":"Adds the sessionId","type":"main","index":0}]]}}}


name: Build your own N8N Workflows MCP Server
author_name: Jimleuk
author_username: jimleuk
categories: []
created_at: 2025-04-28T09:09:58.852Z
updated_at: 2025-04-28T09:09:58.852Z
url: https://n8n.io/workflows/3770
scraped_at: 2025-07-06 21:16:30
description:
  This n8n template shows you how to create an MCP server out of your existing n8n workflows. With this, any MCP client connected can get more done with powerful end-to-end workflows rather than just simple tools.

  Designing agent tools for outcome rather than utility has been a long recommended practice of mine and it applies well when it comes to building MCP servers; In gist, agents to be making the least amount of calls possible to complete a task.

  This is why n8n can be a great fit for MCP servers! This template connects your agent/MCP client (like Claude Desktop) to your existing workflows by allowing the AI to discover, manage and run these workflows indirectly.

  How it works
  An MCP trigger is used and attaches 4 custom workflow tools to discover and manage existing workflows to use and 1 custom workflow tool to execute them.
  We'll introduce an idea of "available" workflows which the agent is allowed to use. This will help limit and avoid some issues when trying to use every workflow such as clashes or non-production.
  The n8n node is a core node which taps into your n8n instance API and is able to retrieve all workflows or filter by tag. For our example, we've tagged the workflows we want to use with "mcp" and these are exposed through the tool "search workflows".
  Redis is used as our main memory for keeping track of which workflows are "available". The tools we have are "add Workflow", "remove workflow" and "list workflows". The agent should be able to manage this autonomously.
  Our approach to allow the agent to execute workflows is to use the Subworkflow trigger. The tricky part is figuring out the input schema for each but was eventually solved by pulling this information out of the workflow's template JSON and adding it as part of the "available" workflow's description. To pass parameters through the Subworkflow trigger, we can do so via the passthrough method - which is that incoming data is used when parameters are not explicitly set within the node.
  When running, the agent will not see the "available" workflows immediately but will need to discover them via "list" and "search". The human will need to make the agent aware that these workflows will be preferred when answering queries or completing tasks.

  How to use
  First, decide which workflows will be made visible to the MCP server. This example uses the tag of "mcp" but you can all workflows or filter in other ways.
  Next, ensure these workflows have Subworkflow triggers with input schema set. This is how the MCP server will run them.
  Set the MCP server to "active" which turns on production mode and makes available to production URL.
  Use this production URL in your MCP client. For Claude Desktop, see the instructions here - https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/#integrating-with-claude-desktop.
  There is a small learning curve which will shape how you communicate with this MCP server so be patient and test. The MCP server will work better if there is a focused goal in mind ie. Research and report, rather than just a collection of unrelated tools.

  Requirements
  N8N API key to filter for selected workflows.
  N8N workflows with Subworkflow triggers!
  Redis for memory and tracking the "available" workflows.
  MCP Client or Agent for usage such as Claude Desktop - https://claude.ai/download

  Customising this workflow
  If your targeted workflows do not use the subworkflow trigger, it is possible to amend the executeTool to use HTTP requests for webhooks.
  Managing available workflows helps if you have many workflows where some may be too similar for the agent. If this isn't a problem for you however, feel free to remove the concept of "available" and let the agent discover and use all workflows!

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

workflow_json:
  {"meta":{"instanceId":"408f9fb9940c3cb18ffdef0e0150fe342d6e655c3a9fac21f0f644e8bedabcd9","templateCredsSetupCompleted":true},"nodes":[{"id":"e3ed1048-bad0-4e91-bfb5-aef3e1883de4","name":"Simplify Workflows","type":"n8n-nodes-base.set","position":[-1740,0],"parameters":{"options":{},"assignments":{"assignments":[{"id":"821226b0-12ad-4d1d-81c3-dfa3c286cce4","name":"id","type":"string","value":"={{ $json.id }}"},{"id":"629d95d6-2501-4ad4-a5ed-e557237e1cc2","name":"name","type":"string","value":"={{ $json.name }}"},{"id":"30699f7c-98d3-44ee-9749-c5528579f7e6","name":"description","type":"string","value":"={{\n$json.nodes\n  .filter(node => node.type === 'n8n-nodes-base.stickyNote')\n  .filter(node => node.parameters.content.toLowerCase().includes('try it out'))\n  .map(node => node.parameters.content.substr(0,255) + '...')\n  .join('\\n')\n}}"},{"id":"6199c275-1ced-4f72-ba59-cb068db54c1b","name":"parameters","type":"string","value":"={{\n(function(node) {\n  if (!node) return {};\n  const inputs = node.parameters.workflowInputs.values;\n  return {\n    \"type\": \"object\",\n    \"required\": inputs.map(input => input.name),\n    \"properties\": inputs.reduce((acc, input) => ({\n      ...acc,\n      [input.name]: { type: input.type ?? 'string' }\n    }), {})\n  }\n})(\n$json.nodes\n  .filter(node => node.type === 'n8n-nodes-base.executeWorkflowTrigger')\n  .first()\n)\n.toJsonString()\n}}"}]}},"executeOnce":false,"typeVersion":3.4},{"id":"a935f5b6-3a35-49e7-870c-87e4daf0ad13","name":"When Executed by Another Workflow","type":"n8n-nodes-base.executeWorkflowTrigger","position":[-3060,600],"parameters":{"workflowInputs":{"values":[{"name":"operation"},{"name":"workflowIds"},{"name":"parameters","type":"object"}]}},"typeVersion":1.1},{"id":"2ff5e521-5288-47a9-af49-55a1bbbfb4f4","name":"Operations","type":"n8n-nodes-base.switch","position":[-2660,560],"parameters":{"rules":{"values":[{"outputKey":"Add","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"3254a8f9-5fd3-4089-be16-cc3fd20639b8","operator":{"type":"string","operation":"equals"},"leftValue":"={{ $('When Executed by Another Workflow').first().json.operation }}","rightValue":"addWorkflow"}]},"renameOutput":true},{"outputKey":"remove","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"a33dd02d-5192-48c9-b569-eafddabd2462","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $('When Executed by Another Workflow').first().json.operation }}","rightValue":"removeWorkflow"}]},"renameOutput":true},{"outputKey":"list","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2d68dc3f-a213-47f8-8453-1bceae404653","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $('When Executed by Another Workflow').first().json.operation }}","rightValue":"listWorkflows"}]},"renameOutput":true},{"outputKey":"search","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2146a87e-1a50-4caa-a2ee-f7f6fc2b19c9","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $('When Executed by Another Workflow').first().json.operation }}","rightValue":"searchWorkflows"}]},"renameOutput":true},{"outputKey":"execute","conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"98b25a51-2cb5-49af-9609-827245595dc9","operator":{"name":"filter.operator.equals","type":"string","operation":"equals"},"leftValue":"={{ $('When Executed by Another Workflow').first().json.operation }}","rightValue":"executeWorkflow"}]},"renameOutput":true}]},"options":{}},"typeVersion":3.2},{"id":"5b78271a-6474-4d87-a344-72f7f63822dc","name":"Get MCP-tagged Workflows","type":"n8n-nodes-base.n8n","position":[-2400,200],"parameters":{"filters":{"tags":"mcp"},"requestOptions":{}},"credentials":{"n8nApi":{"id":"5vELmsVPmK4Bkqkg","name":"n8n account"}},"typeVersion":1},{"id":"1197d29e-b124-4576-846d-876ad16de6e9","name":"Filter Matching Ids","type":"n8n-nodes-base.filter","position":[-2180,200],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"90c97733-48de-4402-8388-5d49e3534388","operator":{"type":"boolean","operation":"true","singleValue":true},"leftValue":"={{\n$json.id\n  ? $('When Executed by Another Workflow').first().json.workflowIds.split(',').includes($json.id)\n  : false\n}}","rightValue":"={{ $json.id }}"}]}},"executeOnce":false,"typeVersion":2.2,"alwaysOutputData":true},{"id":"81623298-c3e7-4e20-86a9-d2587b302f28","name":"Store In Memory","type":"n8n-nodes-base.redis","position":[-1520,0],"parameters":{"key":"mcp_n8n_tools","value":"={{\n($('Get Memory').item.json.data?.parseJson() ?? [])\n  .concat($input.all().map(item => item.json))\n  .toJsonString()\n}}","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"executeOnce":true,"typeVersion":1},{"id":"5ff0ea2f-a2ee-4cc3-bdf9-153ce5973770","name":"AddTool Success","type":"n8n-nodes-base.set","position":[-1300,0],"parameters":{"options":{},"assignments":{"assignments":[{"id":"d921063f-e8ed-44a8-95a0-4402ecde6c5d","name":"=response","type":"string","value":"={{ $('Simplify Workflows').all().length }} tools were added successfully."}]}},"executeOnce":true,"typeVersion":3.4},{"id":"1d3169cc-15cd-4296-9e63-bb162322e5e2","name":"AddTool Error","type":"n8n-nodes-base.set","position":[-1740,200],"parameters":{"options":{},"assignments":{"assignments":[{"id":"8c4e0763-a4ff-4e8a-a992-13e4e12a5685","name":"response","type":"string","value":"Expected Tools matching Ids given, but none found."}]}},"executeOnce":true,"typeVersion":3.4},{"id":"6149a950-c1ed-44b4-aee6-3daeabf8ba01","name":"Get Memory","type":"n8n-nodes-base.redis","position":[-2860,600],"parameters":{"key":"mcp_n8n_tools","options":{},"operation":"get","propertyName":"data"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"typeVersion":1},{"id":"3c538002-45f7-4a2f-9ef4-5aede63235ab","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[-2180,400],"parameters":{"options":{},"fieldToSplitOut":"data"},"typeVersion":1},{"id":"d41e48e0-d610-4e18-9942-842419c99c83","name":"Filter Matching IDs","type":"n8n-nodes-base.filter","position":[-1960,400],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"d2c149fb-d115-449b-9b74-f3c2f8ff7950","operator":{"type":"boolean","operation":"false","singleValue":true},"leftValue":"={{\n$json.id\n  ? $('Operations').first().json.workflowIds.split(',').includes($json.id)\n  : false\n}}","rightValue":""}]}},"typeVersion":2.2,"alwaysOutputData":true},{"id":"21d8cdda-bb47-42cd-a056-809a5556b438","name":"Store In Memory1","type":"n8n-nodes-base.redis","position":[-1520,500],"parameters":{"key":"mcp_n8n_tools","value":"={{ $input.all().flatMap(item => item.json.data).compact() }}","operation":"set"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"executeOnce":true,"typeVersion":1},{"id":"5a391d0a-ba13-4d54-85fd-eb2f6a935614","name":"Remove Tool Success","type":"n8n-nodes-base.set","position":[-1300,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"1368947f-6625-4e2e-ae27-0fcad0a1d12a","name":"response","type":"string","value":"={{ $('When Executed by Another Workflow').first().json.workflowIds.split(',').length }} tool(s) removed successfully."}]}},"typeVersion":3.4},{"id":"65dfecc4-43ba-4518-adbf-9676c5cb1377","name":"Convert to JSON","type":"n8n-nodes-base.set","position":[-2400,400],"parameters":{"options":{},"assignments":{"assignments":[{"id":"bce29a06-cff6-4409-96d2-04cc858a0e98","name":"data","type":"array","value":"={{ $json.data.parseJson() }}"}]}},"typeVersion":3.4},{"id":"b8b64fc2-63cf-4b17-9b6d-9d94aec10065","name":"listTools Success","type":"n8n-nodes-base.set","position":[-2400,600],"parameters":{"options":{},"assignments":{"assignments":[{"id":"bce29a06-cff6-4409-96d2-04cc858a0e98","name":"response","type":"array","value":"={{\n$json.data\n  ? $json.data.parseJson()\n  : []\n}}"}]}},"typeVersion":3.4},{"id":"d4fd9e74-f040-4b3c-8ce0-371315a0d130","name":"Get MCP-tagged Workflows1","type":"n8n-nodes-base.n8n","position":[-2180,600],"parameters":{"filters":{"tags":"mcp"},"requestOptions":{}},"credentials":{"n8nApi":{"id":"5vELmsVPmK4Bkqkg","name":"n8n account"}},"typeVersion":1},{"id":"d58922c4-b721-4228-83cb-0b1d9632bbc6","name":"Simplify Workflows1","type":"n8n-nodes-base.set","position":[-1960,600],"parameters":{"options":{},"assignments":{"assignments":[{"id":"821226b0-12ad-4d1d-81c3-dfa3c286cce4","name":"id","type":"string","value":"={{ $json.id }}"},{"id":"629d95d6-2501-4ad4-a5ed-e557237e1cc2","name":"name","type":"string","value":"={{ $json.name }}"},{"id":"30699f7c-98d3-44ee-9749-c5528579f7e6","name":"description","type":"string","value":"={{\n$json.nodes\n  .filter(node => node.type === 'n8n-nodes-base.stickyNote')\n  .filter(node => node.parameters.content.toLowerCase().includes('try it out'))\n  .map(node => node.parameters.content.substr(0,255) + '...')\n  .join('\\n')\n}}"},{"id":"137221ef-f0a3-4441-bae7-d9d4a22e05b7","name":"parameters","type":"string","value":"={{\n(function(node) {\n  if (!node) return {};\n  const inputs = node.parameters.workflowInputs.values;\n  return {\n    \"type\": \"object\",\n    \"required\": inputs.map(input => input.name),\n    \"properties\": inputs.reduce((acc, input) => ({\n      ...acc,\n      [input.name]: { type: input.type ?? 'string' }\n    }), {})\n  }\n})(\n$json.nodes\n  .filter(node => node.type === 'n8n-nodes-base.executeWorkflowTrigger')\n  .first()\n)\n.toJsonString()\n}}"}]}},"executeOnce":false,"typeVersion":3.4},{"id":"b44b1115-5153-4b98-979f-219a32b693de","name":"listTools Success1","type":"n8n-nodes-base.aggregate","position":[-1740,600],"parameters":{"options":{},"aggregate":"aggregateAllItemData","destinationFieldName":"response"},"typeVersion":1},{"id":"e9d9a33c-ebfa-4f74-a4da-fb6b6f6f6df5","name":"Get Parameters","type":"n8n-nodes-base.set","position":[-1920,1020],"parameters":{"mode":"raw","options":{},"jsonOutput":"={{ $('When Executed by Another Workflow').first().json.parameters }}"},"typeVersion":3.4},{"id":"c028324a-5c79-4ce9-afd6-097b6f75a74a","name":"executeTool Result","type":"n8n-nodes-base.aggregate","position":[-1440,1020],"parameters":{"options":{},"aggregate":"aggregateAllItemData","destinationFieldName":"response"},"typeVersion":1},{"id":"9eeac3cb-af7e-44c7-8891-6ff4367d0b54","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[-3600,1040],"parameters":{"options":{"systemMessage":"=You are a helpful assistant who only uses workflows to answer questions and perform tasks.\n* When asked to complete a task, you will assume there is a workflow which you can use. Do not generate custom scripts or raw commands - use a workflow isntead.\n* Only use the available active workflows as listed using the \"listWorkflows\" tool.\n* Workflows returned by \"listWorkflows\" tool are active in the pool and do not need to be added again.\n* Always ask the user before adding workflows to the availble pool.\n* You do not need to confirm each step with the user when executing workflows.\n* When executing the workflow, the required parameters schema for it is listed in the workflow's profile. To get this profile, use the listWokflows tool.\n* If no available workflows are suitable and you are not able to complete the task, simply let the user know.\n* Do not search for workflows in the directory unless the user requests."}},"typeVersion":1.8},{"id":"23601548-7863-403e-a671-267bf592b824","name":"When chat message received","type":"@n8n/n8n-nodes-langchain.chatTrigger","position":[-3840,1040],"webhookId":"86a50552-8058-4896-bd7e-ab95eba073ce","parameters":{"options":{}},"typeVersion":1.1},{"id":"54ed210d-e1b8-4bd7-85e4-88678111a45e","name":"MCP Client","type":"@n8n/n8n-nodes-langchain.mcpClientTool","position":[-3360,1240],"parameters":{"sseEndpoint":"=<Production URL of MCP Server>"},"typeVersion":1},{"id":"c612da64-9cc1-4601-a987-cd2023fd1863","name":"Simple Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[-3500,1240],"parameters":{"contextWindowLength":30},"typeVersion":1.3},{"id":"77a9fd22-c31c-49e4-9d5f-af572b137925","name":"Convert to JSON1","type":"n8n-nodes-base.set","position":[-2360,1120],"parameters":{"options":{},"assignments":{"assignments":[{"id":"bce29a06-cff6-4409-96d2-04cc858a0e98","name":"data","type":"array","value":"={{ $json.data.parseJson() }}"}]}},"typeVersion":3.4},{"id":"3377aa25-4190-4bdc-be20-b4e324212060","name":"Has Workflow Available?","type":"n8n-nodes-base.if","position":[-2140,1120],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"9c9df00b-b090-4773-8012-1824b4eeb13f","operator":{"type":"object","operation":"exists","singleValue":true},"leftValue":"={{\n$json.data.find(d => d.id === $('When Executed by Another Workflow').item.json.workflowIds)\n}}","rightValue":""}]}},"typeVersion":2.2},{"id":"92b1bb21-d739-47f0-a278-92ffa5a10cbf","name":"ExecuteTool Error","type":"n8n-nodes-base.set","position":[-1920,1220],"parameters":{"options":{},"assignments":{"assignments":[{"id":"2fa3e311-e836-42f4-922a-fae19d8e0267","name":"response","type":"string","value":"=Expected workflow to be available but not yet added. You can only use workflows which have been added to the available pool. Use the listWorkflows tool to see available workflows."}]}},"typeVersion":3.4},{"id":"529e35e0-cf11-405a-9011-e6f7f2122a4e","name":"Workflow Exists?","type":"n8n-nodes-base.if","position":[-1960,200],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"15aef770-639e-4df0-900f-29013ccd00c4","operator":{"type":"object","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json }}","rightValue":""}]}},"typeVersion":2.2},{"id":"ba278834-c774-4a3d-8ebc-f64ac77317c2","name":"N8N Workflows MCP Server","type":"@n8n/n8n-nodes-langchain.mcpTrigger","position":[-3720,240],"webhookId":"4625bcf4-0dd9-4562-a70f-6fee41f6f12d","parameters":{"path":"4625bcf4-0dd9-4562-a70f-6fee41f6f12d"},"typeVersion":1},{"id":"ed940612-4772-4377-afe2-5484a8978665","name":"Add Workflow","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-3800,460],"parameters":{"name":"addWorkflow","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Adds one or more workflows by ID to the available pool of workflows for the agent. You can get a list of workflows by calling the listTool tool.","workflowInputs":{"value":{"operation":"addWorkflow","parameters":"null","workflowIds":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('workflowIds', ``, 'string') }}"},"schema":[{"id":"operation","type":"string","display":true,"required":false,"displayName":"operation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"workflowIds","type":"string","display":true,"required":false,"displayName":"workflowIds","defaultMatch":false,"canBeUsedToMatch":true},{"id":"parameters","type":"object","display":true,"required":false,"displayName":"parameters","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"e7d5096c-3545-43fd-aa1f-495dc041ccce","name":"RemoveWorkflow","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-3700,560],"parameters":{"name":"removeWorkflow","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Removes one or more workflows by ID from the available pool of workflows for the agent.","workflowInputs":{"value":{"operation":"removeWorkflow","parameters":"null","workflowIds":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('workflowIds', ``, 'string') }}"},"schema":[{"id":"operation","type":"string","display":true,"required":false,"displayName":"operation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"workflowIds","type":"string","display":true,"required":false,"displayName":"workflowIds","defaultMatch":false,"canBeUsedToMatch":true},{"id":"parameters","type":"object","display":true,"required":false,"displayName":"parameters","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"c20b63dc-e768-4529-a08c-5370853fc4c9","name":"List Workflows","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-3580,660],"parameters":{"name":"listTool","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Lists the available pool of workflows for the agent.","workflowInputs":{"value":{"operation":"listWorkflows","parameters":"null","workflowIds":"null"},"schema":[{"id":"operation","type":"string","display":true,"required":false,"displayName":"operation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"workflowIds","type":"string","display":true,"required":false,"displayName":"workflowIds","defaultMatch":false,"canBeUsedToMatch":true},{"id":"parameters","type":"object","display":true,"required":false,"displayName":"parameters","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"88fb8a1e-2f4c-4ff1-8be9-0f7afee2dd4d","name":"SearchWorkflows","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-3460,560],"parameters":{"name":"searchTool","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Returns all workflows which can be added to the pool of available workflows for the agent.","workflowInputs":{"value":{"operation":"searchWorkflows","parameters":"null","workflowIds":"null"},"schema":[{"id":"operation","type":"string","display":true,"required":false,"displayName":"operation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"workflowIds","type":"string","display":true,"required":false,"displayName":"workflowIds","defaultMatch":false,"canBeUsedToMatch":true},{"id":"parameters","type":"object","display":true,"required":false,"displayName":"parameters","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"c643c007-de89-4d94-9739-aeb2032c792f","name":"ExecuteWorkflow","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[-3340,460],"parameters":{"name":"executeTool","workflowId":{"__rl":true,"mode":"id","value":"={{ $workflow.id }}"},"description":"Executes a workflow which has been added to the pool of available workflows for the agent.","workflowInputs":{"value":{"operation":"executeWorkflow","parameters":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('parameters', ``, 'string') }}","workflowIds":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('workflowIds', ``, 'string') }}"},"schema":[{"id":"operation","type":"string","display":true,"required":false,"displayName":"operation","defaultMatch":false,"canBeUsedToMatch":true},{"id":"workflowIds","type":"string","display":true,"required":false,"displayName":"workflowIds","defaultMatch":false,"canBeUsedToMatch":true},{"id":"parameters","type":"object","display":true,"required":false,"displayName":"parameters","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2.1},{"id":"4f1c1559-8d50-48b1-94f2-542e0bb4d494","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-3920,80],"parameters":{"color":7,"width":720,"height":740,"content":"## 1. Add MCP Server Trigger\n[Read more about the MCP server trigger](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/)"},"typeVersion":1},{"id":"54d61491-04dc-4263-96e0-67827842ca07","name":"Execute Workflow with PassThrough Variables","type":"n8n-nodes-base.executeWorkflow","position":[-1660,1020],"parameters":{"options":{"waitForSubWorkflow":true},"workflowId":{"__rl":true,"mode":"id","value":"={{ $('When Executed by Another Workflow').first().json.workflowIds }}"},"workflowInputs":{"value":{},"schema":[],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":true}},"executeOnce":false,"typeVersion":1.2},{"id":"1042884f-a44c-4757-9ff9-3a5cc81058f2","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-2600,-140],"parameters":{"color":7,"width":740,"height":300,"content":"## 2. Dynamically manage a list of \"Available\" Workflows\n[Learn more about the n8n node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.n8n)\n\nThe idea is to limit the number of workflows the agent has access to in order to ensure undesired workflows or duplication of similar workflows are avoided. Here, we do this by managing a virtual list of workflows in memory using Redis - under the hood, it's just an array to store Workflow details.\n\nGood to note, the intended workflows must have **Subworkflow triggers** and ideally, with input schema set as well. This template analyses each workflow's JSON and captures its input schema as part of the workflow's description. Doing so,  when it comes time to execute, the agent will know in what format to set the parameters when calling the subworkflow.\n"},"typeVersion":1},{"id":"903ead44-3eab-4606-aa4e-e66378bb5f7e","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-2420,820],"parameters":{"color":7,"width":1160,"height":600,"content":"## 3. Let the Agent execute any N8N Workflow\n[Learn more about the Execute Workflow node](https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.executeworkflow/)\n\nFinally once the agent has gathered the required workflows, it will start performing the requested task by executing one or more available workflows. The desired behaviour is that the agent will use \"listWorkflows\" to see which workflows are \"active\" and then plan out how to use them. Attempts to use a workflow before adding it to the available pool will result in an error response."},"typeVersion":1},{"id":"194fbcbc-a7bb-41c8-9289-a214b1415386","name":"OpenAI Chat Model","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[-3660,1240],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4.1-mini","cachedResultName":"gpt-4.1-mini"},"options":{}},"credentials":{"openAiApi":{"id":"8gccIjcuf3gvaoEr","name":"OpenAi account"}},"typeVersion":1.2},{"id":"aee33258-cf30-4cb4-ab58-7bef7ba27b65","name":"Is Empty Array?","type":"n8n-nodes-base.if","position":[-1740,400],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"2cd1b233-fb24-45d5-9efd-1db44b817809","operator":{"type":"array","operation":"empty","singleValue":true},"leftValue":"={{ $input.all().flatMap(item => item.json.data).compact() }}","rightValue":""}]}},"typeVersion":2.2},{"id":"b367a25f-e679-4a71-910e-27f1aa686816","name":"Delete Key","type":"n8n-nodes-base.redis","position":[-1520,300],"parameters":{"key":"mcp_n8n_tools","operation":"delete"},"credentials":{"redis":{"id":"zU4DA70qSDrZM1El","name":"Redis account (localhost)"}},"executeOnce":true,"typeVersion":1},{"id":"eec527e1-db4d-4294-a076-379ebd9640a9","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[-3920,860],"parameters":{"color":7,"width":740,"height":560,"content":"## 4. Connect any Agent with a MCP Client\nUse this agent to test your MCP server. Note, i"},"typeVersion":1},{"id":"c9b51f36-f9bd-4a60-b195-8da229462331","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-2880,820],"parameters":{"color":5,"width":320,"height":400,"content":"* **AddWorkflow**\n  This tool adds (or rather, appends) workflows to our \"available\" list.\n* **RemoveWorkflow**\n  This tool removes a workflow entry from our list.\n* **listWorkflows**\n  This tool displays the current state of the workflows list and the available workflows within it. Useful for checking which workflows have been added to the list.\n* **searchWorkflows**\n  For now, this tools just pulls the existing workflows from the n8n instance and returns it to the agent. Given more resources, you may want to swap this out for a indexed search instead (you'll need to build this yourself!)."},"typeVersion":1},{"id":"91b2859a-7563-4ebd-ae61-c9a487e18d81","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-4600,-180],"parameters":{"width":600,"height":1440,"content":"## Try it out!\n### This n8n template shows you how to create an MCP server out of your existing n8n workflows. With this, any MCP client connected can get more done with powerful end-to-end workflows rather than just simple tools.\n\nDesigning agent tools for outcome rather than utility has been a long recommended practice of mine and it applies well when it comes to building MCP servers; In gist, it prefers agents to be making the least calls possible to complete a task.\n\nThis is why n8n can be a great fit for MCP servers! This template connects your agent/MCP client (like Claude Desktop) to your existing workflows by allowing the AI to discover, manage and run these workflows indirectly.\n\n### How it works\n* An MCP trigger is used and attaches 4 custom workflow tools to discover and manage existing workflows to use and 1 custom workflow tool to execute them.\n* We'll introduce an idea of \"available\" workflows which the agent is allowed to use. This will help limit and avoid some issues when trying to use every workflow such as clashes or non-production.\n* The n8n node is a core node which taps into your n8n instance API and is able to retrieve all workflows or filter by tag. For our example, we've tagged the workflows we want to use with \"mcp\" and these are exposed through the tool \"search workflows\".\n* Redis is used as our main memory for keeping track of which workflows are \"available\". The tools we have are \"add Workflow\", \"remove workflow\" and \"list workflows\". The agent should be able to manage this autonomously.\n* Our approach to allow the agent to execute workflows is to use the Subworkflow trigger. The tricky part is figuring out the input schema for each but was eventually solved by pulling this information out of the workflow's template JSON and adding it as part of the \"available\" workflow's description. To pass parameters through the Subworkflow trigger, we can do so via the passthrough method - which is that incoming data is used when parameters are not explicitly set within the node.\n* When running, the agent will not see the \"available\" workflows immediately but will need to discover them via \"list\" and \"search\". The human will need to make the agent aware that these workflows will be preferred when answering queries or completing tasks.\n\n### How to use\n* First, decide which workflows will be made visible to the MCP server. This example uses the tag of \"mcp\" but you can all workflows or filter in other ways.\n* Next, ensure these workflows have Subworkflow triggers with input schema set. This is how the MCP server will run them.\n* Set the MCP server to \"active\" which turns on production mode and makes available to production URL.\n* Use this production URL in your MCP client. For Claude Desktop, see the instructions here - https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-langchain.mcptrigger/#integrating-with-claude-desktop.\n* There is a small learning curve which will shape how you communicate with this MCP server so be patient and test. The MCP server will work better if there is a focused goal in mind ie. Research and report, rather than just a collection of unrelated tools.\n\n### Requirements\n* N8N API key to filter for selected workflows.\n* N8N workflows with Subworkflow triggers!\n* Redis for memory and tracking the \"available\" workflows.\n* MCP Client or Agent for usage such as Claude Desktop - https://claude.ai/download\n\n### Customising this workflow\n* If your targeted workflows do not use the subworkflow trigger, it is possible to amend the executeTool to use HTTP requests for webhooks.\n* Managing available workflows helps if you have many workflows where some may be too similar for the agent. If this isn't a problem for you however, feel free to remove the concept of \"available\" and let the agent discover and use all workflows!"},"typeVersion":1},{"id":"ec3194d2-90c8-4019-a1b5-576c61e9a8b0","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-2600,-280],"parameters":{"color":5,"width":380,"height":120,"content":"### How many existing workflows can I use?\nWell, as many as you want really! For this example, I've limited it for workflows which are tagged as \"mcp\" but you can remove this filter to allow all."},"typeVersion":1},{"id":"5f587241-5604-4724-bc01-3c9bc3f7bdc2","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[-1720,1000],"parameters":{"height":440,"content":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### 🚨 Ensure this node does not set the input schema!\nFor passthrough parameters to work, this node should not make available input schema fields. ie. the input fields should not be visible.\n\nIf there are, the node needs to be reset!"},"typeVersion":1}],"pinData":{},"connections":{"Split Out":{"main":[[{"node":"Filter Matching IDs","type":"main","index":0}]]},"Delete Key":{"main":[[{"node":"Remove Tool Success","type":"main","index":0}]]},"Get Memory":{"main":[[{"node":"Operations","type":"main","index":0}]]},"MCP Client":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"Operations":{"main":[[{"node":"Get MCP-tagged Workflows","type":"main","index":0}],[{"node":"Convert to JSON","type":"main","index":0}],[{"node":"listTools Success","type":"main","index":0}],[{"node":"Get MCP-tagged Workflows1","type":"main","index":0}],[{"node":"Convert to JSON1","type":"main","index":0}]]},"Add Workflow":{"ai_tool":[[{"node":"N8N Workflows MCP Server","type":"ai_tool","index":0}]]},"Simple Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"Get Parameters":{"main":[[{"node":"Execute Workflow with PassThrough Variables","type":"main","index":0}]]},"List Workflows":{"ai_tool":[[{"node":"N8N Workflows MCP Server","type":"ai_tool","index":0}]]},"RemoveWorkflow":{"ai_tool":[[{"node":"N8N Workflows MCP Server","type":"ai_tool","index":0}]]},"Convert to JSON":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"ExecuteWorkflow":{"ai_tool":[[{"node":"N8N Workflows MCP Server","type":"ai_tool","index":0}]]},"Is Empty Array?":{"main":[[{"node":"Delete Key","type":"main","index":0}],[{"node":"Store In Memory1","type":"main","index":0}]]},"SearchWorkflows":{"ai_tool":[[{"node":"N8N Workflows MCP Server","type":"ai_tool","index":0}]]},"Store In Memory":{"main":[[{"node":"AddTool Success","type":"main","index":0}]]},"Convert to JSON1":{"main":[[{"node":"Has Workflow Available?","type":"main","index":0}]]},"Store In Memory1":{"main":[[{"node":"Remove Tool Success","type":"main","index":0}]]},"Workflow Exists?":{"main":[[{"node":"Simplify Workflows","type":"main","index":0}],[{"node":"AddTool Error","type":"main","index":0}]]},"OpenAI Chat Model":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"Simplify Workflows":{"main":[[{"node":"Store In Memory","type":"main","index":0}]]},"Filter Matching IDs":{"main":[[{"node":"Is Empty Array?","type":"main","index":0}]]},"Filter Matching Ids":{"main":[[{"node":"Workflow Exists?","type":"main","index":0}]]},"Simplify Workflows1":{"main":[[{"node":"listTools Success1","type":"main","index":0}]]},"Has Workflow Available?":{"main":[[{"node":"Get Parameters","type":"main","index":0}],[{"node":"ExecuteTool Error","type":"main","index":0}]]},"Get MCP-tagged Workflows":{"main":[[{"node":"Filter Matching Ids","type":"main","index":0}]]},"Get MCP-tagged Workflows1":{"main":[[{"node":"Simplify Workflows1","type":"main","index":0}]]},"When chat message received":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"When Executed by Another Workflow":{"main":[[{"node":"Get Memory","type":"main","index":0}]]},"Execute Workflow with PassThrough Variables":{"main":[[{"node":"executeTool Result","type":"main","index":0}]]}}}


name: Automated Stock Analysis Reports with Technical & News Sentiment using GPT-4o
author_name: Elay Guez
author_username: elay96
categories: []
created_at: 2025-04-29T17:33:05.653Z
updated_at: 2025-04-29T17:33:05.653Z
url: https://n8n.io/workflows/3790
scraped_at: 2025-07-06 21:16:30
description:
  Stock Analysis Agent (Hebrew, RTL, GPT-4o)

  Overview

  Get comprehensive stock analysis with this AI-powered workflow that provides actionable insights for your investment decisions. On a weekly basis, this workflow:

  Analyzes stock data from multiple sources (Chart-img, Twelve Data API, Alphavantage)
  Performs technical analysis using advanced indicators (RSI, MACD, Bollinger Bands, Resistance and Support Levels)
  Scans financial news from Alpha Vantage to capture market sentiment
  Uses OpenAI's GPT-4o to identify patterns, trends, and trading opportunities
  Generates a fully styled, responsive HTML email (with proper RTL layout) in Hebrew
  Sends detailed recommendations directly to your inbox

  Perfect for investors, traders, and financial analysts who want data-driven stock insights - combining technical indicators with news sentiment for more informed decisions.

  Setup Instructions

  Estimated setup time:
  15 minutes

  Required credentials:
  OpenAI API Key
  Chart-img API Key (free tier)
  Twelve Data API Key (free tier)
  Alpha Vantage API Key (free tier)
  SMTP credentials (for email delivery)

  Steps:

  Import this template into your n8n instance.
  Add your API keys under credentials.
  Configure the SMTP Email node with: Host (e.g., smtp.gmail.com), Port (465 or 587), Username (your email), Password (app-specific password or login).
  Activate the workflow.
  Fill in the Form.
  Enjoy! (Check your Spam mailbox)

  Customization Tips

  Modify the analysis timeframe (daily, weekly, monthly)
  Add integrations with trading platforms or portfolio management tools
  Adjust the recommendation criteria based on your risk tolerance

  Why Use This?
  This is more than just stock data. It's an intelligent financial assistant that combines technical analysis with market sentiment to provide actionable recommendations - automatically.

  Important Note:
  This report is being generated automatically and does not constitute an investment recommendation. Please consult a licensed investment advisor before making any investment decisions.

nodes_used:
  ["n8n-nodes-base.emailSend","n8n-nodes-base.httpRequest","n8n-nodes-base.code","n8n-nodes-base.html","@n8n/n8n-nodes-langchain.agent","@n8n/n8n-nodes-langchain.lmChatOpenAi","@n8n/n8n-nodes-langchain.memoryBufferWindow","@n8n/n8n-nodes-langchain.outputParserStructured","@n8n/n8n-nodes-langchain.toolWorkflow","@n8n/n8n-nodes-langchain.openAi","@n8n/n8n-nodes-langchain.toolThink"]

workflow_json:
  {"meta":{"instanceId":"6c3d8936583f8a98fa8ebe06f510117c0e8fff2df771e73deba4126a853eb55e"},"nodes":[{"id":"a9bbe9d0-51aa-40f8-8931-f405c695c732","name":"Window Buffer Memory","type":"@n8n/n8n-nodes-langchain.memoryBufferWindow","position":[1140,140],"parameters":{"sessionKey":"=335458847","sessionIdType":"customKey"},"typeVersion":1.3},{"id":"2d6315d6-959d-4e16-97ed-30839d826ce2","name":"AI Agent","type":"@n8n/n8n-nodes-langchain.agent","position":[1080,-100],"parameters":{"text":"=Ticker = {{ $json[\"Ticker symbol:\"] }}","options":{"systemMessage":"=# Overview\nYou are an AI agent specialized in stock analysis. You provide technical analysis and sentiment for stock investments by combining chart data and news sentiment.\n\n# Instructions\n1. When a user requests an analysis of a stock with its symbol:\n  - Send the stock symbol to both tools **technical_analysis** and **trends_analysis**\n  - Analyze the combined data and prepare a JSON report with your insights\n  - Provide a clear recommendation (positive, neutral, or negative)\n2. Your output must be in the format of a structured JSON object that will be used to fill an HTML template.\n3. Translate the article titles in topArticles to Hebrew\n4. Translate the sentimentHebrew results to only one of these values:\n\"חיובי-חזק/חיובי-חלש/נייטרלי/שלילי-חלש/שלילי-חזק\". Somewhat=חלש.\n5. Write the Date value in each article: \"topArticles\" only in this format: \"DD/MM/YYYY\".\n6. Update the technicalAnalysis value as a detailed technical analysis of three paragraphs, which explains even to those who don't understand economics what you did and how you reached your conclusions. Touch on all the indicators examined (Volume, EMA, RSI, Fibonacci retracement, MACD, Bollinger bands, Resistance and support levels)\n7. Ensure that the text in the technicalAnalysis value is written in proper Hebrew, like a professional analyst. Use the think tool\n8. In the Recommendation value - recommend to buy or sell only if you think with high probability that there will be a rise or fall. Use the think tool to verify your Recommendation based on recommendationText. Advise something only if you really believe it. Your default is the \"ממליץ לחכות\" value.\n\n## Tools\n- **technical_analysis**: Generates technical analysis based on stock charts\n- **trends_analysis**: Analyzes news sentiment for the requested stock\n\n## Response Format\nYou must respond with a JSON object containing exactly the following keys to fill the HTML template:\n\n```json\n{\n \"stockSymbol\": \"סימול\",\n \"analysisDate\": \"DD/MM/YYYY\",\n \"recommendationClass\": \"positive/neutral/negative\",\n \"recommendationTitle\": \"כותרת המלצה בעברית\",\n \"recommendationText\": \"הסבר מפורט של ההמלצה בעברית\",\n \"bullishCount\": 0,\n \"neutralCount\": 0, \n \"bearishCount\": 0,\n \"bullishHeight\": 0,\n \"neutralHeight\": 0,\n \"bearishHeight\": 0,\n \"overallSentiment\": \"חיובי/נייטרלי/שלילי\",\n \"Recommendation\": \"ממליץ לקנות/ ממליץ לחכות/ ממליץ למכור\",\n \"sentimentScore\": 0.00,\n \"chartImageUrl\": \"URL_PLACEHOLDER\",\n \"technicalAnalysis\": \"ניתוח טכני מפורט בעברית עם תגי <p>\",\n \"topArticles\": [\n   {\n     \"title\": \"כותרת המאמר בעברית\",\n     \"url\": \"כתובת URL של המאמר\",\n     \"source\": \"שם המקור באנגלית\",\n     \"date\": \"DD/MM/YYYY\",\n     \"sentimentClass\": \"bullish/neutral/bearish\",\n     \"sentimentHebrew\": \"חיובי-חזק/חיובי-חלש/נייטרלי/שלילי-חלש/שלילי-חזק\"\n   }\n ],\n \"hotTopics\": [\n   {\n     \"topic\": \"שם הנושא בעברית\",\n     \"article_count\": 0,\n     \"average_relevance\": \"0.00\"\n   }\n ]\n}"},"promptType":"define","hasOutputParser":true},"typeVersion":1.7},{"id":"14112026-19eb-493f-971b-28455a8d4412","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[680,-220],"parameters":{"color":4,"width":1820,"height":580,"content":"# AI Agent\nAI agent powered by GPT-4o that analyses stocks by combining technical analysis and news sentiment, generating detailed reports in Hebrew with data-driven investment recommendations"},"typeVersion":1},{"id":"8b2e573e-7acc-4b0b-a708-4ce33873a893","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[680,380],"parameters":{"width":2820,"height":920,"content":"# Technical Analysis Tool\nA tool that performs in-depth technical analysis of stock charts by combining visual pattern recognition with quantitative indicators. It fetches data from Chart-img API for generating visual charts, Twelve Data API for historical prices and technical indicators (Bollinger Bands, MACD), and uses OpenAI's GPT-4o for visual chart pattern recognition.\nThe system synthesizes this multi-source data into a comprehensive technical assessment with actionable trading insights based on support/resistance levels, Fibonacci retracements, and candlestick patterns."},"typeVersion":1},{"id":"b0d49fa6-5c57-4ab5-a752-93d7d278b8fa","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[2520,-220],"parameters":{"width":980,"height":580,"content":"# Trends Analysis Tool\nA tool that analyses news sentiment for requested stocks by fetching recent financial news articles, calculating sentiment metrics, identifying influential stories, and extracting trending topics. It processes data from Alpha Vantage's news API, determines overall market sentiment, and delivers structured analysis on stock sentiment, relevance, and market outlook."},"typeVersion":1},{"id":"13a242cf-0a01-4aea-a58e-9b734aed912c","name":"Structured Output Parser","type":"@n8n/n8n-nodes-langchain.outputParserStructured","position":[1900,140],"parameters":{"schemaType":"manual","inputSchema":"{\n  \"stockSymbol\": \"סימול\",\n  \"analysisDate\": \"DD/MM/YYYY\",\n  \"recommendationClass\": \"positive/neutral/negative\",\n  \"recommendationTitle\": \"כותרת המלצה בעברית\",\n  \"recommendationText\": \"הסבר מפורט של ההמלצה בעברית\",\n  \"bullishCount\": 0,\n  \"neutralCount\": 0, \n  \"bearishCount\": 0,\n  \"bullishHeight\": 0,\n  \"neutralHeight\": 0,\n  \"bearishHeight\": 0,\n  \"overallSentiment\": \"חיובי/נייטרלי/שלילי\",\n  \"Recommendation\": \"ממליץ לקנות/ ממליץ לחכות/ ממליץ למכור\",\n  \"sentimentScore\": 0.00,\n  \"chartImageUrl\": \"URL_PLACEHOLDER\",\n  \"technicalAnalysis\": \"ניתוח טכני מפורט בעברית עם תגי <p>\",\n  \"topArticles\": [\n    {\n      \"title\": \"כותרת המאמר\",\n      \"url\": \"כתובת URL של המאמר\",\n      \"source\": \"שם המקור\",\n      \"date\": \"DD/MM/YYYY\",\n      \"sentimentClass\": \"bullish/neutral/bearish\",\n      \"sentimentHebrew\": \"חיובי-חזק/חיובי-חלש/נייטרלי/שלילי-חלש/שלילי-חזק\"\n    }\n  ],\n  \"hotTopics\": [\n    {\n      \"topic\": \"שם הנושא בעברית\",\n      \"article_count\": 0,\n      \"average_relevance\": \"0.00\"\n    }\n  ]\n}"},"typeVersion":1.2},{"id":"bb5dd63a-a3e6-408e-a5c9-13e9f72f2b26","name":"GPT 4o","type":"@n8n/n8n-nodes-langchain.lmChatOpenAi","position":[960,140],"parameters":{"model":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"gpt-4o"},"options":{}},"credentials":{"openAiApi":{"id":"2m1HH5crgPAhTJlv","name":"OpenAi account"}},"typeVersion":1.2},{"id":"94d820d2-eb20-4184-8e21-1ed5936c9166","name":"Generate HTML","type":"n8n-nodes-base.html","position":[1860,-100],"parameters":{"html":"<!DOCTYPE html>\n<html dir=\"rtl\" lang=\"he\">\n<head>\n    <meta charset=\"UTF-8\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n    <title>ניתוח מניית {{ $('AI Agent').item.json.output.stockSymbol }}</title>\n</head>\n<body style=\"margin: 0; padding: 0; font-family: 'Segoe UI', 'Helvetica Neue', Helvetica, Arial, sans-serif; background-color: #f5f7fa; color: #333; line-height: 1.6; -webkit-font-smoothing: antialiased; font-size: 16px; text-align: right; direction: rtl;\">\n    <!-- עוטף ראשי -->\n    <div style=\"max-width: 650px; margin: 0 auto; background-color: #ffffff; border-radius: 16px; overflow: hidden; box-shadow: 0 4px 24px rgba(0,0,0,0.08); margin-top: 30px; margin-bottom: 30px; text-align: right; direction: rtl;\">\n        \n        <!-- כותרת עליונה -->\n        <div style=\"background: linear-gradient(135deg, #0057ff 0%, #00b2ff 100%); padding: 30px 40px; text-align: center; position: relative; overflow: hidden; margin-bottom: 20px;\">\n            <div style=\"position: absolute; top: 0; left: 0; right: 0; bottom: 0; background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTAwJSIgaGVpZ2h0PSIxMDAlIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxkZWZzPjxwYXR0ZXJuIGlkPSJwYXR0ZXJuIiB4PSIwIiB5PSIwIiB3aWR0aD0iNDAiIGhlaWdodD0iNDAiIHBhdHRlcm5Vbml0cz0idXNlclNwYWNlT25Vc2UiIHBhdHRlcm5UcmFuc2Zvcm09InJvdGF0ZSgzMCkiPjxwYXRoIGQ9Ik0wIDEwIEw0MCAxMCIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjAuNSIgc3Ryb2tlLW9wYWNpdHk9IjAuMSIvPjwvcGF0dGVybj48L2RlZnM+PHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgZmlsbD0idXJsKCNwYXR0ZXJuKSIvPjwvc3ZnPg=='); opacity: 0.2;\"></div>\n            <h1 style=\"color: #ffffff; font-weight: 700; font-size: 28px; margin: 0 0 5px 0; letter-spacing: -0.5px; position: relative;\">ניתוח מניית {{ $('AI Agent').item.json.output.stockSymbol }}</h1>\n            <div style=\"color: rgba(255,255,255,0.85); font-size: 15px; position: relative;\">תאריך: {{ $('AI Agent').item.json.output.analysisDate }}</div>\n        </div>\n        \n        <!-- תוכן המייל -->\n        <div style=\"padding: 40px; text-align: right; direction: rtl;\">\n            \n            <!-- תיבת המלצה -->\n            <div style=\"background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.04); padding: 25px; margin-bottom: 40px; position: relative; overflow: hidden; text-align: right;\">\n                <div style=\"position: absolute; right: 0; top: 0; bottom: 0; width: 6px; background-color: #f7b955;\"></div>\n                <div style=\"position: absolute; right: 0; top: 0; width: 100%; height: 100%; background: linear-gradient(90deg, rgba(247, 185, 85, 0.07) 0%, rgba(247, 185, 85, 0) 50%);\"></div>\n                <div style=\"text-align: center; position: relative;\">\n                    <div style=\"display: inline-block; width: 40px; height: 40px; border-radius: 50%; margin-bottom: 10px; background-color: rgba(247, 185, 85, 0.15); text-align: center;\">\n                        <span style=\"font-size: 20px; line-height: 40px;\">⚖️</span>\n                    </div>\n                    <h2 style=\"margin: 0 0 10px 0; color: #f7b955; font-size: 22px; font-weight: 700; text-align: center;\">{{ $('AI Agent').item.json.output.recommendationTitle }}</h2>\n                    <p style=\"margin: 0; font-size: 16px; line-height: 1.6; color: #4a5568; text-align: right;\">{{ $json.message.content.recommendationText }}</p>\n                    <div style=\"margin-top: 25px;\">\n                        <a style=\"display: inline-block; background-color: #29cc7a; color: white; font-weight: 600; font-size: 16px; padding: 12px 30px; border-radius: 8px; text-decoration: none; box-shadow: 0 4px 6px rgba(41, 204, 122, 0.25); transition: all 0.2s ease;\">{{ $('AI Agent').item.json.output.Recommendation }}</a>\n                    </div>\n                </div>\n            </div>\n\n            <!-- ניתוח טכני -->\n            <div style=\"margin-bottom: 40px; text-align: right;\">\n                <h2 style=\"font-size: 20px; color: #1a202c; margin: 0 0 20px 0; padding-bottom: 12px; border-bottom: 1px solid #edf2f7; font-weight: 700; text-align: right;\">ניתוח טכני</h2>\n                \n                <div style=\"background: #ffffff; border-radius: 12px; box-shadow: 0 2px 12px rgba(0,0,0,0.06); overflow: hidden; margin-bottom: 25px;\">\n                    <img src=\"{{ $('AI Agent').item.json.output.chartImageUrl }}\" alt=\"גרף טכני {{ $('AI Agent').item.json.output.stockSymbol }}\" style=\"width: 100%; display: block; max-height: 450px; object-fit: contain;\">\n                </div>\n                \n                <div style=\"background-color: #f8fafc; border-radius: 12px; padding: 25px; font-size: 15px; line-height: 1.6; color: #4a5568; text-align: right;\">\n                    {{ $json.message.content.technicalAnalysis }}\n                </div>\n            </div>\n                      \n            <!-- ניתוח סנטימנט -->\n            <div style=\"margin-bottom: 40px; text-align: right;\">\n                <h2 style=\"font-size: 20px; color: #1a202c; margin: 0 0 20px 0; padding-bottom: 12px; border-bottom: 1px solid #edf2f7; font-weight: 700; text-align: right;\">ניתוח סנטימנט שוק</h2>\n                \n                <!-- גרף סנטימנט - עם טבלה במקום flex -->\n                <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin: 45px 0 30px 0;\">\n                    <tr valign=\"bottom\" align=\"center\">\n                        <td width=\"33%\" style=\"text-align: center; padding: 0 10px;\">\n                            <div style=\"font-weight: 600; margin-bottom: 10px; color: #29cc7a;\">{{ $('AI Agent').item.json.output.bullishCount }}</div>\n                            <div style=\"background-color: #29cc7a; border-radius: 8px 8px 0 0; width: 100%; height: {{ $('AI Agent').item.json.output.bullishHeight }}px; margin: 0 auto; opacity: 0.85;\"></div>\n                            <div style=\"font-size: 14px; color: #4a5568; margin-top: 10px;\">חיובי</div>\n                        </td>\n                        <td width=\"33%\" style=\"text-align: center; padding: 0 10px;\">\n                            <div style=\"font-weight: 600; margin-bottom: 10px; color: #f7b955;\">{{ $('AI Agent').item.json.output.neutralCount }}</div>\n                            <div style=\"background-color: #f7b955; border-radius: 8px 8px 0 0; width: 100%; height: {{ $('AI Agent').item.json.output.neutralHeight }}px; margin: 0 auto; opacity: 0.85;\"></div>\n                            <div style=\"font-size: 14px; color: #4a5568; margin-top: 10px;\">נייטרלי</div>\n                        </td>\n                        <td width=\"33%\" style=\"text-align: center; padding: 0 10px;\">\n                            <div style=\"font-weight: 600; margin-bottom: 10px; color: #f55e5e;\">{{ $('AI Agent').item.json.output.bearishCount }}</div>\n                            <div style=\"background-color: #f55e5e; border-radius: 8px 8px 0 0; width: 100%; height: {{ $('AI Agent').item.json.output.bearishHeight }}px; margin: 0 auto; opacity: 0.85;\"></div>\n                            <div style=\"font-size: 14px; color: #4a5568; margin-top: 10px;\">שלילי</div>\n                        </td>\n                    </tr>\n                </table>\n                \n                <div style=\"background-color: #f8fafc; border-radius: 10px; padding: 15px; text-align: center; font-size: 15px;\">\n                    הסנטימנט הכללי למניית <strong>{{ $('AI Agent').item.json.output.stockSymbol }}</strong> הוא \n                    <span style=\"font-weight: 600; color: #f7b955;\">{{ $('AI Agent').item.json.output.overallSentiment }}</span> \n                    עם ציון של <strong>{{ $('AI Agent').item.json.output.sentimentScore }}</strong>\n                </div>\n            </div>\n            \n            <!-- מאמרים משפיעים -->\n            <div style=\"margin-bottom: 40px; text-align: right;\">\n                <h2 style=\"font-size: 20px; color: #1a202c; margin: 0 0 20px 0; padding-bottom: 12px; border-bottom: 1px solid #edf2f7; font-weight: 700; text-align: right;\">מאמרים משפיעים</h2>\n                \n                <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse;\">\n                    <!-- מאמר 1 -->\n                    <tr>\n                        <td style=\"padding-bottom: 16px;\">\n                            <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;\">\n                                <tr>\n                                    <td width=\"4\" style=\"background-color: #f7b955;\"></td>\n                                    <td style=\"padding: 18px 22px;\">\n                                        <h3 style=\"margin: 0 0 8px 0; font-size: 16px; font-weight: 600; line-height: 1.4; text-align: right;\">\n                                            <a href=\"{{ $('AI Agent').item.json.output.topArticles[0].url }}\" target=\"_blank\" style=\"color: #2b6cb0; text-decoration: none;\">{{ $('AI Agent').item.json.output.topArticles[0].title }}</a>\n                                        </h3>\n                                        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin-top: 10px;\">\n                                            <tr>\n                                                <td style=\"font-size: 13px; color: #718096; text-align: right;\">{{ $('AI Agent').item.json.output.topArticles[0].source }} | {{ $('AI Agent').item.json.output.topArticles[0].date }}</td>\n                                                <td style=\"text-align: left;\">\n                                                    <div style=\"display: inline-block; padding: 3px 10px; border-radius: 30px; font-weight: 500; font-size: 12px; background-color: rgba(247, 185, 85, 0.1); color: #f7b955;\">\n                                                        {{ $('AI Agent').item.json.output.topArticles[0].sentimentHebrew }}\n                                                    </div>\n                                                </td>\n                                            </tr>\n                                        </table>\n                                    </td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                    \n                    <!-- מאמר 2 -->\n                    <tr>\n                        <td style=\"padding-bottom: 16px;\">\n                            <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;\">\n                                <tr>\n                                    <td width=\"4\" style=\"background-color: #f7b955;\"></td>\n                                    <td style=\"padding: 18px 22px;\">\n                                        <h3 style=\"margin: 0 0 8px 0; font-size: 16px; font-weight: 600; line-height: 1.4; text-align: right;\">\n                                            <a href=\"{{ $('AI Agent').item.json.output.topArticles[1].url }}\" target=\"_blank\" style=\"color: #2b6cb0; text-decoration: none;\">{{ $('AI Agent').item.json.output.topArticles[1].title }}</a>\n                                        </h3>\n                                        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin-top: 10px;\">\n                                            <tr>\n                                                <td style=\"font-size: 13px; color: #718096; text-align: right;\">{{ $('AI Agent').item.json.output.topArticles[1].source }} | {{ $('AI Agent').item.json.output.topArticles[1].date }}</td>\n                                                <td style=\"text-align: left;\">\n                                                    <div style=\"display: inline-block; padding: 3px 10px; border-radius: 30px; font-weight: 500; font-size: 12px; background-color: rgba(247, 185, 85, 0.1); color: #f7b955;\">\n                                                        {{ $('AI Agent').item.json.output.topArticles[1].sentimentHebrew }}\n                                                    </div>\n                                                </td>\n                                            </tr>\n                                        </table>\n                                    </td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                    \n                    <!-- מאמר 3 -->\n                    <tr>\n                        <td style=\"padding-bottom: 16px;\">\n                            <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;\">\n                                <tr>\n                                    <td width=\"4\" style=\"background-color: #f7b955;\"></td>\n                                    <td style=\"padding: 18px 22px;\">\n                                        <h3 style=\"margin: 0 0 8px 0; font-size: 16px; font-weight: 600; line-height: 1.4; text-align: right;\">\n                                            <a href=\"{{ $('AI Agent').item.json.output.topArticles[2].url }}\" target=\"_blank\" style=\"color: #2b6cb0; text-decoration: none;\">{{ $('AI Agent').item.json.output.topArticles[2].title }}</a>\n                                        </h3>\n                                        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin-top: 10px;\">\n                                            <tr>\n                                                <td style=\"font-size: 13px; color: #718096; text-align: right;\">{{ $('AI Agent').item.json.output.topArticles[2].source }} | {{ $('AI Agent').item.json.output.topArticles[2].date }}</td>\n                                                <td style=\"text-align: left;\">\n                                                    <div style=\"display: inline-block; padding: 3px 10px; border-radius: 30px; font-weight: 500; font-size: 12px; background-color: rgba(247, 185, 85, 0.1); color: #f7b955;\">\n                                                        {{ $('AI Agent').item.json.output.topArticles[2].sentimentHebrew }}\n                                                    </div>\n                                                </td>\n                                            </tr>\n                                        </table>\n                                    </td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                    \n                    <!-- מאמר 4 -->\n                    <tr>\n                        <td style=\"padding-bottom: 16px;\">\n                            <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;\">\n                                <tr>\n                                    <td width=\"4\" style=\"background-color: #f7b955;\"></td>\n                                    <td style=\"padding: 18px 22px;\">\n                                        <h3 style=\"margin: 0 0 8px 0; font-size: 16px; font-weight: 600; line-height: 1.4; text-align: right;\">\n                                            <a href=\"{{ $('AI Agent').item.json.output.topArticles[3].url }}\" target=\"_blank\" style=\"color: #2b6cb0; text-decoration: none;\">{{ $('AI Agent').item.json.output.topArticles[3].title }}</a>\n                                        </h3>\n                                        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin-top: 10px;\">\n                                            <tr>\n                                                <td style=\"font-size: 13px; color: #718096; text-align: right;\">{{ $('AI Agent').item.json.output.topArticles[3].source }} | {{ $('AI Agent').item.json.output.topArticles[3].date }}</td>\n                                                <td style=\"text-align: left;\">\n                                                    <div style=\"display: inline-block; padding: 3px 10px; border-radius: 30px; font-weight: 500; font-size: 12px; background-color: rgba(247, 185, 85, 0.1); color: #f7b955;\">\n                                                        {{ $('AI Agent').item.json.output.topArticles[3].sentimentHebrew }}\n                                                    </div>\n                                                </td>\n                                            </tr>\n                                        </table>\n                                    </td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                    \n                    <!-- מאמר 5 -->\n                    <tr>\n                        <td style=\"padding-bottom: 16px;\">\n                            <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; background-color: #f8fafc; border-radius: 12px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); overflow: hidden;\">\n                                <tr>\n                                    <td width=\"4\" style=\"background-color: #f7b955;\"></td>\n                                    <td style=\"padding: 18px 22px;\">\n                                        <h3 style=\"margin: 0 0 8px 0; font-size: 16px; font-weight: 600; line-height: 1.4; text-align: right;\">\n                                            <a href=\"{{ $('AI Agent').item.json.output.topArticles[4].url }}\" target=\"_blank\" style=\"color: #2b6cb0; text-decoration: none;\">{{ $('AI Agent').item.json.output.topArticles[4].title }}</a>\n                                        </h3>\n                                        <table cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\" style=\"border-collapse: collapse; margin-top: 10px;\">\n                                            <tr>\n                                                <td style=\"font-size: 13px; color: #718096; text-align: right;\">{{ $('AI Agent').item.json.output.topArticles[4].source }} | {{ $('AI Agent').item.json.output.topArticles[4].date }}</td>\n                                                <td style=\"text-align: left;\">\n                                                    <div style=\"display: inline-block; padding: 3px 10px; border-radius: 30px; font-weight: 500; font-size: 12px; background-color: rgba(247, 185, 85, 0.1); color: #f7b955;\">\n                                                        {{ $('AI Agent').item.json.output.topArticles[4].sentimentHebrew }}\n                                                    </div>\n                                                </td>\n                                            </tr>\n                                        </table>\n                                    </td>\n                                </tr>\n                            </table>\n                        </td>\n                    </tr>\n                </table>\n            </div>\n              \n    <!-- נושאים חמים - גרסה משופרת למובייל -->\n    <div style=\"margin-bottom: 30px; text-align: right;\">\n        <h2 style=\"font-size: 20px; color: #1a202c; margin: 0 0 20px 0; padding-bottom: 12px; border-bottom: 1px solid #edf2f7; font-weight: 700; text-align: right;\">נושאים חמים</h2>\n        \n        <div style=\"background-color: #f8fafc; border-radius: 12px; padding: 20px 25px; text-align: right;\">\n            <p style=\"margin: 0 0 15px 0; font-size: 15px; color: #4a5568; text-align: right;\">הנושאים המרכזיים שמופיעים בחדשות על {{ $('AI Agent').item.json.output.stockSymbol }}:</p>\n            \n            <!-- נושא 1 -->\n            <div style=\"margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #edf2f7;\">\n                <div style=\"display: table; width: 100%; margin-bottom: 8px;\">\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: right; font-weight: 600; font-size: 15px;\">\n                        {{ $('AI Agent').item.json.output.hotTopics[0].topic }}\n                    </div>\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: left; white-space: nowrap;\">\n                        <div style=\"display: inline-block; background-color: #edf2f7; border-radius: 30px; padding: 4px 12px; font-size: 13px; color: #4a5568; text-align: center;\">\n                            <strong>{{ $('AI Agent').item.json.output.hotTopics[0].article_count }}</strong> מאמרים\n                        </div>\n                    </div>\n                </div>\n                <div style=\"background-color: #e2e8f0; height: 4px; width: 100%; border-radius: 2px; overflow: hidden;\">\n                    <div style=\"background-color: #4299e1; height: 100%; width: calc({{ $('AI Agent').item.json.output.hotTopics[0].average_relevance }} * 100%);\"></div>\n                </div>\n                <div style=\"text-align: left; font-size: 12px; color: #718096; margin-top: 4px;\">רלוונטיות: {{ $('AI Agent').item.json.output.hotTopics[0].average_relevance }}</div>\n            </div>\n            \n            <!-- נושא 2 -->\n            <div style=\"margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #edf2f7;\">\n                <div style=\"display: table; width: 100%; margin-bottom: 8px;\">\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: right; font-weight: 600; font-size: 15px;\">\n                        {{ $('AI Agent').item.json.output.hotTopics[1].topic }}\n                    </div>\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: left; white-space: nowrap;\">\n                        <div style=\"display: inline-block; background-color: #edf2f7; border-radius: 30px; padding: 4px 12px; font-size: 13px; color: #4a5568; text-align: center;\">\n                            <strong>{{ $('AI Agent').item.json.output.hotTopics[1].article_count }}</strong> מאמרים\n                        </div>\n                    </div>\n                </div>\n                <div style=\"background-color: #e2e8f0; height: 4px; width: 100%; border-radius: 2px; overflow: hidden;\">\n                    <div style=\"background-color: #4299e1; height: 100%; width: calc({{ $('AI Agent').item.json.output.hotTopics[1].average_relevance }} * 100%);\"></div>\n                </div>\n                <div style=\"text-align: left; font-size: 12px; color: #718096; margin-top: 4px;\">רלוונטיות: {{ $('AI Agent').item.json.output.hotTopics[1].average_relevance }}</div>\n            </div>\n            \n            <!-- נושא 3 -->\n            <div style=\"margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #edf2f7;\">\n                <div style=\"display: table; width: 100%; margin-bottom: 8px;\">\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: right; font-weight: 600; font-size: 15px;\">\n                        {{ $('AI Agent').item.json.output.hotTopics[2].topic }}\n                    </div>\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: left; white-space: nowrap;\">\n                        <div style=\"display: inline-block; background-color: #edf2f7; border-radius: 30px; padding: 4px 12px; font-size: 13px; color: #4a5568; text-align: center;\">\n                            <strong>{{ $('AI Agent').item.json.output.hotTopics[2].article_count }}</strong> מאמרים\n                        </div>\n                    </div>\n                </div>\n                <div style=\"background-color: #e2e8f0; height: 4px; width: 100%; border-radius: 2px; overflow: hidden;\">\n                    <div style=\"background-color: #4299e1; height: 100%; width: calc({{ $('AI Agent').item.json.output.hotTopics[2].average_relevance }} * 100%);\"></div>\n                </div>\n                <div style=\"text-align: left; font-size: 12px; color: #718096; margin-top: 4px;\">רלוונטיות: {{ $('AI Agent').item.json.output.hotTopics[2].average_relevance }}</div>\n            </div>\n            \n            <!-- נושא 4 -->\n            <div style=\"margin-bottom: 15px; padding-bottom: 15px; border-bottom: 1px solid #edf2f7;\">\n                <div style=\"display: table; width: 100%; margin-bottom: 8px;\">\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: right; font-weight: 600; font-size: 15px;\">\n                        {{ $('AI Agent').item.json.output.hotTopics[3].topic }}\n                    </div>\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: left; white-space: nowrap;\">\n                        <div style=\"display: inline-block; background-color: #edf2f7; border-radius: 30px; padding: 4px 12px; font-size: 13px; color: #4a5568; text-align: center;\">\n                            <strong>{{ $('AI Agent').item.json.output.hotTopics[3].article_count }}</strong> מאמרים\n                        </div>\n                    </div>\n                </div>\n                <div style=\"background-color: #e2e8f0; height: 4px; width: 100%; border-radius: 2px; overflow: hidden;\">\n                    <div style=\"background-color: #4299e1; height: 100%; width: calc({{ $('AI Agent').item.json.output.hotTopics[3].average_relevance }} * 100%);\"></div>\n                </div>\n                <div style=\"text-align: left; font-size: 12px; color: #718096; margin-top: 4px;\">רלוונטיות: {{ $('AI Agent').item.json.output.hotTopics[3].average_relevance }}</div>\n            </div>\n            \n            <!-- נושא 5 -->\n            <div style=\"margin-bottom: 0;\">\n                <div style=\"display: table; width: 100%; margin-bottom: 8px;\">\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: right; font-weight: 600; font-size: 15px;\">\n                        {{ $('AI Agent').item.json.output.hotTopics[4].topic }}\n                    </div>\n                    <div style=\"display: table-cell; vertical-align: middle; text-align: left; white-space: nowrap;\">\n                        <div style=\"display: inline-block; background-color: #edf2f7; border-radius: 30px; padding: 4px 12px; font-size: 13px; color: #4a5568; text-align: center;\">\n                            <strong>{{ $('AI Agent').item.json.output.hotTopics[4].article_count }}</strong> מאמרים\n                        </div>\n                    </div>\n                </div>\n                <div style=\"background-color: #e2e8f0; height: 4px; width: 100%; border-radius: 2px; overflow: hidden;\">\n                    <div style=\"background-color: #4299e1; height: 100%; width: calc({{ $('AI Agent').item.json.output.hotTopics[4].average_relevance }} * 100%);\"></div>\n                </div>\n                <div style=\"text-align: left; font-size: 12px; color: #718096; margin-top: 4px;\">רלוונטיות: {{ $('AI Agent').item.json.output.hotTopics[4].average_relevance }}</div>\n            </div>\n        </div>\n    </div>\n\t        \n        <!-- פוטר -->\n        <div style=\"background-color: #f8fafc; padding: 25px 40px; text-align: center; border-top: 1px solid #edf2f7;\">\n            <div style=\"font-size: 13px; color: #718096; line-height: 1.6;\">\n                <p style=\"margin: 0 0 8px 0;\">דוח זה נוצר באופן אוטומטי ואינו מהווה המלצת השקעה.</p>\n                <p style=\"margin: 0;\">יש להתייעץ עם יועץ השקעות מורשה לפני קבלת החלטות השקעה.</p>\n            </div>\n            <div style=\"margin-top: 20px;\">\n                נבנה ב-❤️ ע\"י <a href=\"https://www.linkedin.com/in/elay-g\" style=\"display: inline-block; text-decoration: none;\">עילי גז</a>\n            </div>\n        </div>\n        \n    </div>\n\n</body>\n</html>"},"typeVersion":1.2},{"id":"84a2fe62-e936-49ca-83d6-a02371e02166","name":"Send Stock Analysis","type":"n8n-nodes-base.emailSend","position":[2280,-100],"webhookId":"0de4d8cd-3519-4a4a-a05b-a9c973b64141","parameters":{"html":"={{ $json.html }}","options":{},"subject":"=הסקירה היומית של מניית {{ $('AI Agent').item.json.output.stockSymbol }}: {{ $('AI Agent').item.json.output.analysisDate }}","toEmail":"={{ $('On form submission').item.json[\"Email:\"] }}","fromEmail":"Elay's AI Assistant <elayguez@gmail.com>"},"credentials":{"smtp":{"id":"583PMpoYf46gbncd","name":"SMTP account"}},"executeOnce":false,"typeVersion":2.1},{"id":"36943e20-b0fc-40b0-b695-e0bdbd9182d1","name":"Adjust HTML Colors","type":"n8n-nodes-base.code","position":[2080,-100],"parameters":{"jsCode":"// New function to remove topics with only one article - ultra-simple approach\nfunction removeSingleArticleTopics(html) {\n  // First, see if there are any topics with exactly 1 article\n  if (!html.includes('<strong>1</strong> מאמרים')) {\n    console.log('No topics with 1 article found');\n    return html;\n  }\n\n  // Find each line that contains the \"נושא\" comment\n  // and check if it has exactly 1 article mentioned\n  const lines = html.split('\\n');\n  const linesToRemove = [];\n\n  // For each line containing \"1 מאמרים\", find the topic it belongs to\n  for (let i = 0; i < lines.length; i++) {\n    if (lines[i].includes('<strong>1</strong> מאמרים')) {\n      console.log(`Found line ${i} with 1 article mention`);\n      \n      // Go back to find the start of this topic\n      let startLine = -1;\n      for (let j = i; j >= 0; j--) {\n        if (lines[j].includes('<!-- נושא') || \n            lines[j].includes('<div style=\"margin-bottom: 15px; padding-bottom: 15px; border-bottom:')) {\n          startLine = j;\n          break;\n        }\n      }\n      \n      if (startLine === -1) {\n        console.log(`Couldn't find start of topic for line ${i}`);\n        continue;\n      }\n      \n      // Go forward to find the end of this topic\n      let endLine = -1;\n      let divCount = 0;\n      for (let j = startLine; j < lines.length; j++) {\n        // Count opening divs\n        const openMatches = lines[j].match(/<div/g);\n        if (openMatches) {\n          divCount += openMatches.length;\n        }\n        \n        // Count closing divs\n        const closeMatches = lines[j].match(/<\\/div>/g);\n        if (closeMatches) {\n          divCount -= closeMatches.length;\n        }\n        \n        // When divCount returns to 0, we've found the end\n        if (divCount === 0 && j > startLine) {\n          endLine = j;\n          break;\n        }\n      }\n      \n      if (endLine === -1) {\n        console.log(`Couldn't find end of topic for line ${i}`);\n        continue;\n      }\n      \n      // Now we have the start and end lines of the topic\n      console.log(`Found topic from line ${startLine} to ${endLine}`);\n      \n      // Mark these lines for removal\n      for (let j = startLine; j <= endLine; j++) {\n        linesToRemove.push(j);\n      }\n    }\n  }\n  \n  // Remove the marked lines\n  const newLines = [];\n  for (let i = 0; i < lines.length; i++) {\n    if (!linesToRemove.includes(i)) {\n      newLines.push(lines[i]);\n    }\n  }\n  \n  console.log(`Removed ${linesToRemove.length} lines in total`);\n  return newLines.join('\\n');\n}// Code for updating colors according to sentiment - for n8n\n\n// Define colors by sentiment type\nconst colors = {\n  positive: {\n    main: '#29cc7a',          // Green\n    background: 'rgba(41, 204, 122, 0.15)',\n    gradient: 'rgba(41, 204, 122, 0.07)',\n    accent: 'rgba(41, 204, 122, 0.1)'\n  },\n  neutral: {\n    main: '#f7b955',          // Orange\n    background: 'rgba(247, 185, 85, 0.15)',\n    gradient: 'rgba(247, 185, 85, 0.07)',\n    accent: 'rgba(247, 185, 85, 0.1)'\n  },\n  negative: {\n    main: '#f55e5e',          // Red\n    background: 'rgba(245, 94, 94, 0.15)',\n    gradient: 'rgba(245, 94, 94, 0.07)',\n    accent: 'rgba(245, 94, 94, 0.1)'\n  }\n};\n\n// Function to identify sentiment type from text\nfunction getSentimentType(text) {\n  if (!text) return 'neutral';\n  \n  const lowerText = text.toLowerCase();\n  \n  // Negative keywords - check first because there are expressions with both \"positive\" and \"negative\" together\n  if (lowerText.includes('שלילי') || lowerText.includes('negative') || \n      lowerText.includes('bearish') || lowerText.includes('ירידה') || \n      lowerText.includes('דובי') || lowerText.includes('מכירה') || \n      lowerText.includes('שלילי-חזק') || lowerText.includes('שלילי-חלש') ||\n      lowerText.includes('שלילית')) {\n    return 'negative';\n  }\n  \n  // Positive keywords\n  if (lowerText.includes('חיובי') || lowerText.includes('positive') || \n      lowerText.includes('bullish') || lowerText.includes('עלייה') || \n      lowerText.includes('שורי') || lowerText.includes('קנייה') || \n      lowerText.includes('חיובי-חזק') || lowerText.includes('חיובי-חלש') ||\n      lowerText.includes('חיובית')) {\n    return 'positive';\n  }\n  \n  // Additional check for expressions containing only \"strong\" or \"weak\"\n  if (lowerText.includes('חזק')) {\n    // If no negative word, assume it's positive\n    return 'positive';\n  }\n  \n  // Default - neutral\n  return 'neutral';\n}\n\n// Function to check if a specific text belongs to a sentiment - used for bug fixing\nfunction debugSentiment(text) {\n  console.log(`Sentiment check: \"${text}\" => ${getSentimentType(text)}`);\n}\n\n// New function to remove undefined articles from HTML\nfunction removeUndefinedArticles(html) {\n  // Find all article blocks\n  const articleBlocksRegex = /<tr>\\s*<td style=\"padding-bottom: 16px;\">\\s*<table[^>]*>[\\s\\S]*?<\\/table>\\s*<\\/td>\\s*<\\/tr>/g;\n  const articleBlocks = Array.from(html.matchAll(articleBlocksRegex));\n  \n  // No articles found\n  if (!articleBlocks || articleBlocks.length === 0) {\n    console.log(\"No article blocks found\");\n    return html;\n  }\n  \n  // Function to check if an article is fully undefined\n  function isFullyUndefinedArticle(articleHtml) {\n    // An article is considered fully undefined if:\n    // 1. It has href=\"undefined\"\n    // 2. It has link text that is \"undefined\"\n    // 3. It has \"undefined | undefined\" (source and date)\n    return articleHtml.includes('href=\"undefined\"') && \n           articleHtml.includes('>undefined</a>') &&\n           articleHtml.includes('undefined | undefined');\n  }\n  \n  // Identify blocks to remove\n  const blocksToRemove = [];\n  for (const match of articleBlocks) {\n    const block = match[0];\n    if (isFullyUndefinedArticle(block)) {\n      console.log(\"Found undefined article, will remove\");\n      blocksToRemove.push(match);\n    } else {\n      console.log(\"Found valid article, keeping it\");\n    }\n  }\n  \n  // If no blocks to remove, return original HTML\n  if (blocksToRemove.length === 0) {\n    console.log(\"No undefined articles found to remove\");\n    return html;\n  }\n  \n  console.log(`Found ${blocksToRemove.length} undefined articles to remove`);\n  \n  // Create a new string by removing the matches from end to start (to avoid index shifting)\n  let cleanedHtml = html;\n  for (let i = blocksToRemove.length - 1; i >= 0; i--) {\n    const match = blocksToRemove[i];\n    cleanedHtml = cleanedHtml.slice(0, match.index) + cleanedHtml.slice(match.index + match[0].length);\n  }\n  \n  return cleanedHtml;\n}\n\n// Get the HTML from the specified parameter\nconst html = $input.first().json.html;\nlet updatedHtml = html;\n\n// Bug checks - check several keywords\ndebugSentiment(\"חיובי\");\ndebugSentiment(\"שלילי\");\ndebugSentiment(\"נייטרלי\");\ndebugSentiment(\"חיובי-חזק\");\ndebugSentiment(\"שלילי-חזק\");\ndebugSentiment(\"חיובי-חלש\");\ndebugSentiment(\"שלילי-חלש\");\n\n// 1. Update colors in the recommendation title\nconst titleMatch = html.match(/<h2 style=\"[^\"]*color: #[a-f0-9]+;[^\"]*\">([^<]+)<\\/h2>/i);\nif (titleMatch) {\n  const titleText = titleMatch[1].trim();\n  const titleSentiment = getSentimentType(titleText);\n  \n  // Update title color\n  updatedHtml = updatedHtml.replace(\n    /(<h2 style=\"[^\"]*color: )#[a-f0-9]+(;[^\"]*\">)/i,\n    `$1${colors[titleSentiment].main}$2`\n  );\n  \n  // Update side bar color\n  updatedHtml = updatedHtml.replace(\n    /(<div style=\"position: absolute; right: 0; top: 0; bottom: 0; width: 6px; background-color: )#[a-f0-9]+(;\"><\\/div>)/i,\n    `$1${colors[titleSentiment].main}$2`\n  );\n  \n  // Update gradient color\n  updatedHtml = updatedHtml.replace(\n    /(<div style=\"position: absolute; right: 0; top: 0; width: 100%; height: 100%; background: linear-gradient\\(90deg, )rgba\\([^)]+\\)( 0%, )rgba\\([^)]+\\)( 50%\\);\"><\\/div>)/i,\n    `$1${colors[titleSentiment].gradient}$2${colors[titleSentiment].gradient.replace('0.07', '0')}$3`\n  );\n  \n  // Update icon background color\n  updatedHtml = updatedHtml.replace(\n    /(<div style=\"display: inline-block; width: 40px; height: 40px; border-radius: 50%; margin-bottom: 10px; background-color: )rgba\\([^)]+\\)(; text-align: center;\">)/i,\n    `$1${colors[titleSentiment].background}$2`\n  );\n}\n\n// 2. Update overall sentiment color\nconst sentimentMatch = updatedHtml.match(/<span style=\"[^\"]*font-weight: 600; color: #[a-f0-9]+;[^\"]*\">([^<]+)<\\/span>/i);\nif (sentimentMatch) {\n  const sentimentText = sentimentMatch[1].trim();\n  const sentimentType = getSentimentType(sentimentText);\n  \n  updatedHtml = updatedHtml.replace(\n    /(<span style=\"[^\"]*font-weight: 600; color: )#[a-f0-9]+(;[^\"]*\">)/i,\n    `$1${colors[sentimentType].main}$2`\n  );\n}\n\n// 3. Update article colors\nconst articleBlocks = updatedHtml.match(/<tr>\\s*<td style=\"padding-bottom: 16px;\">\\s*<table[^>]*>[\\s\\S]*?<\\/table>\\s*<\\/td>\\s*<\\/tr>/g);\nif (articleBlocks) {\n  for (const block of articleBlocks) {\n    // Check if this is a fully undefined article before skipping\n    const isUndefined = block.includes('href=\"undefined\"') && \n                        block.includes('>undefined</a>') && \n                        block.includes('undefined | undefined');\n    \n    // Skip if this is a completely undefined article\n    if (isUndefined) {\n      console.log(\"Skipping color update for undefined article\");\n      continue;\n    }\n    \n    // Find sentiment within the block\n    const articleSentimentMatch = block.match(/<div style=\"[^\"]*padding: 3px 10px;[^\"]*\">([^<]+)<\\/div>/i);\n    if (articleSentimentMatch) {\n      const articleSentimentText = articleSentimentMatch[1].trim();\n      const articleSentimentType = getSentimentType(articleSentimentText);\n      \n      // Debug check - log the identified sentiment\n      debugSentiment(articleSentimentText);\n      \n      // Create updated block\n      let updatedBlock = block;\n      \n      // Update side line color\n      updatedBlock = updatedBlock.replace(\n        /(<td width=\"4\" style=\"background-color: )#[a-f0-9]+(;\"><\\/td>)/i,\n        `$1${colors[articleSentimentType].main}$2`\n      );\n      \n      // Update sentiment tag colors (background and text color)\n      updatedBlock = updatedBlock.replace(\n        /(<div style=\"[^\"]*background-color: )rgba\\([^)]+\\)(; color: )#[a-f0-9]+(;[^\"]*\">)/i,\n        `$1${colors[articleSentimentType].accent}$2${colors[articleSentimentType].main}$3`\n      );\n      \n      // Replace the block with its updated version\n      updatedHtml = updatedHtml.replace(block, updatedBlock);\n    }\n  }\n}\n\n// 4. Update recommendation button color\nconst buttonMatch = updatedHtml.match(/<a style=\"[^\"]*background-color: #[a-f0-9]+;[^\"]*\">([^<]+)<\\/a>/i);\nif (buttonMatch) {\n  const buttonText = buttonMatch[1].trim();\n  let buttonSentiment = 'neutral'; // Default\n  \n  // Determine sentiment based on button text\n  if (buttonText.includes(\"ממליץ לקנות\")) {\n    buttonSentiment = 'positive';\n  } else if (buttonText.includes(\"ממליץ למכור\")) {\n    buttonSentiment = 'negative';\n  } else if (buttonText.includes(\"ממליץ לחכות\")) {\n    buttonSentiment = 'neutral';\n  }\n  \n  // Update button background color\n  updatedHtml = updatedHtml.replace(\n    /(<a style=\"[^\"]*background-color: )#[a-f0-9]+(;[^\"]*\">)/i,\n    `$1${colors[buttonSentiment].main}$2`\n  );\n  \n  // Update box-shadow color\n  const boxShadowRgba = `rgba(${parseInt(colors[buttonSentiment].main.substring(1, 3), 16)}, ${parseInt(colors[buttonSentiment].main.substring(3, 5), 16)}, ${parseInt(colors[buttonSentiment].main.substring(5, 7), 16)}, 0.25)`;\n  updatedHtml = updatedHtml.replace(\n    /(box-shadow: 0 4px 6px )rgba\\([^)]+\\)(;[^\"]*\">)/i,\n    `$1${boxShadowRgba}$2`\n  );\n}\n\n// 5. Remove undefined articles\nupdatedHtml = removeUndefinedArticles(updatedHtml);\n\n// 6. Remove topics with only one article\nupdatedHtml = removeSingleArticleTopics(updatedHtml);\n\n// Return updated HTML\nreturn { html: updatedHtml };"},"typeVersion":2},{"id":"d9174ea1-e42b-4533-98ab-9dc8f94055db","name":"Think","type":"@n8n/n8n-nodes-langchain.toolThink","position":[1680,140],"parameters":{},"typeVersion":1},{"id":"ca2820e9-553d-477b-9084-74b2fab92cc9","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[940,260],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace OpenAI Credentials"},"typeVersion":1},{"id":"2e0013ca-2dda-425c-b6d8-bdd3b3cd262d","name":"Generate Variables For API","type":"n8n-nodes-base.code","position":[2760,-20],"parameters":{"jsCode":"// Function to generate yesterday's date in the required format\nfunction getYesterdayDateFormat() {\n  // Create a current date object\n  const today = new Date();\n  \n  // Set the date to the previous day (yesterday)\n  today.setDate(today.getDate() - 1);\n  \n  // Reset hours, minutes, seconds and milliseconds to 00:00:00.000\n  today.setHours(0, 0, 0, 0);\n  \n  // Extract components\n  const year = today.getFullYear();\n  const month = String(today.getMonth() + 1).padStart(2, '0'); // Months in JS start from 0\n  const day = String(today.getDate()).padStart(2, '0');\n  const hours = String(today.getHours()).padStart(2, '0');\n  const minutes = String(today.getMinutes()).padStart(2, '0');\n  \n  // Build the string in the required format\n  return `${year}${month}${day}T${hours}${minutes}`;\n}\n// Calculate the date\nconst yesterdayDate = getYesterdayDateFormat();\n// Return the result in the format required by n8n - array of objects\nreturn [\n  {\n    json: {\n      wanted_date: yesterdayDate\n    }\n  }\n];"},"typeVersion":2},{"id":"a3d8d689-7b9a-4d45-9a9b-ffb9597606a1","name":"Set Variables","type":"n8n-nodes-base.set","position":[2920,-20],"parameters":{"values":{"number":[{"name":"wantedDate","value":"={{ $json.wanted_date }}"}],"string":[{"name":"stockSymbol","value":"={{ $('Workflow Input Trigger').item.json.ticker }}"},{"name":"apikey"}]},"options":{}},"typeVersion":2},{"id":"f4eeb758-ba3e-4fb2-882f-7422bdcdc30b","name":"Get News Data","type":"n8n-nodes-base.httpRequest","position":[3100,-20],"parameters":{"url":"=https://www.alphavantage.co/query?function=NEWS_SENTIMENT&tickers={{ $json.stockSymbol }}&sort=RELEVANCE&time_from={{ $json.wantedDate }}&apikey={{ $json.apikey }}","options":{}},"typeVersion":4.1},{"id":"87a2eb36-36e2-427d-8db2-2de3a280e404","name":"Analyse API Input","type":"n8n-nodes-base.code","position":[3280,-20],"parameters":{"jsCode":"/**\n * Custom code for n8n Code node to analyze news data from Alpha Vantage\n * \n * - The code receives API data from the previous node\n * - Analyzes sentiment, leading articles, and hot topics\n * - Returns a structured JSON object for further processing\n */\n\nconst stockSymbol = $('Set Variables').first().json.stockSymbol\nconst allNews = $input.first().json.feed\n  ;\nconst today = new Date().toISOString().split('T')[0]; // Current date in YYYY-MM-DD format\n\n// Filter articles relevant to the stock\nconst relevantArticles = allNews.filter(article => {\n  return article.ticker_sentiment && article.ticker_sentiment.some(ticker => \n    ticker.ticker === stockSymbol\n  );\n});\n\n// Sentiment analysis\nlet sentimentCounts = {\n  \"Bullish\": 0,\n  \"Somewhat-Bullish\": 0,\n  \"Neutral\": 0,\n  \"Somewhat-Bearish\": 0,\n  \"Bearish\": 0\n};\n\nlet totalSentimentScore = 0;\nlet totalRelevanceScore = 0;\n\nrelevantArticles.forEach(article => {\n  const stockTicker = article.ticker_sentiment.find(ticker => ticker.ticker === stockSymbol);\n  if (stockTicker) {\n    sentimentCounts[stockTicker.ticker_sentiment_label]++;\n    totalSentimentScore += parseFloat(stockTicker.ticker_sentiment_score) * parseFloat(stockTicker.relevance_score);\n    totalRelevanceScore += parseFloat(stockTicker.relevance_score);\n  }\n});\n\nconst avgSentimentScore = totalRelevanceScore > 0 ? totalSentimentScore / totalRelevanceScore : 0;\n\n// Determining overall sentiment\nlet overallSentiment;\nif (avgSentimentScore >= 0.35) {\n  overallSentiment = \"חיובי מאוד\";\n} else if (avgSentimentScore >= 0.15) {\n  overallSentiment = \"חיובי\";\n} else if (avgSentimentScore > -0.15) {\n  overallSentiment = \"נייטרלי\";\n} else if (avgSentimentScore > -0.35) {\n  overallSentiment = \"שלילי\";\n} else {\n  overallSentiment = \"שלילי מאוד\";\n}\n\n// Most influential articles\nconst topArticles = relevantArticles\n  .map(article => {\n    const stockTicker = article.ticker_sentiment.find(ticker => ticker.ticker === stockSymbol);\n    return {\n      title: article.title,\n      url: article.url,\n      source: article.source,\n      date: formatDate(article.time_published),\n      sentiment_label: stockTicker ? stockTicker.ticker_sentiment_label : \"N/A\",\n      sentiment_score: stockTicker ? parseFloat(stockTicker.ticker_sentiment_score) : 0,\n      relevance_score: stockTicker ? parseFloat(stockTicker.relevance_score) : 0,\n      impact_score: stockTicker ? Math.abs(parseFloat(stockTicker.ticker_sentiment_score) * parseFloat(stockTicker.relevance_score)) : 0\n    };\n  })\n  .sort((a, b) => b.impact_score - a.impact_score)\n  .slice(0, 5);\n\n// Analysis of main topics\nconst topicsMap = {};\n\nrelevantArticles.forEach(article => {\n  if (article.topics) {\n    article.topics.forEach(topic => {\n      if (!topicsMap[topic.topic]) {\n        topicsMap[topic.topic] = {\n          count: 0,\n          relevance: 0\n        };\n      }\n      topicsMap[topic.topic].count++;\n      topicsMap[topic.topic].relevance += parseFloat(topic.relevance_score);\n    });\n  }\n});\n\nconst hotTopics = Object.entries(topicsMap)\n  .map(([topic, data]) => ({\n    topic,\n    article_count: data.count,\n    average_relevance: (data.relevance / data.count).toFixed(2)\n  }))\n  .sort((a, b) => b.article_count - a.article_count)\n  .slice(0, 5);\n\n// Creating result object\nconst analysisResult = {\n  stock_symbol: stockSymbol,\n  analysis_date: today,\n  sentiment_analysis: {\n    overall_sentiment: overallSentiment,\n    sentiment_score: parseFloat(avgSentimentScore.toFixed(4)),\n    sentiment_distribution: sentimentCounts\n  },\n  top_articles: topArticles.map(article => ({\n    title: article.title,\n    source: article.source,\n    url: article.url,\n    date: article.date,\n    sentiment: article.sentiment_label,\n    impact_score: article.impact_score.toFixed(4)\n  })),\n  hot_topics: hotTopics,\n  recent_trends: {\n    description: getTrendDescription(overallSentiment, hotTopics),\n    market_outlook: getMarketOutlook(overallSentiment)\n  }\n};\n\n// Helper functions\nfunction formatDate(dateStr) {\n  if (!dateStr) return \"N/A\";\n  \n  try {\n    // Format: 20250418T152049 -> 2025-04-18\n    const year = dateStr.substring(0, 4);\n    const month = dateStr.substring(4, 6);\n    const day = dateStr.substring(6, 8);\n    return `${year}-${month}-${day}`;\n  } catch (e) {\n    return dateStr;\n  }\n}\n\nfunction getTrendDescription(sentiment, topics) {\n  let description = \"\";\n  \n  if (sentiment === \"חיובי מאוד\" || sentiment === \"חיובי\") {\n    description = \"מגמה חיובית כאשר משקיעים מתמקדים בעיקר ב\";\n  } else if (sentiment === \"שלילי מאוד\" || sentiment === \"שלילי\") {\n    description = \"מגמה שלילית כאשר החששות העיקריים מתמקדים ב\";\n  } else {\n    description = \"מגמה מעורבת עם התמקדות ב\";\n  }\n  \n  if (topics.length > 0) {\n    const topThreeTopics = topics.slice(0, Math.min(3, topics.length));\n    description += topThreeTopics.map(t => t.topic).join(\", \");\n  } else {\n    description += \"מגוון נושאים\";\n  }\n  \n  return description + \".\";\n}\n\nfunction getMarketOutlook(sentiment) {\n  if (sentiment === \"חיובי מאוד\") {\n    return \"תחזית שוק חיובית מאוד. הסנטימנט הכללי מצביע על אמון משקיעים גבוה ופוטנציאל לעלייה בטווח הקצר.\";\n  } else if (sentiment === \"חיובי\") {\n    return \"תחזית שוק חיובית. ישנן אינדיקציות לאופטימיות זהירה בקרב משקיעים.\";\n  } else if (sentiment === \"נייטרלי\") {\n    return \"תחזית שוק מעורבת. קיימים כוחות מאזנים של אופטימיות ופסימיות בשוק.\";\n  } else if (sentiment === \"שלילי\") {\n    return \"תחזית שוק שלילית. ישנן דאגות בקרב משקיעים שעשויות להשפיע על המניה בטווח הקצר.\";\n  } else {\n    return \"תחזית שוק שלילית מאוד. קיימת אווירת זהירות משמעותית ונטייה למכירות.\";\n  }\n}\n\n// Return the object for further flow in n8n\nreturn {\n  json: analysisResult\n};"},"typeVersion":2},{"id":"8a108780-d2e3-4cc7-bf7f-49da726f37fd","name":"Workflow Input Trigger","type":"n8n-nodes-base.executeWorkflowTrigger","position":[740,800],"parameters":{"workflowInputs":{"values":[{"name":"ticker"},{"name":"chart_style"}]}},"typeVersion":1.1},{"id":"8491ca61-2367-401e-9ff2-4f1d90f3ce59","name":"Download Chart","type":"n8n-nodes-base.httpRequest","position":[1540,520],"parameters":{"url":"={{ $json.url }}","options":{}},"typeVersion":4.2},{"id":"1250dca0-d4d6-4890-9aa4-110cd0f0fbb6","name":"Get Chart URL","type":"n8n-nodes-base.httpRequest","position":[1320,520],"parameters":{"url":"https://api.chart-img.com/v2/tradingview/advanced-chart/storage","method":"POST","options":{"response":{"response":{"responseFormat":"json"}}},"jsonBody":"={\n  \"style\": \"candle\",\n  \"theme\": \"light\",\n  \"interval\": \"1W\",\n  \"symbol\": \"NASDAQ:{{ $json.ticker }}\",\n  \"override\": {\n    \"showStudyLastValue\": false\n  },\n  \"studies\": [\n    {\n      \"name\": \"Volume\",\n      \"forceOverlay\": true\n    },\n    {\n      \"name\": \"Moving Average Exponential\",\n      \"inputs\": {\n        \"length\": 200\n      }\n    },\n    {\n      \"name\": \"Relative Strength Index\"\n    }\n  ]\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","authentication":"genericCredentialType","genericAuthType":"httpHeaderAuth","headerParameters":{"parameters":[{"name":"Content-Type","value":"application/json"}]}},"credentials":{"httpHeaderAuth":{"id":"cnQIlBI286n0AZiU","name":"Header Auth account"}},"typeVersion":4.2},{"id":"cfc9c470-c284-4d58-b6be-260f36d3d2b7","name":"Get Price History","type":"n8n-nodes-base.httpRequest","position":[1320,800],"parameters":{"url":"=https://api.twelvedata.com/time_series","options":{"response":{"response":{"responseFormat":"json"}}},"sendQuery":true,"queryParameters":{"parameters":[{"name":"symbol","value":"={{ $json.ticker }}"},{"name":"interval","value":"1day"},{"name":"outputsize","value":"180"},{"name":"apikey","value":"={{ $json.TwelveData_API_Key }}"}]}},"typeVersion":4.1},{"id":"3974f7f8-99b3-43b2-83f3-05819cdde7b2","name":"Get Bollinger Bands","type":"n8n-nodes-base.httpRequest","position":[1320,960],"parameters":{"url":"=https://api.twelvedata.com/bbands","options":{"response":{"response":{"responseFormat":"json"}}},"sendQuery":true,"queryParameters":{"parameters":[{"name":"symbol","value":"={{ $json.ticker }}"},{"name":"interval","value":"1day"},{"name":"outputsize","value":"1"},{"name":"apikey","value":"={{ $json.TwelveData_API_Key }}"}]}},"typeVersion":4.1},{"id":"0d333729-3fe5-4253-9989-16adaf1166b8","name":"Get MACD","type":"n8n-nodes-base.httpRequest","position":[1320,1120],"parameters":{"url":"=https://api.twelvedata.com/macd","options":{"response":{"response":{"responseFormat":"json"}}},"sendQuery":true,"queryParameters":{"parameters":[{"name":"symbol","value":"={{ $json.ticker }}"},{"name":"interval","value":"1day"},{"name":"outputsize","value":"1"},{"name":"apikey","value":"={{ $json.TwelveData_API_Key }}"}]}},"typeVersion":4.1},{"id":"4bd10a52-082b-4842-91ee-ef748c6ba695","name":"Merge","type":"n8n-nodes-base.merge","position":[1820,960],"parameters":{"numberInputs":3},"typeVersion":3.1},{"id":"8061fbcf-d138-44b5-b6d7-14c7a4e5904e","name":"Calculate Support Resistance","type":"n8n-nodes-base.code","position":[1540,800],"parameters":{"jsCode":"// Get historical price data\nconst data = $input.item.json;\n\n// Check if data exists\nif (!data.values || data.values.length === 0) {\n  return { json: { error: \"No price data available\", ticker: data.meta?.symbol } };\n}\n\n// Convert prices to numbers\nconst prices = data.values.map(v => parseFloat(v.close)).reverse();\n\n// Function to calculate Fibonacci levels\nfunction calculateFibonacciLevels() {\n  // Find min and max prices\n  const max = Math.max(...prices);\n  const min = Math.min(...prices);\n  const diff = max - min;\n  \n  return {\n    level_0: min.toFixed(2),\n    level_0_236: (min + diff * 0.236).toFixed(2),\n    level_0_382: (min + diff * 0.382).toFixed(2),\n    level_0_5: (min + diff * 0.5).toFixed(2),\n    level_0_618: (min + diff * 0.618).toFixed(2),\n    level_0_786: (min + diff * 0.786).toFixed(2),\n    level_1: max.toFixed(2)\n  };\n}\n// Function to identify support and resistance levels\nfunction findSupportResistanceLevels() {\n  // We need at least 30 data points\n  if (prices.length < 30) {\n    return { support: [], resistance: [] };\n  }\n  \n  const supportLevels = [];\n  const resistanceLevels = [];\n  \n  // Check each point (except edges) if it's a local minimum or maximum\n  const lookback = 5; // how many points to check in each direction\n  \n  for (let i = lookback; i < prices.length - lookback; i++) {\n    // Check for local minimum (support)\n    let isMinimum = true;\n    for (let j = i - lookback; j < i; j++) {\n      if (prices[j] <= prices[i]) {\n        isMinimum = false;\n        break;\n      }\n    }\n    \n    for (let j = i + 1; j <= i + lookback; j++) {\n      if (prices[j] <= prices[i]) {\n        isMinimum = false;\n        break;\n      }\n    }\n    \n    if (isMinimum) {\n      supportLevels.push(prices[i]);\n    }\n    \n    // Check for local maximum (resistance)\n    let isMaximum = true;\n    for (let j = i - lookback; j < i; j++) {\n      if (prices[j] >= prices[i]) {\n        isMaximum = false;\n        break;\n      }\n    }\n    \n    for (let j = i + 1; j <= i + lookback; j++) {\n      if (prices[j] >= prices[i]) {\n        isMaximum = false;\n        break;\n      }\n    }\n    \n    if (isMaximum) {\n      resistanceLevels.push(prices[i]);\n    }\n  }\n  \n  // Sort and remove duplicates\n  const uniqueSupports = [...new Set(supportLevels)];\n  const uniqueResistances = [...new Set(resistanceLevels)];\n  \n  // Return only significant levels (up to 5 of each)\n  return {\n    support: uniqueSupports.sort((a, b) => b - a).slice(0, 5).map(p => p.toFixed(2)),\n    resistance: uniqueResistances.sort((a, b) => a - b).slice(0, 5).map(p => p.toFixed(2))\n  };\n}\n\n// Calculate levels\nconst fibonacciLevels = calculateFibonacciLevels();\nconst supportResistanceLevels = findSupportResistanceLevels();\n\n// Return information with additional stock data\nreturn {\n  json: {\n    ticker: data.meta.symbol,\n    currentPrice: parseFloat(data.values[0].close).toFixed(2),\n    fibonacci: fibonacciLevels,\n    supportResistance: supportResistanceLevels,\n    dataPoints: prices.length\n  }\n};"},"typeVersion":2},{"id":"c692581d-a41d-48ef-9a7a-0a20fbceea81","name":"Organizing Data","type":"n8n-nodes-base.code","position":[2040,960],"parameters":{"jsCode":"// Getting data from different sources\n// Checking existence of objects before trying to access them\nconst items = $input.all();\nconst fibData = $input.first().json;\n\n// Trying to locate bband and MACD data if they exist\nlet bbandsData = null;\nlet macdData = null;\n\n// Trying to check if there is data in additional items\nif (items.length > 1 && items[1] && items[1].json) {\n  bbandsData = items[1].json;\n}\n\nif (items.length > 2 && items[2] && items[2].json) {\n  macdData = items[2].json;\n}\n\n// Creating data structure for the response - ensure all fields exist\nconst result = {\n  ticker: fibData.ticker || \"לא ידוע\",\n  currentPrice: fibData.currentPrice || \"0\",\n  timestamp: new Date().toISOString(),\n  technicalAnalysis: {\n    fibonacci: fibData.fibonacci || {},\n    supportResistance: fibData.supportResistance || { support: [], resistance: [] },\n    bollingerBands: {},\n    macd: {}\n  }\n};\n\n// Adding Bollinger Bands data - only if they exist\nif (bbandsData && bbandsData.values && bbandsData.values.length > 0) {\n  const bbands = bbandsData.values[0];\n  result.technicalAnalysis.bollingerBands = {\n    upperBand: parseFloat(bbands.upper_band).toFixed(2),\n    middleBand: parseFloat(bbands.middle_band).toFixed(2),\n    lowerBand: parseFloat(bbands.lower_band).toFixed(2)\n  };\n} else if (bbandsData && bbandsData.status === \"ok\") {\n  // If returning another data format\n  result.technicalAnalysis.bollingerBands = {\n    upperBand: bbandsData.upperBand || bbandsData.upper_band || \"0\",\n    middleBand: bbandsData.middleBand || bbandsData.middle_band || \"0\",\n    lowerBand: bbandsData.lowerBand || bbandsData.lower_band || \"0\"\n  };\n}\n\n// Adding MACD data - only if they exist\nif (macdData && macdData.values && macdData.values.length > 0) {\n  const macd = macdData.values[0];\n  result.technicalAnalysis.macd = {\n    macd: parseFloat(macd.macd).toFixed(2),\n    signal: parseFloat(macd.signal).toFixed(2),\n    histogram: parseFloat(macd.hist).toFixed(2)\n  };\n} else if (macdData && macdData.status === \"ok\") {\n  // If returning another data format\n  result.technicalAnalysis.macd = {\n    macd: macdData.macd || \"0\",\n    signal: macdData.signal || \"0\",\n    histogram: macdData.histogram || macdData.hist || \"0\"\n  };\n}\n\n// Creating summary and recommendation\nlet bullishFactors = [];\nlet bearishFactors = [];\n\n// Analyzing Bollinger Bands - only if data exists\nconst bbands = result.technicalAnalysis.bollingerBands;\nif (bbands.upperBand && bbands.lowerBand) {\n  const currentPrice = parseFloat(result.currentPrice);\n  const upperBand = parseFloat(bbands.upperBand);\n  const lowerBand = parseFloat(bbands.lowerBand);\n  \n  if (!isNaN(currentPrice) && !isNaN(upperBand) && !isNaN(lowerBand)) {\n    if (currentPrice > upperBand) {\n      bearishFactors.push(\"מחיר מעל רצועת בולינגר העליונה - אפשרות לקנייה יתר\");\n    } else if (currentPrice < lowerBand) {\n      bullishFactors.push(\"מחיר מתחת לרצועת בולינגר התחתונה - אפשרות למכירה יתר\");\n    }\n  }\n}\n\n// Analyzing MACD - only if data exists\nconst macdInfo = result.technicalAnalysis.macd;\nif (macdInfo.macd && macdInfo.signal) {\n  const macd = parseFloat(macdInfo.macd);\n  const signal = parseFloat(macdInfo.signal);\n  \n  if (!isNaN(macd) && !isNaN(signal)) {\n    if (macd > signal) {\n      bullishFactors.push(\"MACD מעל קו האיתות - אינדיקציה חיובית\");\n    } else {\n      bearishFactors.push(\"MACD מתחת לקו האיתות - אינדיקציה שלילית\");\n    }\n  }\n}\n\n// Analyzing support and resistance levels - only if data exists\nconst supportResistance = result.technicalAnalysis.supportResistance;\nif (supportResistance.support && supportResistance.resistance) {\n  const currentPrice = parseFloat(result.currentPrice);\n  \n  if (!isNaN(currentPrice)) {\n    const supports = supportResistance.support.map(s => parseFloat(s)).filter(s => !isNaN(s));\n    const resistances = supportResistance.resistance.map(r => parseFloat(r)).filter(r => !isNaN(r));\n    \n    // Finding the closest support level\n    let closestSupport = null;\n    let minSupportDist = Infinity;\n    for (const support of supports) {\n      if (support < currentPrice) {\n        const dist = currentPrice - support;\n        if (dist < minSupportDist) {\n          minSupportDist = dist;\n          closestSupport = support;\n        }\n      }\n    }\n    \n    // Finding the closest resistance level\n    let closestResistance = null;\n    let minResistanceDist = Infinity;\n    for (const resistance of resistances) {\n      if (resistance > currentPrice) {\n        const dist = resistance - currentPrice;\n        if (dist < minResistanceDist) {\n          minResistanceDist = dist;\n          closestResistance = resistance;\n        }\n      }\n    }\n    \n    // Adding support/resistance analysis\n    if (closestSupport !== null) {\n      const supportPercentage = ((currentPrice - closestSupport) / currentPrice * 100).toFixed(2);\n      if (supportPercentage < 5) {\n        bullishFactors.push(`המחיר קרוב לרמת תמיכה (${supportPercentage}%) - אפשרות להיפוך כלפי מעלה`);\n      }\n    }\n    \n    if (closestResistance !== null) {\n      const resistancePercentage = ((closestResistance - currentPrice) / currentPrice * 100).toFixed(2);\n      if (resistancePercentage < 5) {\n        bearishFactors.push(`המחיר קרוב לרמת התנגדות (${resistancePercentage}%) - אפשרות להיפוך כלפי מטה`);\n      }\n    }\n  }\n}\n\n// Analyzing Fibonacci - only if data exists\nconst fibonacci = result.technicalAnalysis.fibonacci;\nif (fibonacci && Object.keys(fibonacci).length > 0) {\n  const currentPrice = parseFloat(result.currentPrice);\n  \n  if (!isNaN(currentPrice)) {\n    const fibLevels = Object.values(fibonacci).map(level => parseFloat(level)).filter(level => !isNaN(level));\n    fibLevels.sort((a, b) => a - b);\n    \n    // Checking which Fibonacci level the price is at\n    for (let i = 0; i < fibLevels.length - 1; i++) {\n      if (currentPrice >= fibLevels[i] && currentPrice <= fibLevels[i+1]) {\n        // If the price is close to a Fibonacci resistance level\n        if (Math.abs(currentPrice - fibLevels[i+1]) / currentPrice * 100 < 2) {\n          bearishFactors.push(`המחיר קרוב לרמת פיבונאצ'י ${[0, 23.6, 38.2, 50, 61.8, 78.6, 100][Math.min(i+1, 6)]}% - אפשרות להתנגדות`);\n        }\n        // If the price is close to a Fibonacci support level\n        if (Math.abs(currentPrice - fibLevels[i]) / currentPrice * 100 < 2) {\n          bullishFactors.push(`המחיר קרוב לרמת פיבונאצ'י ${[0, 23.6, 38.2, 50, 61.8, 78.6, 100][Math.min(i, 6)]}% - אפשרות לתמיכה`);\n        }\n        break;\n      }\n    }\n  }\n}\n\n// Adding general recommendation based on factors\nlet recommendation = \"\";\nif (bullishFactors.length > bearishFactors.length) {\n  recommendation = \"חיובית\";\n} else if (bearishFactors.length > bullishFactors.length) {\n  recommendation = \"שלילית\";\n} else {\n  recommendation = \"נייטרלית\";\n}\n\n// Adding summary to the result\nresult.summary = {\n  recommendation: recommendation,\n  bullishFactors: bullishFactors,\n  bearishFactors: bearishFactors\n};\n\nreturn { json: result };"},"typeVersion":2},{"id":"d00b380b-43a4-478e-8265-d79299278867","name":"Merge-2","type":"n8n-nodes-base.merge","position":[2440,800],"parameters":{"mode":"combine","options":{},"combineBy":"combineByPosition"},"typeVersion":3.1},{"id":"4ca4c3aa-9c91-4a6c-973f-bb0ed3754a82","name":"ChatGPT 4o","type":"@n8n/n8n-nodes-langchain.openAi","position":[2900,800],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"role":"system","content":"# Role\nYou are a senior technical analyst who merges visual insights with quantitative indicators.\n\n# Inputs\n1. Visual JSON from Agent 1:\n   {\n     \"ai_agent_visual_analysis\": \"...\"\n   }\n2. Technical-indicator JSON in the format:\n   {\n     \"ticker\": \"...\",\n     \"currentPrice\": \"...\",\n     \"timestamp\": \"...\",\n     \"technicalAnalysis\": {\n       \"fibonacci\": { ... },\n       \"supportResistance\": { ... },\n       \"bollingerBands\": { ... },\n       \"macd\": { ... }\n     },\n     \"summary\": { ... }\n   }\n\n# Expected Sections\nWrite five titled sections exactly in this order:\n\n1. Quick Stats  \n   - Ticker, current price, timestamp  \n   - Overall recommendation from technical JSON, if present\n\n2. Candles and EMA  \n   - Use Agent 1 data: trendDirection, candlestickPatterns, emaRelation, volumeNotes\n\n3. RSI  \n   - Report rsiNumeric and rsiState from Agent 1  \n   - Mention rsiDivergence and its implication\n\n4. Indicator Synthesis  \n   - Fibonacci – cite closest level above and below price  \n   - Bollinger Bands – quote upper, middle, lower and note price position  \n   - MACD – quote macd, signal, histogram, note cross or momentum if numbers are valid  \n   - Support-Resistance – use technicalAnalysis plus priceZones from Agent 1 to highlight the nearest levels\n\n5. Actionable Takeaway  \n   - One sentence bias (bullish, bearish, neutral)  \n   - Clear next step such as watch for break above X or pullback to Y\n\n# Style Rules\n- Be concise and strictly data driven  \n- Every statement must reference either a value from the inputs or a specific visual observation from Agent 1  \n- No speculation beyond supplied data  \n- End after the Takeaway section – output nothing else"},{"content":"={{ $json.textPayload }}"}]}},"credentials":{"openAiApi":{"id":"2m1HH5crgPAhTJlv","name":"OpenAi account"}},"typeVersion":1.8},{"id":"d46f175b-0737-4e33-b8fc-4937f0c6456e","name":"Set Variable","type":"n8n-nodes-base.set","position":[2040,520],"parameters":{"options":{},"assignments":{"assignments":[{"id":"fdf7e016-7082-4146-9038-454139023990","name":"ai_agent_visual_analysis","type":"string","value":"={{ $('First Technical Analysis').item.json.choices[0].message.content }}"}]}},"typeVersion":3.4},{"id":"186b6551-ac08-43f3-b000-9be984a4eb13","name":"Warp as JSON for GPT","type":"n8n-nodes-base.code","position":[2660,800],"parameters":{"jsCode":"/**\n * INPUT: items[0].json (Original JSON)\n * OUTPUT: { textPayload: \"```json\\n{ ... }\\n```\" }\n */\n\nconst pretty = JSON.stringify(items[0].json, null, 2);\nconst wrapped = `\\`\\`\\`json\\n${pretty}\\n\\`\\`\\``;\n\nreturn [\n  {\n    json: {\n      textPayload: wrapped\n    }\n  }\n];\n"},"typeVersion":2},{"id":"b42da048-4e0a-4e45-b6a4-9272473844cb","name":"Set Final Response","type":"n8n-nodes-base.set","position":[3280,800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"fdf7e016-7082-4146-9038-454139023990","name":"response","type":"string","value":"={{ $json.message.content }}"},{"id":"4e5afd49-67c2-40ab-bc8c-565dea3850ed","name":"image","type":"string","value":"={{ $('Download Chart').item.json.url }}"}]}},"typeVersion":3.4},{"id":"c718d0a7-2689-42da-985f-17030583e51c","name":"Set Stock Symbol and API Key","type":"n8n-nodes-base.set","position":[960,800],"parameters":{"options":{},"assignments":{"assignments":[{"id":"cf5f7210-5b54-4f4a-abf7-87873be82df4","name":"ticker","type":"string","value":"={{ $json.ticker }}"},{"id":"9f008c4b-60e2-4d99-a119-b0170ec28358","name":"TwelveData_API_Key","type":"string","value":""}]}},"typeVersion":3.4},{"id":"884a7e3b-3e8f-4c69-8950-5b0f1dd25f29","name":"First Technical Analysis","type":"@n8n/n8n-nodes-langchain.openAi","position":[1820,520],"parameters":{"text":"=# Role\nYou are a visual chart analyst.  \nYour only input is a weekly candlestick chart image that shows:\n- Price candles and volume bars  \n- One short-term EMA line  \n- An RSI panel with its live value  \n\n# Task\nInspect the image and produce a **structured JSON** object with the following keys:\n\n{\n  \"rsiNumeric\": number,          // exact RSI value from the chart\n  \"rsiState\": \"overbought\" | \"oversold\" | \"neutral\",\n  \"rsiDivergence\": \"bullish\" | \"bearish\" | \"none\",\n  \"trendDirection\": \"up\" | \"down\" | \"sideways\",\n  \"candlestickPatterns\": [ \"pattern1\", \"pattern2\", ... ],   // max 3\n  \"emaRelation\": \"aboveEMA\" | \"belowEMA\" | \"testingEMA\",\n  \"volumeNotes\": \"string\",        // brief comment on recent volume behavior\n  \"priceZones\": {                 // visually inferred areas\n      \"potentialSupport\": [number, ...],  // up to 2 levels taken from visible lows\n      \"potentialResistance\": [number, ...]// up to 2 levels taken from visible highs\n  }\n}\n\n# Style Rules\n- Derive every value only from what is visible in the chart\n- Do not mention any external data or speculation\n- Return the JSON object only, nothing else\n","modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{"detail":"auto"},"resource":"image","simplify":false,"inputType":"base64","operation":"analyze"},"credentials":{"openAiApi":{"id":"2m1HH5crgPAhTJlv","name":"OpenAi account"}},"typeVersion":1.8},{"id":"ba7aca23-5d4c-4bfd-8d7f-af45aaa8d8a0","name":"Schedule Trigger1","type":"n8n-nodes-base.scheduleTrigger","position":[2560,-20],"parameters":{"rule":{"interval":[{}]}},"typeVersion":1.2},{"id":"4b93b4ba-3369-4051-a92d-d3ff811fb566","name":"Technical Analysis Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[1360,140],"parameters":{"name":"technical_analysis","workflowId":{"__rl":true,"mode":"list","value":"GDXsoM9kWq3cz53Y","cachedResultName":"technical_analysis"},"description":"Call this tool to get an analysis of a requested stock. It'll be obligatory to pass ticker.","workflowInputs":{"value":{"ticker":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('ticker', ``, 'string') }}"},"schema":[{"id":"ticker","type":"string","display":true,"required":false,"displayName":"ticker","defaultMatch":false,"canBeUsedToMatch":true},{"id":"chart_style","type":"string","display":true,"removed":true,"required":false,"displayName":"chart_style","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2},{"id":"c5d70195-f90b-42b4-b056-52794c75c20f","name":"Trends Analysis Tool","type":"@n8n/n8n-nodes-langchain.toolWorkflow","position":[1520,140],"parameters":{"name":"trends_analysis","workflowId":{"__rl":true,"mode":"list","value":"jnlklBcNkky9yFoc","cachedResultName":"trends_analysis"},"description":"Call this tool to get an analysis of a requested stock. It'll be obligatory to pass ticker.","workflowInputs":{"value":{"ticker":"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('ticker', ``, 'string') }}"},"schema":[{"id":"ticker","type":"string","display":true,"required":false,"displayName":"ticker","defaultMatch":false,"canBeUsedToMatch":true},{"id":"chart_style","type":"string","display":true,"removed":true,"required":false,"displayName":"chart_style","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":[],"attemptToConvertTypes":false,"convertFieldsToString":false}},"typeVersion":2},{"id":"de8355ea-8f6b-4733-b5ac-06e080e42e30","name":"Sticky Note16","type":"n8n-nodes-base.stickyNote","position":[2900,120],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace Alphavantage API Key"},"typeVersion":1},{"id":"9c25c2ab-796f-4156-8267-efe6d0182e9d","name":"Sticky Note14","type":"n8n-nodes-base.stickyNote","position":[1800,680],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace OpenAI Credentials"},"typeVersion":1},{"id":"e78394cb-809e-4731-b74b-e8378f8e2bc9","name":"Sticky Note15","type":"n8n-nodes-base.stickyNote","position":[2900,920],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace OpenAI Credentials"},"typeVersion":1},{"id":"dcf46ba4-b309-4d41-8041-717d564c0690","name":"Sticky Note17","type":"n8n-nodes-base.stickyNote","position":[1300,680],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace Chart-img API Key"},"typeVersion":1},{"id":"727d5d8b-c537-41d2-a757-479813ecb733","name":"Sticky Note19","type":"n8n-nodes-base.stickyNote","position":[920,980],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace TwelveData API Key"},"typeVersion":1},{"id":"580f36fb-2d85-4a74-825b-540f328b860f","name":"Sticky Note13","type":"n8n-nodes-base.stickyNote","position":[2280,60],"parameters":{"color":3,"width":160,"height":80,"content":"### Replace SMTP Credentials"},"typeVersion":1},{"id":"e40b611a-12c3-4975-b692-f338d0477c8b","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[220,-220],"parameters":{"color":7,"width":440,"height":300,"content":"# Advance Stock Analysis (both Technical and Trends) Using GPT4o Powered AI Agent\n\n## Built by  [Elay Guez](https://www.linkedin.com/in/elay-g)"},"typeVersion":1},{"id":"ab83de34-3083-4882-b329-c368d5818917","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[220,100],"parameters":{"color":7,"width":440,"height":1200,"content":"### Overview ###\n\nGet comprehensive stock analysis with this AI-powered workflow that provides actionable insights for your investment decisions. On a weekly basis, this workflow:\n\n- Analyzes stock data from multiple sources (Chart-img, Twelve Data API, Alphavantage)\n- Performs technical analysis using advanced indicators (RSI, MACD, Bollinger Bands, Resistance and Support Levels)\n- Scans financial news from Alpha Vantage to capture market sentiment\n- Uses OpenAI's GPT-4o to identify patterns, trends, and trading opportunities\n- Generates a fully styled, responsive HTML email (with proper RTL layout) in Hebrew\n- Sends detailed recommendations directly to your inbox\n\n**Perfect for investors, traders, and financial analysts who want data-driven stock insights - combining technical indicators with news sentiment for more informed decisions.**\n\n### Setup Instructions ###\n\n**Estimated setup time:**\n- 15 minutes\n\n**Required credentials:**\n- OpenAI API Key\n- Chart-img API Key (free tier)\n- Twelve Data API Key (free tier)\n- Alpha Vantage API Key (free tier)\n- SMTP credentials (for email delivery)\n\n**Steps:**\n\n1. Import this template into your n8n instance.\n2. Add your API keys under credentials.\n3. Configure the SMTP Email node with: Host (e.g., smtp.gmail.com), Port (465 or 587), Username (your email), Password (app-specific password or login).\n4. Activate the workflow.\n5. Fill in the Form.\n6. **Enjoy!** (Check your Spam mailbox)\n\n### Important Note: ###\nThis report is being generated automatically and does not constitute an investment recommendation. **Please consult a licensed investment advisor before making any investment decisions.**"},"typeVersion":1},{"id":"28e1e96f-e27c-4933-afee-35931241060c","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[720,-100],"webhookId":"79520027-d875-4ca3-a533-614bfca5e5b1","parameters":{"options":{"appendAttribution":true,"respondWithOptions":{"values":{"formSubmittedText":"Success! Check your inbox (or spam folder) for your analysis report."}}},"formTitle":"Advance Stock Analysis","formFields":{"values":[{"fieldLabel":"Ticker symbol:","placeholder":"TSLA","requiredField":true},{"fieldType":"email","fieldLabel":"Email:","placeholder":"youremail@gmail.com","requiredField":true}]},"responseMode":"lastNode","formDescription":"Please enter the company’s NASDAQ ticker symbol (e.g. AAPL) to get a weekly email with combined technical-and-news sentiment analysis from our AI agent"},"typeVersion":2.2},{"id":"4d9939ec-4a8e-40cb-95d2-24bbdbc27c8e","name":"Refine Text","type":"@n8n/n8n-nodes-langchain.openAi","position":[1520,-100],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-4o","cachedResultName":"GPT-4O"},"options":{},"messages":{"values":[{"content":"=\"technicalAnalysis\": {{ $json.output.technicalAnalysis }}"},{"content":"=\"recommendationText\":  {{ $json.output.recommendationText }}"},{"role":"system","content":"Ensure that the text in the \"recommendationText\" \"technicalAnalysis\" values is written in proper Hebrew, like a professional analyst.\nReturn the same JSON format, but rewrite \"recommendationText\" \"technicalAnalysis\" values better.\nשים לב שכותבים \"רצועות בולינגר\" ולא \"חגורות בולינגר\""}]},"jsonOutput":true},"credentials":{"openAiApi":{"id":"2m1HH5crgPAhTJlv","name":"OpenAi account"}},"typeVersion":1.8}],"pinData":{},"connections":{"Merge":{"main":[[{"node":"Organizing Data","type":"main","index":0}]]},"Think":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"GPT 4o":{"ai_languageModel":[[{"node":"AI Agent","type":"ai_languageModel","index":0}]]},"Merge-2":{"main":[[{"node":"Warp as JSON for GPT","type":"main","index":0}]]},"AI Agent":{"main":[[{"node":"Refine Text","type":"main","index":0}]]},"Get MACD":{"main":[[{"node":"Merge","type":"main","index":2}]]},"ChatGPT 4o":{"main":[[{"node":"Set Final Response","type":"main","index":0}]]},"Refine Text":{"main":[[{"node":"Generate HTML","type":"main","index":0}]]},"Set Variable":{"main":[[{"node":"Merge-2","type":"main","index":0}]]},"Generate HTML":{"main":[[{"node":"Adjust HTML Colors","type":"main","index":0}]]},"Get Chart URL":{"main":[[{"node":"Download Chart","type":"main","index":0}]]},"Get News Data":{"main":[[{"node":"Analyse API Input","type":"main","index":0}]]},"Set Variables":{"main":[[{"node":"Get News Data","type":"main","index":0}]]},"Download Chart":{"main":[[{"node":"First Technical Analysis","type":"main","index":0}]]},"Organizing Data":{"main":[[{"node":"Merge-2","type":"main","index":1}]]},"Get Price History":{"main":[[{"node":"Calculate Support Resistance","type":"main","index":0}]]},"Schedule Trigger1":{"main":[[{"node":"Generate Variables For API","type":"main","index":0}]]},"Adjust HTML Colors":{"main":[[{"node":"Send Stock Analysis","type":"main","index":0}]]},"On form submission":{"main":[[{"node":"AI Agent","type":"main","index":0}]]},"Get Bollinger Bands":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Trends Analysis Tool":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"Warp as JSON for GPT":{"main":[[{"node":"ChatGPT 4o","type":"main","index":0}]]},"Window Buffer Memory":{"ai_memory":[[{"node":"AI Agent","type":"ai_memory","index":0}]]},"Workflow Input Trigger":{"main":[[{"node":"Set Stock Symbol and API Key","type":"main","index":0}]]},"Technical Analysis Tool":{"ai_tool":[[{"node":"AI Agent","type":"ai_tool","index":0}]]},"First Technical Analysis":{"main":[[{"node":"Set Variable","type":"main","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"AI Agent","type":"ai_outputParser","index":0}]]},"Generate Variables For API":{"main":[[{"node":"Set Variables","type":"main","index":0}]]},"Calculate Support Resistance":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Set Stock Symbol and API Key":{"main":[[{"node":"Get Chart URL","type":"main","index":0},{"node":"Get Price History","type":"main","index":0},{"node":"Get Bollinger Bands","type":"main","index":0},{"node":"Get MACD","type":"main","index":0}]]}}}


name: Generate & Enrich LinkedIn Leads with Apollo.io, LinkedIn API, Mail.so & GPT-3.5
author_name: Joseph
author_username: mjomba
categories: []
created_at: 2025-04-29T19:44:52.069Z
updated_at: 2025-04-29T19:44:52.069Z
url: https://n8n.io/workflows/3791
scraped_at: 2025-07-06 21:16:30
description:
  Note: Now includes an Apify alternative for Rapid API (Some users can't create new accounts on Rapid API, so I have added an alternative for you. But immediately you are able to get access to Rapid API, please use that option, it returns more detailed data). *Scroll to bottom for APify setup guide*

  This n8n workflow automates LinkedIn lead generation, enrichment, and activity analysis using Apollo.io, RapidAPI, Google Sheets and Mail.so.

  Perfect for sales teams, founders, B2B marketers, and cold outreach pros who want personalized lead insights to drive better conversion rates.

  ⚙️ How This Workflow Works

  The workflow is broken down into several key steps, each designed to help you build and enrich a valuable list of LinkedIn leads:

  1. 🔑 Lead Discovery (Keyword Search via Apollo)
  Pulls leads using Apollo.io's API based on keywords, industries, or job titles.
  Saves lead name, title, company, and LinkedIn URL to your Google Sheet.
  You can replace the trigger node from the form node to a webhook, whatsapp, telegram, etc, any way for you to send over your query variables over to initiate the workflow.

  2. 🧠 Username Extraction (from LinkedIn URL)
  Extracts the LinkedIn username from profile URLs using a simple script node.
  This is required for further enrichment via RapidAPI.

  3. ✉️ Email Lookup (via Apollo User ID)
  Uses the Apollo User ID to retrieve the lead’s verified work email.
  Ensures high-quality leads with reliable contact info.
  To double check that the email is currently valid, we use the mail.so api and filter out emails that fail deliverability and mx-record check. We don't wanna risk sending emails to no longer existent addresses, right?

  4. 🧾 Profile Summary Enrichment (via RapidAPI)
  Queries the LinkedIn Data API to fetch a lead’s profile summary/bio.
  Gives you a deeper understanding of their background and expertise.

  5. 📰 Recent Activity Collection (Posts & Reposts)
  Retrieves recent posts or reposts from each lead’s profile.
  Great for tailoring outreach with reference to what they’re currently talking about.

  6. 🗂️ Leads Database Update
  All enriched data is written to the same Google Sheet.
  New columns are filled in without overwriting existing data.

  ✅ Smart Retry & Row Status Logic

  Every subworkflow includes a fail-safe mechanism to ensure:

  ✅ Each row has status columns (e.g., done, failed, pending).
  🕒 A scheduled retry workflow resets failed rows to pending after 2 weeks (customizable).
  💬 This gives failed enrichments another chance to be processed later, reducing data loss.

  📋 Google Sheets Setup

  Template 1: Apollo Leads Scraping & Enrichment  

  Template 2: Enriched Leads Database  

  Make a copy to your Drive and use.

  Columns will be filled as each subworkflow runs (email, summary, interests, etc.)

  🔐 Required API Keys

  To use this workflow, you’ll need the following credentials:

  🧩 Apollo.io
  Sign up and get your key here: Apollo.io API Keys
  ⚠️ Important: Toggle the “Master API Key” option to ON when generating your key.  
  This ensures the same key can be used for all Apollo endpoints in this workflow.

  🌐 RapidAPI (LinkedIn Data API)
  Subscribe to the API here: LinkedIn Data API on RapidAPI
  Use the key in the x-rapidapi-key header in the relevant nodes.

  ✉️ Mail.so
  Sign up and get your key here: Mail.so API


  &gt; 💡 For both APIs, set up the credentials in n8n as “Generic Credential” types.  
  This way, you won’t need to reconfigure the headers in each node.

  🛠️ Customization Options

  Modify the Apollo filters (location, industry, seniority) to target your ideal customers.
  Change retry interval in the scheduler (e.g., weekly instead of 2 weeks).
  Connect the database to your email campaign tool like Mailchimp or Instantly.ai.
  Replace the AI nodes with your desired AI agents and customize the system messages further to get desired results.

  🆕 Apify Update Guide

  To use this workflow, you’ll need the following credentials:

  Login to Apify, then open this link; https://console.apify.com/actors/2SyF0bVxmgGr8IVCZ/

  Click on integrations and scroll down to API Solutions and select "Use API endpoints". Scroll to "Run Actor synchronously and get dataset items" and copy the actor endpoint url then paste it in the placeholder inside the http node of Apify alternative flow "apify-actor-endpoint". That's it, you are set to go.


  I am available for custom n8n workflows, if you like my work, please get in touch with me on email at joseph@uppfy.com

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

workflow_json:
  {"id":"7wwY8wfZdNpL83QQ","meta":{"instanceId":"b3c467df4053d13fe31cc98f3c66fa1d16300ba750506bfd019a0913cec71ea3","templateCredsSetupCompleted":true},"name":"LinkedIn Leads Scraping & Enrichment (Main)","tags":[],"nodes":[{"id":"5d07dfa4-6e6a-41a6-a2ea-8a8787331735","name":"On form submission","type":"n8n-nodes-base.formTrigger","position":[-80,-80],"webhookId":"28ff6927-5d05-4182-910b-be2381e3b2c4","parameters":{"options":{},"formTitle":"Leads Search","formFields":{"values":[{"fieldLabel":"Job Title","requiredField":true},{"fieldLabel":"Location","requiredField":true},{"fieldType":"number","fieldLabel":"Number of Leads","requiredField":true}]}},"typeVersion":2.2},{"id":"76ade63a-7b44-4fd1-85d8-6dbacd83aca7","name":"Split Out","type":"n8n-nodes-base.splitOut","position":[360,-80],"parameters":{"options":{},"fieldToSplitOut":"people"},"typeVersion":1,"alwaysOutputData":false},{"id":"3c7b7179-a8b9-41d6-9617-8eb7af38f571","name":"Google Sheets Trigger","type":"n8n-nodes-base.googleSheetsTrigger","position":[-100,280],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"9a55977c-638f-49ae-a51f-420f71c15454","name":"OpenAI1","type":"@n8n/n8n-nodes-langchain.openAi","position":[360,280],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-3.5-turbo","cachedResultName":"GPT-3.5-TURBO"},"options":{},"messages":{"values":[{"content":"=remove the http or https://www.linkedin.com/in/ from this  {{ $json.linkedin_url }}"}]}},"credentials":{"openAiApi":{"id":"DO9F6MAeTGLeqgoF","name":"OpenAi account"}},"typeVersion":1.8},{"id":"ca4d6b69-d4cb-4aa1-89bc-f0b5555f31cd","name":"Google Sheets Trigger2","type":"n8n-nodes-base.googleSheetsTrigger","position":[-100,680],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"15422703-fa1f-42e4-8387-7d2d4f154938","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[-200,200],"parameters":{"color":3,"width":1260,"height":300,"content":"## Extract Linkedin Username \n"},"typeVersion":1},{"id":"f8ffe414-9ca9-463a-9b98-22a65a86d4c4","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[-200,-160],"parameters":{"width":1260,"height":300,"content":"## Scrape Leads from Apollo\n"},"typeVersion":1},{"id":"a09d3993-99d6-488e-8bc0-76542de7b53c","name":"Clean Data","type":"n8n-nodes-base.set","position":[600,-80],"parameters":{"options":{},"assignments":{"assignments":[{"id":"e3bfe30e-9136-4ac9-b3da-c26eb678153b","name":"id","type":"string","value":"={{ $json.id }}"},{"id":"d45c81fb-1461-45fd-be95-d5d9901d72d7","name":"name","type":"string","value":"={{ $json.name }}"},{"id":"b4b8f660-7758-4a5f-a8f6-dc8ab6355132","name":"linkedin_url","type":"string","value":"={{ $json.linkedin_url }}"},{"id":"399f533a-6e6b-4f40-8ed8-aa5dd39017cd","name":"title","type":"string","value":"={{ $json.title }}"},{"id":"227d34c5-17db-4436-b0c2-f74e5ae453f2","name":"organization","type":"string","value":"={{ $json.employment_history[0].organization_name }}"}]}},"typeVersion":3.4},{"id":"92d03853-644e-4c73-8ecf-1e216238b37f","name":"Add Leads to Google Sheet","type":"n8n-nodes-base.googleSheets","position":[840,-80],"parameters":{"columns":{"value":{"name":"={{ $json.name }}","title":"={{ $json.title }}","apollo_id":"={{ $json.id }}","linkedin_url":"={{ $json.linkedin_url }}","organization":"={{ $json.organization }}","posts_scrape_status":"unscraped","contacts_scrape_status":"pending","profile_summary_scrape":"pending","extract_username_status":"pending"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":false,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":false,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":false,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"posts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"append","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"0275f8ba-78d7-4464-bc80-ee939e9575e7","name":"Add Linkedin Username","type":"n8n-nodes-base.googleSheets","position":[720,280],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending Username Row').item.json.apollo_id }}","linkedin_username":"={{ $json.message.content }}","extract_username_status":"finished"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":false,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":false,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"phone_number","type":"string","display":true,"removed":true,"required":false,"displayName":"phone_number","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"42827be7-8727-46e6-8f12-5d517c3ce6f3","name":"Get Pending Username Row","type":"n8n-nodes-base.googleSheets","position":[140,280],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"pending","lookupColumn":"extract_username_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"ffbb16a6-020e-4825-9690-3e89a8bbbbf7","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[-200,560],"parameters":{"color":5,"width":1700,"height":360,"content":"## Get Email Address, Validate Deliverability & Update Column Status"},"typeVersion":1},{"id":"d2a1b54a-bc1b-4f63-a1a4-b9bd2017f82d","name":"Add Email Address","type":"n8n-nodes-base.googleSheets","position":[1240,600],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending Email Statuses').item.json.apollo_id }}","email_address":"={{ $json.data.email }}","contacts_scrape_status":"finished"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":false,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"7abbce6e-90fa-4ac5-9a0b-0ba2669aa77a","name":"Mark Invalid Email","type":"n8n-nodes-base.googleSheets","position":[1240,760],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending Email Statuses').item.json.apollo_id }}","contacts_scrape_status":"invalid_email"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"2e1b9e78-8953-4059-9bbd-117c78742e4b","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[1560,560],"parameters":{"color":5,"width":800,"height":360,"content":"## Update Contact Scrape Status from Invalid back to Pending"},"typeVersion":1},{"id":"dc603dc3-148c-4609-a698-eaae32832423","name":"Schedule Trigger","type":"n8n-nodes-base.scheduleTrigger","position":[1640,680],"parameters":{"rule":{"interval":[{"field":"weeks","triggerAtDay":[2],"triggerAtHour":8,"weeksInterval":4}]}},"typeVersion":1.2},{"id":"a23feccf-f6b5-4440-b12a-ea10b41f4037","name":"Get Email from Apollo","type":"n8n-nodes-base.httpRequest","position":[380,680],"parameters":{"url":"https://api.apollo.io/api/v1/people/match","method":"POST","options":{},"sendBody":true,"sendQuery":true,"sendHeaders":true,"bodyParameters":{"parameters":[{"name":"id","value":"={{ $json.apollo_id }}"}]},"queryParameters":{"parameters":[{"name":"reveal_personal_emails","value":"true"},{"name":"reveal_phone_number","value":"false"}]},"headerParameters":{"parameters":[{"name":"Cache-Control","value":"no-cache"},{"name":"accept","value":"application/json"},{"name":"x-api-key","value":"\"your_api_key\""}]}},"typeVersion":4.2},{"id":"dfd5224d-fdb6-41f2-a219-a4a8f94930cd","name":"Confirm Email Validity","type":"n8n-nodes-base.httpRequest","position":[620,680],"parameters":{"url":"=https://api.mails.so/v1/validate?email={{ $json.person.email }}","options":{},"sendHeaders":true,"headerParameters":{"parameters":[{"name":"x-mails-api-key","value":"\"your_api_key\""}]}},"typeVersion":4.2},{"id":"14fab17d-b38b-43de-a38e-c8d49afcf1d0","name":"Get Pending Email Statuses","type":"n8n-nodes-base.googleSheets","position":[140,680],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"pending","lookupColumn":"contacts_scrape_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"09a0c5eb-d098-47f1-a85c-13c93d8b5296","name":"Google Sheets Trigger3","type":"n8n-nodes-base.googleSheetsTrigger","position":[-100,1160],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"3f592a9c-f692-44c0-b5be-9c5ff1506f24","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[-200,1040],"parameters":{"color":6,"width":1920,"height":360,"content":"## Get Profile Summary & Update Status (Rapid API✅ - Primary Option)"},"typeVersion":1},{"id":"6bc025b4-b150-493b-ae38-33772cb51a76","name":"Get Profile Posts","type":"n8n-nodes-base.httpRequest","onError":"continueRegularOutput","maxTries":2,"position":[340,1640],"parameters":{"url":"https://linkedin-data-api.p.rapidapi.com/get-profile-posts","options":{},"sendQuery":true,"sendHeaders":true,"queryParameters":{"parameters":[{"name":"username","value":"={{ $json.linkedin_username }}"},{"name":"start","value":"0"}]},"headerParameters":{"parameters":[{"name":"x-rapidapi-host","value":"linkedin-data-api.p.rapidapi.com"},{"name":"x-rapidapi-key","value":"\"your_api_key\""}]}},"retryOnFail":true,"typeVersion":4.2},{"id":"758da5bf-91e9-434d-9de5-eb3e907524e1","name":"Get About Profile","type":"n8n-nodes-base.httpRequest","onError":"continueRegularOutput","maxTries":2,"position":[380,1160],"parameters":{"url":"https://linkedin-data-api.p.rapidapi.com","options":{},"sendQuery":true,"sendHeaders":true,"queryParameters":{"parameters":[{"name":"username","value":"={{ $json.linkedin_username }}"}]},"headerParameters":{"parameters":[{"name":"x-rapidapi-host","value":"linkedin-data-api.p.rapidapi.com"},{"name":"x-rapidapi-key","value":"\"your_api_key\""}]}},"retryOnFail":true,"typeVersion":4.2},{"id":"9f88649f-3c41-4624-b94f-242d94118b0b","name":"Get Pending About and Posts Rows","type":"n8n-nodes-base.googleSheets","position":[140,1160],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"pending","lookupColumn":"profile_summary_scrape"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"2e8bb4a1-5fa9-446a-8b55-bffd6ceb5648","name":"Clean Profile Data","type":"n8n-nodes-base.code","onError":"continueErrorOutput","maxTries":2,"position":[620,1160],"parameters":{"jsCode":"return [{\n  summary: $input.first().json.summary,\n  headline: $input.first().json.headline,\n  nationality: $input.first().json.geo.country,\n  languaage: $input.first().json.languages[0].name,\n  education: $input.first().json.educations[0].schoolName,\n  fieldOfStudy: $input.first().json.educations[0].fieldOfStudy,\n  employment_company: $input.first().json.position[0].companyName,\n  company_industry: $input.first().json.position[0].companyIndustry,\n  position: $input.first().json.position[0].title,\n  company_location: $input.first().json.position[0].location,\n  employment_description_1: $input.first().json.position[0].description,\n}];\n"},"retryOnFail":true,"typeVersion":2},{"id":"87aa2108-44df-4b7f-8090-f2e86cbf5bf9","name":"Google Sheets Trigger4","type":"n8n-nodes-base.googleSheetsTrigger","position":[-120,1640],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"e3318dd3-4b6a-4994-92bc-2e715f398397","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[-200,1520],"parameters":{"color":7,"width":1920,"height":360,"content":"## Get Summary of Latest Linkedin Profile Posts (Rapid API✅ - Primary Option)"},"typeVersion":1},{"id":"b1c117e8-493a-443f-912b-dbf4718c3348","name":"Get Pending About and Posts Rows1","type":"n8n-nodes-base.googleSheets","position":[100,1640],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"unscraped","lookupColumn":"posts_scrape_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"c480f3ed-f316-4dd8-877b-49191d5aa694","name":"Clean Posts Data","type":"n8n-nodes-base.code","onError":"continueErrorOutput","maxTries":2,"position":[580,1640],"parameters":{"jsCode":"const data = $input.first().json.data || [];\n\nfunction getText(post, reshared = false) {\n  if (!post) return \"\";\n  return reshared ? (post.resharedPost?.text || \"\") : (post.text || \"\");\n}\n\nfunction getDate(post) {\n  if (!post) return \"\";\n  return post.postedDate || post.postedDateTimestamp || \"\";\n}\n\nreturn [{\n  json: {\n    post_1: getText(data[0]),\n    post_1_date: getDate(data[0]),\n\n    post_2: getText(data[1]),\n    post_2_date: getDate(data[1]),\n\n    post_3: getText(data[2]),\n    post_3_date: getDate(data[2]),\n\n    post_4: getText(data[3], true),\n    post_4_date: getDate(data[3]),\n\n    post_5: getText(data[4], true),\n    post_5_date: getDate(data[4]),\n  }\n}];\n"},"retryOnFail":true,"typeVersion":2,"waitBetweenTries":3000},{"id":"88d093e7-0180-4585-b338-11f4974fa0a7","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[-200,1980],"parameters":{"color":4,"width":800,"height":360,"content":"## Update Completely Enriched Profile to Final Database"},"typeVersion":1},{"id":"a9a96a05-f135-4a19-827f-85a750bc1551","name":"Google Sheets Trigger5","type":"n8n-nodes-base.googleSheetsTrigger","position":[-120,2100],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"ef709a3f-7e75-4904-9d3e-299db8db5d60","name":"Sticky Note8","type":"n8n-nodes-base.stickyNote","position":[1780,1040],"parameters":{"color":6,"width":800,"height":360,"content":"## Update profile summary status from failed back to pending"},"typeVersion":1},{"id":"91a1eaed-8645-4eeb-8558-c28a6d55f689","name":"Schedule Trigger2","type":"n8n-nodes-base.scheduleTrigger","position":[1860,1160],"parameters":{"rule":{"interval":[{"field":"weeks","triggerAtDay":[2],"triggerAtHour":8,"weeksInterval":4}]}},"typeVersion":1.2},{"id":"f7658227-39b3-4efb-971c-f17860d20fb8","name":"get invalid email rows","type":"n8n-nodes-base.googleSheets","position":[1880,680],"parameters":{"options":{"returnFirstMatch":false},"filtersUI":{"values":[{"lookupValue":"invalid_email","lookupColumn":"contacts_scrape_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"fce87e8a-9eb3-4c86-a4e3-f93534333206","name":"update_to_pending","type":"n8n-nodes-base.googleSheets","position":[2100,680],"parameters":{"columns":{"value":{"apollo_id":"={{ $json.apollo_id }}","contacts_scrape_status":"pending"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"9583cab2-6373-4e44-b9f2-ba0e8c8871e7","name":"get_failed_profile_summary_rows","type":"n8n-nodes-base.googleSheets","position":[2100,1160],"parameters":{"options":{"returnFirstMatch":false},"filtersUI":{"values":[{"lookupValue":"failed","lookupColumn":"profile_summary_scrape"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"a09d1560-2213-46ff-9668-5e98d5051e1f","name":"update_to_pending1","type":"n8n-nodes-base.googleSheets","position":[2320,1160],"parameters":{"columns":{"value":{"apollo_id":"={{ $json.apollo_id }}","profile_summary_scrape":"pending"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":false,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"809d74c0-bb21-4651-bf52-ccb7e8fac5a6","name":"Sticky Note9","type":"n8n-nodes-base.stickyNote","position":[1760,1520],"parameters":{"color":7,"width":800,"height":360,"content":"## Update posts summary status from failed back to pending"},"typeVersion":1},{"id":"ee1a5073-87a9-4395-9c79-b56165a5325d","name":"Schedule Trigger3","type":"n8n-nodes-base.scheduleTrigger","position":[1840,1640],"parameters":{"rule":{"interval":[{"field":"weeks","triggerAtDay":[2],"triggerAtHour":8,"weeksInterval":4}]}},"typeVersion":1.2},{"id":"4a89e593-adb3-4999-bb0a-cf8cc751a76a","name":"get_failed_posts_summary_rows1","type":"n8n-nodes-base.googleSheets","position":[2080,1640],"parameters":{"options":{"returnFirstMatch":false},"filtersUI":{"values":[{"lookupValue":"failed","lookupColumn":"posts_scrape_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"369715fe-67c5-41f1-9070-af5063f80fe0","name":"Posts AI Summarizer","type":"@n8n/n8n-nodes-langchain.openAi","position":[1060,1560],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-3.5-turbo","cachedResultName":"GPT-3.5-TURBO"},"options":{},"messages":{"values":[{"content":"=Below are the most recent posts and reposts from a LinkedIn user. Summarize them collectively in no more than two short paragraphs. Focus on capturing the main themes, tone, and any recurring interests or professional concerns.\n\nAvoid listing each post separately — instead, synthesize the information into a narrative that gives a clear idea of what this person is currently focused on or passionate about.\n\nPosts: {{ $json.postsString }}\n\nKeep it insightful but brief — no more than 2 concise paragraphs."}]},"simplify":false},"credentials":{"openAiApi":{"id":"DO9F6MAeTGLeqgoF","name":"OpenAi account"}},"executeOnce":true,"typeVersion":1.8},{"id":"a571b341-1a4b-42d7-a4fc-5dd8333e3dab","name":"AI Profile Summarizer","type":"@n8n/n8n-nodes-langchain.openAi","position":[1100,1080],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-3.5-turbo","cachedResultName":"GPT-3.5-TURBO"},"options":{},"messages":{"values":[{"content":"=Please summarize the following linkedin profile data {{ $json.profileString }} for a lead I want to cold email. I want to combine this summary with another information about them to send personalied emails, so please make sure you include relevant bits in the summary"}]},"simplify":false},"credentials":{"openAiApi":{"id":"DO9F6MAeTGLeqgoF","name":"OpenAi account"}},"executeOnce":true,"typeVersion":1.8},{"id":"8a81b29d-0ffa-4418-9aec-21eb94df7d26","name":"Update Profile Summary","type":"n8n-nodes-base.googleSheets","position":[1500,1080],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows').item.json.apollo_id }}","about_linkedin_profile":"={{ $json.choices[0].message.content }}","profile_summary_scrape":"completed"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"4803c443-be3c-4578-90fc-ab78403a0913","name":"Update Posts Summary","type":"n8n-nodes-base.googleSheets","position":[1440,1560],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows1').item.json.apollo_id }}","posts_scrape_status":"scraped","recent_posts_summary":"={{ $json.choices[0].message.content }}"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":true,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":false,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"ccf8b76d-1aba-4c5a-b19e-30aac3ab682a","name":"Get Completely Enriched Profiles","type":"n8n-nodes-base.googleSheets","position":[120,2100],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"finished","lookupColumn":"contacts_scrape_status"},{"lookupValue":"completed","lookupColumn":"profile_summary_scrape"},{"lookupValue":"scraped","lookupColumn":"posts_scrape_status"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"bfe41bd1-3edc-456a-9bf4-8e88009060e4","name":"update_to_unscraped","type":"n8n-nodes-base.googleSheets","position":[2300,1640],"parameters":{"columns":{"value":{"apollo_id":"={{ $json.apollo_id }}","posts_scrape_status":"unscraped"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"0d6e42a6-8b7e-493e-b920-7cb4d3994151","name":"Append to Enriched Leads Database","type":"n8n-nodes-base.googleSheets","position":[340,2100],"parameters":{"columns":{"value":{"Position":"={{ $json.title }}","Lead Name":"={{ $json.name }}","Email Address":"={{ $json.email_address }}","Company/Organization":"={{ $json.organization }}","Recent Posts Summary":"={{ $json.recent_posts_summary }}","Linkedin Profile Summary":"={{ $json.about_linkedin_profile }}"},"schema":[{"id":"Lead Name","type":"string","display":true,"removed":false,"required":false,"displayName":"Lead Name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Email Address","type":"string","display":true,"removed":false,"required":false,"displayName":"Email Address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Company/Organization","type":"string","display":true,"removed":false,"required":false,"displayName":"Company/Organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Position","type":"string","display":true,"required":false,"displayName":"Position","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Linkedin Profile Summary","type":"string","display":true,"required":false,"displayName":"Linkedin Profile Summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"Recent Posts Summary","type":"string","display":true,"required":false,"displayName":"Recent Posts Summary","defaultMatch":false,"canBeUsedToMatch":true}],"mappingMode":"defineBelow","matchingColumns":["Email Address"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"appendOrUpdate","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1c5USULUPS-2_RdNf29cyDguuHH7A7JNwzFCjQQUJTvE/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1c5USULUPS-2_RdNf29cyDguuHH7A7JNwzFCjQQUJTvE","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1c5USULUPS-2_RdNf29cyDguuHH7A7JNwzFCjQQUJTvE/edit?usp=drivesdk","cachedResultName":"Enriched Leads Database"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"dfc1a7e4-6348-4a84-b6b9-d9f53184948e","name":"update status to failed","type":"n8n-nodes-base.googleSheets","position":[880,1240],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows').item.json.apollo_id }}","profile_summary_scrape":"failed"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":true,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"a14fce10-9a03-4005-b440-f2bb5e4c4eed","name":"Google Sheets","type":"n8n-nodes-base.googleSheets","position":[840,1720],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows1').item.json.apollo_id }}","posts_scrape_status":"failed"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":true,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"removed":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"77a48254-5972-4a41-90e9-3903219e78cc","name":"Stringify Profile Data1","type":"n8n-nodes-base.code","position":[880,1080],"parameters":{"jsCode":"const profile = items[0].json;\n\nreturn [{\n  json: {\n    profileString: JSON.stringify(profile, null, 2) // Pretty print with 2-space indentation\n  }\n}];"},"typeVersion":2},{"id":"fb8cf143-7a62-4fdc-8888-b60841354352","name":"Stringify Posts Data","type":"n8n-nodes-base.code","position":[840,1560],"parameters":{"jsCode":"const profile = items[0].json;\n\nreturn [{\n  json: {\n    postsString: JSON.stringify(profile, null, 2) // Pretty print with 2-space indentation\n  }\n}];"},"typeVersion":2},{"id":"c440d713-3371-41a5-9093-8084ecb0eabd","name":"Generate Leads with Apollo.io","type":"n8n-nodes-base.httpRequest","position":[140,-80],"parameters":{"url":"https://api.apollo.io/api/v1/mixed_people/search","method":"POST","options":{"response":{"response":{}}},"jsonBody":"={\n  \"person_locations\": [\"{{ $json.Location }}\"],\n  \"person_titles\": [\"{{ $json['Job Title'] }}\"],\n  \"page\": 1,\n  \"per_page\": {{$json['Number of Leads']}},\n  \"projection\": [\"id\", \"name\", \"linkedin_url\", \"title\"]\n}","sendBody":true,"sendHeaders":true,"specifyBody":"json","headerParameters":{"parameters":[{"name":"Cache-Control","value":"no-cache"},{"name":"accept","value":"application/json"},{"name":"x-api-key","value":"\"your_api_key\""}]}},"typeVersion":4.2},{"id":"81edf4b0-cc78-4d62-ba0d-5e655c01c824","name":"Google Sheets Trigger6","type":"n8n-nodes-base.googleSheetsTrigger","position":[2920,1380],"parameters":{"event":"rowAdded","options":{},"pollTimes":{"item":[{"mode":"everyMinute"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsTriggerOAuth2Api":{"id":"DKYpQQpUt3ceJiG4","name":"Google Sheets Trigger account"}},"typeVersion":1},{"id":"7227fad7-9799-4159-b522-d552e0c0bd44","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2840,1060],"parameters":{"color":3,"width":2040,"height":820,"content":"## Get Profile and Latest Posts Summary & Update Status (Apify Alternative - Secondary, if rapid api option doesn't work )\nSome users that dont have an account on rapid API cant sign up hence are unable to get to the api and get an api key. This alternative is tailored for you. Immediatelty you get access to rapid API, please switch back to using that one. It is more reliable in scraping detailed data. See updated [documentation](https://docs.google.com/document/d/1U0Kk0HXO-9thjPcgFPu2Jk_yMtqLTv-hZobaKIGWOxM/edit?usp=sharing)"},"typeVersion":1},{"id":"c807c49c-ddea-4d63-8d06-070c13ae34f3","name":"Get Pending About and Posts Rows2","type":"n8n-nodes-base.googleSheets","position":[3160,1380],"parameters":{"options":{"returnFirstMatch":true},"filtersUI":{"values":[{"lookupValue":"pending","lookupColumn":"profile_summary_scrape"}]},"sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"executeOnce":true,"typeVersion":4.5},{"id":"7d79491d-5ab8-4435-b655-97e81380428f","name":"Clean Profile Data1","type":"n8n-nodes-base.code","maxTries":2,"position":[3720,1280],"parameters":{"jsCode":"// Safe LinkedIn profile details scraper for n8n\nconst profileData = {};\nconst input = $input.first() && $input.first().json ? $input.first().json : {};\n\n// Basic profile information with fallbacks\nif (input.about) profileData.summary = input.about;\nif (input.headline) profileData.headline = input.headline;\nif (input.addressCountryOnly) profileData.nationality = input.addressCountryOnly;\n\n// Education information with fallbacks\nif (input.educations && Array.isArray(input.educations) && input.educations.length > 0) {\n  const education = input.educations[0];\n  if (education.title) profileData.education = education.title;\n  if (education.subtitle) profileData.fieldOfStudy = education.subtitle;\n}\n\n// Employment information with fallbacks\nif (input.experiences && Array.isArray(input.experiences) && input.experiences.length > 0) {\n  const experience = input.experiences[0];\n  if (experience.subtitle) profileData.employment_company = experience.subtitle;\n  if (experience.title) profileData.position = experience.title;\n  if (experience.metadata) profileData.company_location = experience.metadata;\n}\n\n// Return the profile data in n8n expected format\nreturn [{ json: profileData }];"},"retryOnFail":true,"typeVersion":2},{"id":"e13acd2c-5d4a-4683-9293-6520fc4da4a6","name":"Stringify Data2","type":"n8n-nodes-base.code","position":[3900,1280],"parameters":{"jsCode":"const profile = items[0].json;\n\nreturn [{\n  json: {\n    profileString: JSON.stringify(profile, null, 2) // Pretty print with 2-space indentation\n  }\n}];"},"typeVersion":2},{"id":"e774ffc5-2c4a-46fc-89a1-1ecb3ba2ef10","name":"AI Profile Summarizer1","type":"@n8n/n8n-nodes-langchain.openAi","position":[4100,1280],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-3.5-turbo","cachedResultName":"GPT-3.5-TURBO"},"options":{},"messages":{"values":[{"content":"=Please summarize the following linkedin profile data {{ $json.profileString }} for a lead I want to cold email. I want to combine this summary with another information about them to send personalied emails, so please make sure you include relevant bits in the summary"}]},"simplify":false},"credentials":{"openAiApi":{"id":"DO9F6MAeTGLeqgoF","name":"OpenAi account"}},"executeOnce":true,"typeVersion":1.8},{"id":"557a763a-8388-4f34-bd35-d91cd7018b97","name":"Update Profile Summary1","type":"n8n-nodes-base.googleSheets","position":[4640,1380],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows2').item.json.apollo_id }}","posts_scrape_status":"scraped","about_linkedin_profile":"={{ $json.choices[0].message.content }}","profile_summary_scrape":"completed"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":true,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":false,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"867e28c2-e24f-419c-838f-d1ddc97cbd84","name":"Stringify Data3","type":"n8n-nodes-base.code","position":[3900,1520],"parameters":{"jsCode":"const profile = items[0].json;\n\nreturn [{\n  json: {\n    postsString: JSON.stringify(profile, null, 2) // Pretty print with 2-space indentation\n  }\n}];"},"typeVersion":2},{"id":"ba3ba6c9-803d-4f84-ad95-314fbe68e391","name":"Posts AI Summarizer1","type":"@n8n/n8n-nodes-langchain.openAi","position":[4100,1520],"parameters":{"modelId":{"__rl":true,"mode":"list","value":"gpt-3.5-turbo","cachedResultName":"GPT-3.5-TURBO"},"options":{},"messages":{"values":[{"content":"=Below are the most recent posts and reposts from a LinkedIn user. Summarize them collectively in no more than two short paragraphs. Focus on capturing the main themes, tone, and any recurring interests or professional concerns.\n\nAvoid listing each post separately — instead, synthesize the information into a narrative that gives a clear idea of what this person is currently focused on or passionate about.\n\nPosts: {{ $json.postsString }}\n\nKeep it insightful but brief — no more than 2 concise paragraphs."}]},"simplify":false},"credentials":{"openAiApi":{"id":"DO9F6MAeTGLeqgoF","name":"OpenAi account"}},"executeOnce":true,"typeVersion":1.8},{"id":"8de0e703-1af4-491a-b915-391e94bc0b18","name":"Get About Profile2","type":"n8n-nodes-base.httpRequest","onError":"continueErrorOutput","position":[3400,1380],"parameters":{"url":"\"apify-actor-endpoint\"","options":{},"jsonBody":"={\n    \"profileUrls\": [\n        \"{{ $json.linkedin_url }}\"\n    ]\n}","sendBody":true,"specifyBody":"json"},"typeVersion":4.2},{"id":"2a082269-015e-4d01-850b-89db56135df1","name":"Clean Profile Data2","type":"n8n-nodes-base.code","maxTries":2,"position":[3720,1520],"parameters":{"jsCode":"// n8n function to extract LinkedIn posts\nconst items = [];\n\n// Check if input exists and has updates\nif (!$input.first() || !$input.first().json || !$input.first().json.updates || !Array.isArray($input.first().json.updates)) {\n  // Return a single item with \"no posts\" message\n  items.push({\n    json: {\n      message: \"No posts found\"\n    }\n  });\n  return items;\n}\n\nconst updates = $input.first().json.updates;\n\n// If no posts available, return the \"no posts\" message\nif (updates.length === 0) {\n  items.push({\n    json: {\n      message: \"No posts found\"\n    }\n  });\n  return items;\n}\n\n// Process available posts (up to 4)\nfor (let i = 0; i < Math.min(updates.length, 4); i++) {\n  if (updates[i] && updates[i].postText) {\n    // Create an item for each post with the required n8n structure\n    items.push({\n      json: {\n        postNumber: i + 1,\n        postText: updates[i].postText\n      }\n    });\n  }\n}\n\n// If no valid posts were processed\nif (items.length === 0) {\n  items.push({\n    json: {\n      message: \"No posts found\"\n    }\n  });\n}\n\nreturn items;"},"retryOnFail":true,"typeVersion":2},{"id":"966bf4ba-2680-4092-b62c-d37f77ffa2fc","name":"Merge","type":"n8n-nodes-base.merge","position":[4460,1380],"parameters":{"mode":"combine","options":{},"combineBy":"combineAll"},"typeVersion":3.1},{"id":"36682aa5-73bf-405b-ab10-43bc144b37af","name":"update status to failed1","type":"n8n-nodes-base.googleSheets","position":[3400,1640],"parameters":{"columns":{"value":{"apollo_id":"={{ $('Get Pending About and Posts Rows2').item.json.apollo_id }}","profile_summary_scrape":"failed"},"schema":[{"id":"apollo_id","type":"string","display":true,"removed":false,"required":false,"displayName":"apollo_id","defaultMatch":false,"canBeUsedToMatch":true},{"id":"name","type":"string","display":true,"removed":true,"required":false,"displayName":"name","defaultMatch":false,"canBeUsedToMatch":true},{"id":"organization","type":"string","display":true,"removed":true,"required":false,"displayName":"organization","defaultMatch":false,"canBeUsedToMatch":true},{"id":"title","type":"string","display":true,"removed":true,"required":false,"displayName":"title","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_url","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_url","defaultMatch":false,"canBeUsedToMatch":true},{"id":"linkedin_username","type":"string","display":true,"removed":true,"required":false,"displayName":"linkedin_username","defaultMatch":false,"canBeUsedToMatch":true},{"id":"extract_username_status","type":"string","display":true,"removed":true,"required":false,"displayName":"extract_username_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"email_address","type":"string","display":true,"removed":true,"required":false,"displayName":"email_address","defaultMatch":false,"canBeUsedToMatch":true},{"id":"contacts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"contacts_scrape_status","defaultMatch":false,"canBeUsedToMatch":true},{"id":"about_linkedin_profile","type":"string","display":true,"removed":true,"required":false,"displayName":"about_linkedin_profile","defaultMatch":false,"canBeUsedToMatch":true},{"id":"profile_summary_scrape","type":"string","display":true,"required":false,"displayName":"profile_summary_scrape","defaultMatch":false,"canBeUsedToMatch":true},{"id":"recent_posts_summary","type":"string","display":true,"removed":true,"required":false,"displayName":"recent_posts_summary","defaultMatch":false,"canBeUsedToMatch":true},{"id":"posts_scrape_status","type":"string","display":true,"removed":true,"required":false,"displayName":"posts_scrape_status","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":["apollo_id"],"attemptToConvertTypes":false,"convertFieldsToString":false},"options":{},"operation":"update","sheetName":{"__rl":true,"mode":"list","value":"gid=0","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit#gid=0","cachedResultName":"Sheet1"},"documentId":{"__rl":true,"mode":"list","value":"1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ","cachedResultUrl":"https://docs.google.com/spreadsheets/d/1d99PlHkp9RPeSAtmATgQ4OC4Selcp8JSFLNuKx-n1EQ/edit?usp=drivesdk","cachedResultName":"apollo ai leads & enrichment"}},"credentials":{"googleSheetsOAuth2Api":{"id":"d0qeLhShx9sGXalR","name":"Google Sheets"}},"typeVersion":4.5},{"id":"a3d2a7e0-87ed-46ac-bb75-91c54e6e1f09","name":"If email is valid","type":"n8n-nodes-base.if","position":[880,680],"parameters":{"options":{},"conditions":{"options":{"version":2,"leftValue":"","caseSensitive":true,"typeValidation":"loose"},"combinator":"or","conditions":[{"id":"bc3200af-7ae4-4944-b410-ebb459e2d927","operator":{"type":"string","operation":"notContains"},"leftValue":"={{ $json.data.result }}","rightValue":"undeliverable"},{"id":"b0c7d1c3-a733-4547-899e-ff76b66765ad","operator":{"type":"string","operation":"notEmpty","singleValue":true},"leftValue":"={{ $json.data.mx_record }}","rightValue":"[null]"}]},"looseTypeValidation":true},"typeVersion":2.2}],"active":false,"pinData":{},"settings":{"executionOrder":"v1"},"versionId":"eef068bb-348c-46c5-940b-d6042431aa01","connections":{"Merge":{"main":[[{"node":"Update Profile Summary1","type":"main","index":0}]]},"OpenAI1":{"main":[[{"node":"Add Linkedin Username","type":"main","index":0}]]},"Split Out":{"main":[[{"node":"Clean Data","type":"main","index":0}]]},"Clean Data":{"main":[[{"node":"Add Leads to Google Sheet","type":"main","index":0}]]},"Stringify Data2":{"main":[[{"node":"AI Profile Summarizer1","type":"main","index":0}]]},"Stringify Data3":{"main":[[{"node":"Posts AI Summarizer1","type":"main","index":0}]]},"Clean Posts Data":{"main":[[{"node":"Stringify Posts Data","type":"main","index":0}],[{"node":"Google Sheets","type":"main","index":0}]]},"Schedule Trigger":{"main":[[{"node":"get invalid email rows","type":"main","index":0}]]},"Get About Profile":{"main":[[{"node":"Clean Profile Data","type":"main","index":0}]]},"Get Profile Posts":{"main":[[{"node":"Clean Posts Data","type":"main","index":0}]]},"If email is valid":{"main":[[{"node":"Add Email Address","type":"main","index":0}],[{"node":"Mark Invalid Email","type":"main","index":0}]]},"Schedule Trigger2":{"main":[[{"node":"get_failed_profile_summary_rows","type":"main","index":0}]]},"Schedule Trigger3":{"main":[[{"node":"get_failed_posts_summary_rows1","type":"main","index":0}]]},"update_to_pending":{"main":[[]]},"Clean Profile Data":{"main":[[{"node":"Stringify Profile Data1","type":"main","index":0}],[{"node":"update status to failed","type":"main","index":0}]]},"Get About Profile2":{"main":[[{"node":"Clean Profile Data1","type":"main","index":0},{"node":"Clean Profile Data2","type":"main","index":0}],[{"node":"update status to failed1","type":"main","index":0}]]},"On form submission":{"main":[[{"node":"Generate Leads with Apollo.io","type":"main","index":0}]]},"Clean Profile Data1":{"main":[[{"node":"Stringify Data2","type":"main","index":0}]]},"Clean Profile Data2":{"main":[[{"node":"Stringify Data3","type":"main","index":0}]]},"Posts AI Summarizer":{"main":[[{"node":"Update Posts Summary","type":"main","index":0}]]},"Posts AI Summarizer1":{"main":[[{"node":"Merge","type":"main","index":1}]]},"Stringify Posts Data":{"main":[[{"node":"Posts AI Summarizer","type":"main","index":0}]]},"AI Profile Summarizer":{"main":[[{"node":"Update Profile Summary","type":"main","index":0}]]},"Get Email from Apollo":{"main":[[{"node":"Confirm Email Validity","type":"main","index":0}]]},"Google Sheets Trigger":{"main":[[{"node":"Get Pending Username Row","type":"main","index":0}]]},"AI Profile Summarizer1":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Confirm Email Validity":{"main":[[{"node":"If email is valid","type":"main","index":0}]]},"Google Sheets Trigger2":{"main":[[{"node":"Get Pending Email Statuses","type":"main","index":0}]]},"Google Sheets Trigger3":{"main":[[{"node":"Get Pending About and Posts Rows","type":"main","index":0}]]},"Google Sheets Trigger4":{"main":[[{"node":"Get Pending About and Posts Rows1","type":"main","index":0}]]},"Google Sheets Trigger5":{"main":[[{"node":"Get Completely Enriched Profiles","type":"main","index":0}]]},"Google Sheets Trigger6":{"main":[[{"node":"Get Pending About and Posts Rows2","type":"main","index":0}]]},"get invalid email rows":{"main":[[{"node":"update_to_pending","type":"main","index":0}]]},"Stringify Profile Data1":{"main":[[{"node":"AI Profile Summarizer","type":"main","index":0}]]},"Get Pending Username Row":{"main":[[{"node":"OpenAI1","type":"main","index":0}]]},"Get Pending Email Statuses":{"main":[[{"node":"Get Email from Apollo","type":"main","index":0}]]},"Generate Leads with Apollo.io":{"main":[[{"node":"Split Out","type":"main","index":0}]]},"get_failed_posts_summary_rows1":{"main":[[{"node":"update_to_unscraped","type":"main","index":0}]]},"get_failed_profile_summary_rows":{"main":[[{"node":"update_to_pending1","type":"main","index":0}]]},"Get Completely Enriched Profiles":{"main":[[{"node":"Append to Enriched Leads Database","type":"main","index":0}]]},"Get Pending About and Posts Rows":{"main":[[{"node":"Get About Profile","type":"main","index":0}]]},"Get Pending About and Posts Rows1":{"main":[[{"node":"Get Profile Posts","type":"main","index":0}]]},"Get Pending About and Posts Rows2":{"main":[[{"node":"Get About Profile2","type":"main","index":0}]]}}}


