This workflow corresponds to n8n.io template #8314 — we link there as the canonical source.
This workflow follows the Agent → OpenAI Embeddings 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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "ca80efbc-515a-42d3-917c-07d32700c55b",
"name": "Pass text message",
"type": "n8n-nodes-base.set",
"position": [
16,
384
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "beaca9bb-d352-4ee2-8c27-f90eb6a38362",
"name": "processedMessage",
"type": "string",
"value": "={{ $json.message.text }}"
},
{
"id": "f37a2a8b-e149-485a-bed1-c14d9510f554",
"name": "sessionId",
"type": "string",
"value": "={{ $json.message.chat.id }}"
},
{
"id": "5009366a-70ea-46c9-abc6-d56bae0e5ac0",
"name": "name",
"type": "string",
"value": "={{ $json.message.from.first_name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8c98384b-9b27-4f39-aa26-bd66a58ddd99",
"name": "Link Filter",
"type": "n8n-nodes-base.if",
"position": [
-656,
192
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "792fd1b3-3782-4cf5-9362-e60f415bfb46",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.message.voice.file_id }}",
"rightValue": "=https://lookaside.fbsbx.com"
},
{
"id": "3f908dda-0030-4bae-92e7-6d8831ac1f86",
"operator": {
"type": "number",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.message.chat.id }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "a4170c19-0c40-4660-9db7-d2f212c5e57f",
"name": "Merge",
"type": "n8n-nodes-base.merge",
"position": [
240,
176
],
"parameters": {
"numberInputs": 3
},
"typeVersion": 3.1,
"alwaysOutputData": true
},
{
"id": "7fcec4b0-7715-47f8-a0d1-5fae4e3ff88f",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
464,
192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "4cd71c48-f1bf-4237-935b-071549fb9335",
"name": "processedMessage",
"type": "string",
"value": "={{ $json.processedMessage || $json.error || '' }} "
},
{
"id": "55c5a9e9-24a0-4a99-9792-b4fbdd1c75d1",
"name": "sessionId",
"type": "string",
"value": "={{ $('Telegram Message').item.json.message.from.id }}"
}
]
}
},
"typeVersion": 3.4,
"alwaysOutputData": true
},
{
"id": "4cbfb8d6-f269-4b22-9f0d-7801d43d2e1c",
"name": "Transcript Error Output",
"type": "n8n-nodes-base.set",
"position": [
16,
192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "380af7d7-3a3b-44da-9b2c-d138c1099925",
"name": "error",
"type": "string",
"value": "={{ $json.error }}"
},
{
"id": "5c2d1746-8a82-4391-8616-9df73d646810",
"name": "sessionId",
"type": "string",
"value": "={{ $('Telegram Message').item.json.message.chat.id }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "85d8125a-8874-4a07-ae40-edf4747ae48a",
"name": "Transcript Result",
"type": "n8n-nodes-base.set",
"position": [
16,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "cf189008-5ea4-493d-972d-190f3a785607",
"name": "processedMessage",
"type": "string",
"value": "={{ $json.text }}"
},
{
"id": "bc4c4384-a717-41c7-9b33-8937300525cd",
"name": "sessionId",
"type": "string",
"value": "={{ $('Telegram Message').item.json.message.chat.id }}"
},
{
"id": "2c1eaa75-9eca-467e-9977-02023283ef95",
"name": "name",
"type": "string",
"value": "={{ $('Telegram Message').item.json.message.from.first_name }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "948c4933-6453-4cc8-afa6-bb61b18cb8cd",
"name": "Get Audio File",
"type": "n8n-nodes-base.telegram",
"position": [
-432,
96
],
"parameters": {
"fileId": "={{ $('Telegram Message').item.json.message.voice.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "f521f015-2d23-4e04-a144-ad26c7b19d66",
"name": "Transcribe a recording",
"type": "@n8n/n8n-nodes-langchain.openAi",
"onError": "continueErrorOutput",
"position": [
-208,
96
],
"parameters": {
"options": {},
"resource": "audio",
"operation": "transcribe"
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"retryOnFail": false,
"typeVersion": 1.8
},
{
"id": "d8dd439a-d7be-4954-a524-48631c5cbd97",
"name": "Append row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
688,
192
],
"parameters": {
"columns": {
"value": {
"date": "={{ $now }}",
"message": "={{ $json.processedMessage }}",
"user_id": "={{ $json.sessionId }}"
},
"schema": [
{
"id": "date",
"type": "string",
"display": true,
"required": false,
"displayName": "date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "user_id",
"type": "string",
"display": true,
"required": false,
"displayName": "user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "message",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "message",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1245350096,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
"cachedResultName": "Msg Retention"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "2fe418a4-dae4-4f8c-9adf-4e70af68e8d4",
"name": "Get row(s) in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
2032,
96
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('No Rows').item.json.user_id }}",
"lookupColumn": "user_id"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1245350096,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
"cachedResultName": "Msg Retention"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "db232946-eecb-42c3-b4c4-513beff920d0",
"name": "Embeddings OpenAI1",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
3088,
448
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "418345bd-a996-4654-9237-c9e8fe4ff7a0",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
2768,
288
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-5-mini",
"cachedResultName": "gpt-5-mini"
},
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "62c2632d-31db-42d2-9a10-77bcabeed278",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"onError": "continueRegularOutput",
"maxTries": 3,
"position": [
2928,
32
],
"parameters": {
"text": "={{ $('Batch Messages').item.json.message }} ",
"options": {
"systemMessage": "ADD YOUR PROMPT HERE"
},
"promptType": "define"
},
"retryOnFail": false,
"typeVersion": 1.7,
"alwaysOutputData": false
},
{
"id": "232c7722-2598-45ff-8c10-9f00ac16a977",
"name": "Get row(s) in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
912,
192
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $('Telegram Message').item.json.message.from.id }}",
"lookupColumn": "user_id"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1701618791,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
"cachedResultName": "Msg Waiting"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7,
"alwaysOutputData": true
},
{
"id": "048186f4-e41a-4948-b020-8c5c6e6b1a6a",
"name": "What to do",
"type": "n8n-nodes-base.if",
"position": [
1360,
192
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "or",
"conditions": [
{
"id": "8a83a137-2989-4b42-8e32-39557ef5182e",
"operator": {
"type": "dateTime",
"operation": "before"
},
"leftValue": "={{ $json.last_updated }}",
"rightValue": "={{ new Date(Date.now() - 30000).toISOString() }} "
},
{
"id": "f6925d24-5bc5-4cf6-a4d2-e212eb11ec04",
"operator": {
"type": "boolean",
"operation": "false",
"singleValue": true
},
"leftValue": "={{ $json.is_waiting }}",
"rightValue": "=false"
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "84f200f5-b4e2-4658-9236-80067ef01be7",
"name": "Update row in sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
1584,
96
],
"parameters": {
"columns": {
"value": {
"user_id": "={{ $('Edit Fields').item.json.sessionId }}",
"is_waiting": "true",
"last_updated": "={{ $now }}"
},
"schema": [
{
"id": "user_id",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "is_waiting",
"type": "string",
"display": true,
"required": false,
"displayName": "is_waiting",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "last_updated",
"type": "string",
"display": true,
"required": false,
"displayName": "last_updated",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": true,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"user_id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1701618791,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
"cachedResultName": "Msg Waiting"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7,
"alwaysOutputData": true
},
{
"id": "4ba1454e-1ffa-49c5-8213-45fc16f4fafc",
"name": "Wait",
"type": "n8n-nodes-base.wait",
"position": [
1808,
96
],
"parameters": {
"amount": 30
},
"typeVersion": 1.1
},
{
"id": "9026922d-b27a-4c81-8743-007543caa21e",
"name": "Delete rows or columns from sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
2480,
96
],
"parameters": {
"operation": "delete",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1245350096,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1245350096",
"cachedResultName": "Msg Retention"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
},
"startIndex": "={{ $('Batch Messages').item.json.start_row_number }}",
"numberToDelete": "={{ $('Batch Messages').item.json.row_count }}"
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "8354d413-1d5e-4138-959d-c934a542666d",
"name": "Update row in sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
1584,
288
],
"parameters": {
"columns": {
"value": {
"user_id": "={{ $('Append row in sheet').item.json.user_id }}",
"is_waiting": "true",
"last_updated": "={{ $now }}"
},
"schema": [
{
"id": "user_id",
"type": "string",
"display": true,
"required": false,
"displayName": "user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "is_waiting",
"type": "string",
"display": true,
"required": false,
"displayName": "is_waiting",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "last_updated",
"type": "string",
"display": true,
"required": false,
"displayName": "last_updated",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1701618791,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
"cachedResultName": "Msg Waiting"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "62d9dcb5-80fc-45b4-afbd-87192125569f",
"name": "No Rows",
"type": "n8n-nodes-base.code",
"position": [
1136,
192
],
"parameters": {
"jsCode": "// Normalize Msg Waiting result so the IF node always has something real to check\n\n// 1) Always get sessionId from the earlier node (not from this node's $json)\nconst sessionId = $('Edit Fields').item.json.sessionId;\n\n// 2) Detect \"no rows\": either zero items OR one empty item\nconst noRows =\n items.length === 0 ||\n (items.length === 1 && (!items[0].json || Object.keys(items[0].json).length === 0));\n\nif (noRows) {\n // First-ever message for this user \u2192 pretend we have a row that says \"not waiting yet\"\n return [{ json: { user_id: sessionId, is_waiting: false, last_updated: null } }];\n}\n\n// 3) Rows exist \u2192 pass them through (and ensure required keys exist)\nreturn items.map(it => ({\n json: {\n user_id: it.json.user_id ?? sessionId,\n is_waiting: it.json.is_waiting ?? false,\n last_updated: it.json.last_updated ?? null,\n },\n}));\n"
},
"typeVersion": 2
},
{
"id": "237e36a5-eb9c-486a-9110-c4f5ae195978",
"name": "Batch Messages",
"type": "n8n-nodes-base.code",
"position": [
2256,
96
],
"parameters": {
"jsCode": "// n8n Code node\n\nconst rowNumbers = items.map(item => item.json.row_number);\nconst sessionId = items[0].json.user_id; // Assuming all rows are from the same session/user\n\nconst merged = items\n .map(item => item.json.message)\n .filter(msg => msg && msg.trim() !== '')\n .join(' '); // Or use '\\n' if line breaks are preferred\n\nreturn [\n {\n json: {\n message: merged,\n start_row_number: Math.min(...rowNumbers),\n row_count: items.length,\n session_id: sessionId,\n },\n },\n];\n"
},
"typeVersion": 2
},
{
"id": "e84f5e5b-18b2-4a0e-a5d4-991888294d6b",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
416,
-304
],
"parameters": {
"color": 5,
"width": 2224,
"height": 816,
"content": "# Message Batching\n\n## You will need two Google Sheets to make it work:\n\n### 1. Message retention: \n\nIncoming messages will be kept and then deleted to keep things clean. \nCreate three columns: \n\ndate | user_id | message\n\n### 2. Message Checkup\n\nWill add TRUE boolean to the is_waiting column as we wait for the next message (30 seconds)\t\nCreate three columns: \t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\nuser_id\t| is_waiting | last_updated\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"
},
"typeVersion": 1
},
{
"id": "b81ef537-6b0a-45ac-b6f6-9b36c5747b29",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
-96
],
"parameters": {
"color": 4,
"width": 1120,
"height": 928,
"content": "# Transcription Pipeline\n\n## Add your Open AI API key to transcribe audio messages using Whisper\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n### Voice messages \u2192 downloaded with Telegram, transcribed via Whisper, saved as processedMessage.\n\n### Text messages \u2192 passed straight through as processedMessage.\n\n### Files/media (documents, images, videos, etc.) \u2192 politely refused with a short reply to the user.\n\n### All outputs (voice \u2192 text, plain text, or refusal) are normalized so the rest of the workflow always sees a single field processedMessage with the user\u2019s content or an error message.\n\n### This way, the workflow can differentiate voice, text, and files, and always behave consistently."
},
"typeVersion": 1
},
{
"id": "a9943cf2-7c8c-40cb-afb2-18e9ee682395",
"name": "Simple Memory",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
2928,
288
],
"parameters": {},
"typeVersion": 1.3
},
{
"id": "813d014f-92a7-46d9-99ac-c190e48a89dc",
"name": "Supabase Vector Store",
"type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
"position": [
3072,
288
],
"parameters": {
"mode": "retrieve-as-tool",
"options": {},
"tableName": {
"__rl": true,
"mode": "id",
"value": "{SUPABASE_TABLE_ID}"
},
"toolDescription": "Use this node to access your Knowledge Base"
},
"credentials": {
"supabaseApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "eab1c6d2-e953-4179-9537-029dfa9f3923",
"name": "Send message Back to TG",
"type": "n8n-nodes-base.telegram",
"position": [
3392,
32
],
"parameters": {
"text": "={{ $json.output.text }}",
"chatId": "={{ $('Batch Messages').item.json.session_id }}",
"forceReply": {},
"replyMarkup": "=",
"additionalFields": {
"appendAttribution": false
},
"replyKeyboardRemove": {},
"replyKeyboardOptions": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "2d4ad4ac-0df1-46d3-b894-81075b000b06",
"name": "Telegram Trigger",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
-1088,
192
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "e1a6e83a-f60c-4f9b-8d89-30677f829267",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1296,
-864
],
"parameters": {
"color": 6,
"width": 1664,
"height": 752,
"content": "# How to run this on Telegram\n\n**1) Create a bot + add creds**\n- @BotFather \u2192 `/newbot` \u2192 copy Bot Token.\n- In n8n: **Credentials \u2192 Telegram API** \u2192 paste token.\n- Add **Telegram Trigger** \u2192 select credential \u2192 **Execute Node** once to register webhook.\n\n**2) Enable updates**\n- In **Telegram Trigger**, enable **`message`** (add photo/document if needed).\n\n**3) Voice messages (optional)**\n- Pipeline: **Telegram Trigger \u2192 Telegram (Get File by `file_id`) \u2192 OpenAI Whisper (Transcribe) \u2192 Set**.\n\n**4) Google Sheets (two sheets)**\n- Share both sheets with the **service account email** from your n8n Google Sheets credential (Editor).\n- **Msg Retention** columns: `date | user_id | message`\n- **Message Checkup** columns: `user_id | is_waiting | last_updated`\n\n**5) Debounce / batching**\n- After **Append row in Msg Retention**:\n - **Get row(s) in Msg Waiting** by `user_id` \u2192 **No Rows** code normalizes empty to `{ user_id, is_waiting:false, last_updated:null }`.\n - **IF (OR)**:\n - `last_updated` **before** `{{ new Date(Date.now() - 20000).toISOString() }}`\n - `is_waiting` is **false**\n - **TRUE** \u2192 **Update Message Checkup** (`is_waiting=true`, `last_updated=$now`) \u2192 **Wait (e.g., 30s)** \u2192 **Get rows from Msg Retention** \u2192 **Batch Messages** (merge) \u2192 **Delete those rows** \u2192 **AI Agent** \u2192 **Send to TG** \u2192 **Delete row in Message Checkup**.\n - **FALSE** \u2192 only **Update Message Checkup** (`is_waiting=true`, fresh `last_updated`) \u2014 **no extra Wait**.\n\n**6) Copy-paste expressions**\n- \u201cOlder than 20s\u201d right side (IF \u2192 date before):\n `{{ new Date(Date.now() - 20000).toISOString() }}`\n- Keep IF \u2192 **Type Validation = loose** for `is_waiting` so `\"true\"`/`true` both work.\n\n**7) \u201cNo Rows\u201d safety (Code node)**\n\n"
},
"typeVersion": 1
},
{
"id": "b47866b2-0838-4076-9a08-0eff0937d043",
"name": "Delete Row from Message Checkup",
"type": "n8n-nodes-base.googleSheets",
"position": [
3568,
32
],
"parameters": {
"operation": "delete",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1701618791,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit#gid=1701618791",
"cachedResultName": "Msg Waiting"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1hkHTGSfr0pyqvG6wcdCZgyVSOAKcnwl9Zv3CrU1MBoo/edit?usp=drivesdk",
"cachedResultName": "ATEM Chat Logs"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "15087422-c826-46ea-83df-daafea1d4cb7",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
416,
-688
],
"parameters": {
"width": 1104,
"height": 352,
"content": "# Common pitfalls (TG + Sheets)\n\n- **Webhook not set**: Open the **Telegram Trigger** and **Execute** once to register. Ensure your n8n URL is public + HTTPS.\n- **Sheets permissions**: Share the sheets with the **service account email** from the Google Sheets credential (Editor). Otherwise appends/reads silently fail.\n- **Date comparisons**: Use ISO (`{{ $now }}`) so \u201cbefore\u201d comparisons work across rows.\n- **Duplicate waits (race)**: Only the **TRUE** branch starts a Wait. The **FALSE** branch must *only* refresh `last_updated`. This prevents parallel timers for the same user.\n- **Cleanup order**:\n 1) Batch & **delete Msg Retention rows** after merging.\n 2) Send reply to TG.\n 3) **Delete Msg Waiting row** (or set `is_waiting=false`) last.\n- **Type mismatches**: If `is_waiting` is stored as text `\"true\"/\"false\"`, use IF\u2019s **loose** validation or cast to boolean in a Code node.\n- **Voice transcripts**: Make sure your Link/IF lets either text **or** voice path feed into the merge."
},
"typeVersion": 1
},
{
"id": "2592aa82-2ca1-41b1-8302-c49b85028ab4",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2720,
-480
],
"parameters": {
"width": 608,
"height": 1232,
"content": "# AI Agent node (plug-and-play)\n\n**Goal:** take the batched user text and produce one reply. You can keep it simple, or attach memory + a vector database.\n\n## Minimal setup\n- **Agent node:** `AI Agent`\n- **System prompt:** *Add Yours*\n- **User text:** `{{ $('Batch Messages').item.json.message }}`\n"
},
"typeVersion": 1
}
],
"connections": {
"Wait": {
"main": [
[
{
"node": "Get row(s) in sheet",
"type": "main",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"index": 0
}
]
]
},
"No Rows": {
"main": [
[
{
"node": "What to do",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Send message Back to TG",
"type": "main",
"index": 0
}
]
]
},
"What to do": {
"main": [
[
{
"node": "Update row in sheet",
"type": "main",
"index": 0
}
],
[
{
"node": "Update row in sheet1",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Append row in sheet",
"type": "main",
"index": 0
}
]
]
},
"Link Filter": {
"main": [
[
{
"node": "Get Audio File",
"type": "main",
"index": 0
}
],
[
{
"node": "Pass text message",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory": {
"ai_memory": [
[
{
"node": "AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Batch Messages": {
"main": [
[
{
"node": "Delete rows or columns from sheet1",
"type": "main",
"index": 0
}
]
]
},
"Get Audio File": {
"main": [
[
{
"node": "Transcribe a recording",
"type": "main",
"index": 0
}
]
]
},
"Telegram Trigger": {
"main": [
[
{
"node": "Link Filter",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Pass text message": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 2
}
]
]
},
"Transcript Result": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI1": {
"ai_embedding": [
[
{
"node": "Supabase Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Append row in sheet": {
"main": [
[
{
"node": "Get row(s) in sheet1",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet": {
"main": [
[
{
"node": "Batch Messages",
"type": "main",
"index": 0
}
]
]
},
"Update row in sheet": {
"main": [
[
{
"node": "Wait",
"type": "main",
"index": 0
}
]
]
},
"Get row(s) in sheet1": {
"main": [
[
{
"node": "No Rows",
"type": "main",
"index": 0
}
]
]
},
"Supabase Vector Store": {
"ai_tool": [
[
{
"node": "AI Agent",
"type": "ai_tool",
"index": 0
}
]
]
},
"Transcribe a recording": {
"main": [
[
{
"node": "Transcript Result",
"type": "main",
"index": 0
}
],
[
{
"node": "Transcript Error Output",
"type": "main",
"index": 0
}
]
]
},
"Send message Back to TG": {
"main": [
[
{
"node": "Delete Row from Message Checkup",
"type": "main",
"index": 0
}
]
]
},
"Transcript Error Output": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Delete Row from Message Checkup": {
"main": [
[]
]
},
"Delete rows or columns from sheet1": {
"main": [
[
{
"node": "AI Agent",
"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.
googleSheetsOAuth2ApiopenAiApisupabaseApitelegramApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This Telegram workflow batches rapid-fire messages from the same user into one prompt (20–30s debounce), then sends a single AI reply.
Source: https://n8n.io/workflows/8314/ — 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.
A lightweight, self-hosted AI assistant built entirely in n8n. Multi-channel messaging (Telegram, WhatsApp, Gmail), persistent memory, task management, and autonomous work — all in a single visual wor
Your AI workforce is ready. Are you?
This comprehensive workflow bundle is designed as a powerful starter kit, enabling you to build a multi-functional AI assistant on Telegram. It seamlessly integrates AI-powered voice interactions, an
This n8n template automatically classifies incoming emails (Sales, Support, Internal, Finance, Promotions) and routes them to a dedicated OpenAI LLM Agent for processing. Depending on the category, th
Who is this for? This workflow is ideal for HR teams, startups, and enterprises that want to handle employee interactions through WhatsApp and automate responses using LLM (OpenAI) and intelligent rou