This workflow corresponds to n8n.io template #17346 — we link there as the canonical source.
This workflow follows the Agent → Google Gemini Chat recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "JCMN2lMsnv0aDwyk",
"name": "_lead_clasifier_n8n",
"tags": [],
"nodes": [
{
"id": "78eef699-2827-474b-91ea-de96f3f931fd",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
-1552,
624
],
"parameters": {
"path": "lead-qualifier",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "156ca671-e22a-47e7-a0de-668bbf57268b",
"name": "Validate & Serialize Payload",
"type": "n8n-nodes-base.code",
"position": [
-1328,
624
],
"parameters": {
"jsCode": "const body = $input.first().json.body;\n\nif (!body || Object.keys(body).length === 0) {\n throw new Error('Empty or missing payload body');\n}\n\nconst chatId = body.chatId || body.telegram_chat_id || body.chat_id || null;\nconst payloadStr = JSON.stringify(body, null, 2);\n\nconst chatInput = \"Analyze the following lead payload and classify it:\\n\\n```\\n\" + payloadStr + \"\\n```\";\n\nreturn [{\n json: {\n chatInput: chatInput,\n chatId: chatId,\n rawPayload: body\n }\n}];"
},
"typeVersion": 2
},
{
"id": "47461301-9894-49a5-890a-7c5ac786d8df",
"name": "AI Agent: Lead Qualifier",
"type": "@n8n/n8n-nodes-langchain.agent",
"notes": "Retry on fail",
"position": [
-1104,
624
],
"parameters": {
"text": "={{ $json.chatInput }}",
"options": {
"maxIterations": 10,
"systemMessage": "=You are a lead analyst at Your-Company-Name.\n\nYour role is to analyze the received data payload and determine whether it contains information about a lead (potential client).\n\nRULES:\n1. Analyze the ENTIRE payload, regardless of its structure.\n2. Identify name, email, phone number, company, message, source, and any other relevant data.\n3. Rate the lead quality on a scale of 1 to 10:\n - 8-10: Hot lead \u2013 complete information, clear interest, defined budget\n - 5-7: Warm lead \u2013 partial information or general interest\n - 1-4: Cold lead \u2013 minimal information, spam, or no commercial interest\n4. Classify: hot / warm / cold\n5. Identify the key signals justifying your score.\n6. Recommend a specific next step.\n\nCurrent date: {{ $now }}"
},
"promptType": "define",
"hasOutputParser": true
},
"retryOnFail": true,
"typeVersion": 3.1
},
{
"id": "1cfea055-c4ea-4642-abf2-4386c2825564",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-1088,
1728
],
"parameters": {
"options": {
"temperature": 0.7
},
"modelName": "models/gemini-2.5-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "35f4ac1c-322f-47d5-8738-16a7682c7f1c",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-960,
848
],
"parameters": {
"schemaType": "manual",
"inputSchema": "{\"type\":\"object\",\"properties\":{\"nombre\":{\"type\":\"string\"},\"email\":{\"type\":\"string\"},\"telefono\":{\"type\":\"string\"},\"empresa\":{\"type\":\"string\"},\"resumen\":{\"type\":\"string\"},\"clasificacion\":{\"type\":\"string\",\"enum\":[\"hot\",\"warm\",\"cold\"]},\"puntuacion\":{\"type\":\"number\",\"minimum\":1,\"maximum\":10},\"senales_clave\":{\"type\":\"array\",\"items\":{\"type\":\"string\"}},\"accion_recomendada\":{\"type\":\"string\"}},\"required\":[\"nombre\",\"email\",\"resumen\",\"clasificacion\",\"puntuacion\",\"senales_clave\",\"accion_recomendada\"]}"
},
"typeVersion": 1.3
},
{
"id": "f69d6881-64bc-4db2-a3ed-15dfc8f8321d",
"name": "Format Telegram Message",
"type": "n8n-nodes-base.code",
"position": [
-752,
624
],
"parameters": {
"jsCode": "const output = $input.first().json.output;\n\nconst classification = output.clasificacion || 'cold';\nconst score = output.puntuacion || 0;\n\nconst icons = { hot: '\ud83d\udd25', warm: '\u26a1', cold: '\u2744\ufe0f' };\nconst icon = icons[classification] || '\u2753';\n\nconst senalesArr = output.senales_clave || [];\nlet senales = '';\nfor (let i = 0; i < senalesArr.length; i++) {\n senales += '<br>\u2022 ' + senalesArr[i];\n}\nif (!senales) senales = '<br>\u2022 Sin se\u00f1ales identificadas';\n\nconst nombre = output.nombre || 'No especificado';\nconst email = output.email || 'No especificado';\nconst telefono = output.telefono || 'No especificado';\nconst empresa = output.empresa || 'No especificado';\nconst resumen = output.resumen || 'Sin resumen';\nconst accion = output.accion_recomendada || 'Sin recomendaci\u00f3n';\n\nconst html = '<b>\ud83d\udccb Lead Identificado</b><br><br>' +\n '<b>Nombre:</b> ' + nombre + '<br>' +\n '<b>Email:</b> ' + email + '<br>' +\n '<b>Tel\u00e9fono:</b> ' + telefono + '<br>' +\n '<b>Empresa:</b> ' + empresa + '<br><br>' +\n '<b>\ud83d\udcdd Resumen</b><br>' + resumen + '<br><br>' +\n '<b>\ud83c\udfaf Clasificaci\u00f3n</b><br>' +\n '<b>Nivel:</b> ' + icon + ' ' + classification.toUpperCase() + '<br>' +\n '<b>Puntuaci\u00f3n:</b> ' + score + '/10<br><br>' +\n '<b>\ud83d\udca1 Se\u00f1ales Clave</b><br>' + senales + '<br><br>' +\n '<b>\u27a1\ufe0f Acci\u00f3n Recomendada</b><br>' + accion;\n\nreturn [{\n json: Object.assign({}, output, {\n telegramHtml: html,\n chatId: $('Validate & Serialize Payload').first().json.chatId\n })\n}];"
},
"typeVersion": 2
},
{
"id": "319fb2f5-c2ce-4f51-a522-592c4b6cbe06",
"name": "Send to Telegram",
"type": "n8n-nodes-base.telegram",
"position": [
-208,
544
],
"parameters": {
"chatId": "=-5185964792",
"operation": "sendRichMessage",
"richMessageText": "={{ $json.telegramHtml }}",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "aff2a7fb-9de4-44a5-b089-eea097b5813e",
"name": "Respond Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-528,
720
],
"parameters": {
"options": {
"responseCode": 200
},
"respondWith": "json",
"responseBody": "={{ { \"status\": \"ok\", \"message\": \"Lead analyzed and sent to Telegram\", \"clasificacion\": $json.clasificacion, \"puntuacion\": $json.puntuacion } }}"
},
"typeVersion": 1.5
},
{
"id": "a84d9819-40f1-4128-b721-a771b7dda503",
"name": "Respond Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
-512,
96
],
"parameters": {
"options": {
"responseCode": 500
},
"respondWith": "json",
"responseBody": "={{ { \"status\": \"error\", \"message\": \"Failed to process lead\" } }}"
},
"typeVersion": 1.5
},
{
"id": "fc87435c-8a66-4769-8cee-760c886de785",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1168,
1120
],
"parameters": {
"width": 672,
"height": 432,
"content": "## \ud83d\udca1 You can use any Chat Model here\n\nThis node uses Google Gemini (gemini-2.5-flash) but you can swap it for any n8n Chat Model node \u2014 OpenAI, Groq, Anthropic, Ollama, Mistral, or any other. Just create the corresponding credential in n8n and replace this node. No other configuration needed. The Structured Output Parser and AI Agent work the same way regardless of which model provider you choose."
},
"typeVersion": 1
},
{
"id": "ff7203f6-9f10-44d0-82bc-3f013fcf11ff",
"name": "Groq Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGroq",
"position": [
-768,
1440
],
"parameters": {
"options": {}
},
"typeVersion": 1
},
{
"id": "fa078ae5-7e87-4bf7-9afa-301693206dd9",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-624,
1440
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini"
},
"options": {},
"builtInTools": {}
},
"typeVersion": 1.3
},
{
"id": "ad973e79-fde3-4138-99d9-5df25a103cda",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
784
],
"parameters": {
"color": "#4E5ABC",
"width": 560,
"height": 272,
"content": "## \ud83c\udf10 Adjust your Webhook URL\nYou can find and customize the webhook URL under the Webhook node settings. It defaults to /webhook/lead-qualifier but you can change the path to whatever you need. Once the workflow is active, external services (forms, CRMs, APIs) can POST any JSON payload directly to this URL \u2014 no authentication required, no extra configuration needed. Just point your source to https://{you-n8n-domain}/webhook/your-path and you're set."
},
"typeVersion": 1
},
{
"id": "59e0b4c1-1043-45ab-bc74-3a64c3de3838",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
320
],
"parameters": {
"color": "#4E5ABC",
"width": 864,
"height": 704,
"content": "## \ud83d\udccd Set a fixed Telegram chat for all leads\n\n**Description:**\n\nThis workflow captures leads from any source (web forms, CRMs, APIs) and sends them to Telegram. However, those external sources don't know your Telegram chatId. The simplest solution: use a Telegram group as a fixed destination.\nStep-by-step setup:\n1. Create a Telegram group \u2014 open Telegram, tap the pencil icon \u2192 \"New Group\", name it something like \"Leads \u2013 Bitclick\"\n2. Add your bot to the group \u2014 search for your bot's username (the one you created with @BotFather, e.g. @your_bot_handle) and add it as a member. If you haven't created a bot yet, talk to @BotFather (https://t.me/botfather), create one, and save the token it gives you \u2014 you'll need it for the n8n Telegram credential.\n3. Add @getidsbot to the group \u2014 search for @getidsbot, add it to the same group, and send any message in the group (e.g. \"hi\"). The bot will reply with the group's chat_id (a negative number like -1001234567890). Copy it.\n4. Remove @getidsbot from the group \u2014 once you have the ID, you can remove it. Keep your bot in the group.\n5. Open the Lead Qualifier workflow in n8n \u2014 go to the \"Send to Telegram\" node, find the chatId field, and replace the expression ={{ $json.chatId }} with your group's chat_id number (just the number, no quotes, no expression).\n6. Save and activate \u2014 publish the workflow. Now every lead will arrive in your group's chat.\nAlternative method (if you prefer not to use @getidsbot):\n- Visit https://api.telegram.org/bot<YOUR_BOT_TOKEN>/getUpdates in your browser\n- Send a message in the group\n- Refresh the page\n- Look for \"chat\":{\"id\":-100xxxxxxxxx} in the JSON response \u2014 that's your chat_id\nThat's it. One number swap, no code changes, and every lead lands in the same place where your team can review them."
},
"typeVersion": 1
},
{
"id": "9039fa13-cd23-4fb0-a766-2f2f7617033b",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-768,
400
],
"parameters": {
"color": 7,
"width": 736,
"height": 480,
"content": "## Format and send success\n\nThis right-side cluster formats the qualified lead into a Telegram message, sends the notification, and returns a successful webhook response."
},
"typeVersion": 1
},
{
"id": "6c4ff4ed-b5c8-46fe-b9d6-ff85dbfb1916",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-528,
-160
],
"parameters": {
"color": 7,
"height": 400,
"content": "## Return error response\n\nThe isolated upper response node handles errors from validation, AI qualification, or message formatting and returns an error response to the webhook caller."
},
"typeVersion": 1
},
{
"id": "ef2b7da0-a259-4ef1-9876-aa6646106085",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1808,
432
],
"parameters": {
"color": 7,
"width": 400,
"height": 336,
"content": "## Receive and validate lead\n\nThe webhook accepts incoming lead submissions and the nearby code node validates and serializes the payload before routing it onward or to the error response."
},
"typeVersion": 1
},
{
"id": "8d485cab-f910-4607-b0b1-96479420148d",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1152,
320
],
"parameters": {
"color": 7,
"width": 352,
"height": 784,
"content": "## Qualify lead with AI\n\nThe central AI agent evaluates the validated lead data, with the nearby structured output parser enforcing a predictable response format for downstream processing."
},
"typeVersion": 1
},
{
"id": "a6e46ad4-769b-4fff-bffb-405a8a0888a4",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1168,
1392
],
"parameters": {
"color": 2,
"width": 352,
"height": 480,
"content": "### Customization\n\nYou can adjust the lead qualification prompt, structured output schema, Telegram message formatting, and the success/error response payloads to match your sales process."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "ad4a58c8-0452-4e11-8035-ea000bd96bf8",
"nodeGroups": [],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Validate & Serialize Payload",
"type": "main",
"index": 0
}
]
]
},
"Format Telegram Message": {
"main": [
[
{
"node": "Send to Telegram",
"type": "main",
"index": 0
},
{
"node": "Respond Success",
"type": "main",
"index": 0
},
{
"node": "Respond Error",
"type": "main",
"index": 0
}
]
]
},
"AI Agent: Lead Qualifier": {
"main": [
[
{
"node": "Format Telegram Message",
"type": "main",
"index": 0
},
{
"node": "Respond Error",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent: Lead Qualifier",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "AI Agent: Lead Qualifier",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Validate & Serialize Payload": {
"main": [
[
{
"node": "AI Agent: Lead Qualifier",
"type": "main",
"index": 0
},
{
"node": "Respond Error",
"type": "main",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
googlePalmApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow receives lead data via a webhook, uses Google Gemini through an n8n AI Agent to score and classify the lead (hot/warm/cold) with structured output, then formats and sends the results to a Telegram chat and returns a JSON response to the caller. Receives a POST…
Source: https://n8n.io/workflows/17346/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
leads. Uses supabase, gmail, formTrigger, httpRequest. Webhook trigger; 62 nodes.
This workflow is an AI-powered Dental Appointment Assistant that automates appointment booking, rescheduling, and cancellations through Telegram or a Webhook. It uses intelligent agents to understand
⏺ 🚀 How it works
Are you drowning in daily operational chaos, desperately trying to juggle sales, projects, content, and client communication? Imagine an AI brain that handles it all, freeing you to lead your business
Bitlab-Chatbot. Uses telegramTrigger, telegram, snowflake, httpRequest. Event-driven trigger; 87 nodes.