AutomationFlowsSlack & Telegram › Triage Telegram Voice and Text Support with Groq Llms and Google Sheets

Triage Telegram Voice and Text Support with Groq Llms and Google Sheets

ByChijioke Ogbonna @cjaey5 on n8n.io

This workflow turns Telegram voice notes and text messages into a support agent by transcribing audio with Groq Whisper, classifying intent/sentiment/security risk with Groq LLMs, escalating risky cases to a human via Telegram, and logging interactions and errors to Google…

Event trigger★★★★★ complexity40 nodesTelegram TriggerTelegramHTTP RequestGoogle SheetsSlack
Slack & Telegram Trigger: Event Nodes: 40 Complexity: ★★★★★ Added:
Triage Telegram Voice and Text Support with Groq Llms and Google Sheets — n8n workflow card showing Telegram Trigger, Telegram, HTTP Request integration

This workflow corresponds to n8n.io template #17522 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request 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 →

Download .json
{
  "id": "aOYYI8Y2xAlPyKGI",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Voice & Text Telegram Support Agent",
  "tags": [],
  "nodes": [
    {
      "id": "6fbc5a9f-d46f-4a78-8103-41725e298241",
      "name": "Voice Message Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        0,
        800
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "8fd1d246-8f91-4d8f-b614-58b5b59210c4",
      "name": "Has Voice?",
      "type": "n8n-nodes-base.if",
      "position": [
        224,
        800
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f4bb2bb0-6841-4765-a6aa-241583897dfa",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.voice }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "05048dce-81cd-452d-b909-92772b49a13b",
      "name": "Get Voice File",
      "type": "n8n-nodes-base.telegram",
      "onError": "continueErrorOutput",
      "position": [
        448,
        624
      ],
      "parameters": {
        "fileId": "={{ $json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "24e43330-378f-4f5a-9db4-c90a50133d92",
      "name": "Fix Audio Filename",
      "type": "n8n-nodes-base.code",
      "onError": "continueErrorOutput",
      "position": [
        640,
        560
      ],
      "parameters": {
        "jsCode": "const item = $input.first();\n\nif (!item.binary || Object.keys(item.binary).length === 0) {\n  throw new Error('No binary audio data received from Telegram. Make sure \"Get Voice File\" downloaded the voice file.');\n}\n\n// Telegram usually stores the file under the \"data\" property; fall back to whatever key is present.\nconst binaryKey = item.binary.data ? 'data' : Object.keys(item.binary)[0];\nconst binary = item.binary[binaryKey];\n\nbinary.fileName = 'voice.ogg';\nbinary.mimeType = 'audio/ogg';\n\n// Ensure the downstream Whisper node reads the binary from the \"data\" field.\nif (binaryKey !== 'data') {\n  item.binary.data = binary;\n  delete item.binary[binaryKey];\n}\n\nreturn [item];"
      },
      "typeVersion": 2
    },
    {
      "id": "ea95bc6c-517a-4519-a316-90056ab5c162",
      "name": "Transcribe (Whisper)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        832,
        480
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/audio/transcriptions",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            },
            {
              "name": "model",
              "value": "whisper-large-v3-turbo"
            }
          ]
        },
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "e3b64f94-d521-448a-9bb9-18ddb1995627",
      "name": "Extract Transcript (Voice)",
      "type": "n8n-nodes-base.code",
      "position": [
        1104,
        352
      ],
      "parameters": {
        "jsCode": "const transcript = $input.first().json.text;\nconst trigger = $('Voice Message Trigger').first().json.message;\n\nreturn [{\n  json: {\n    transcript,\n    chatId: trigger.chat.id,\n    userId: trigger.from.id,\n    userName: trigger.from.first_name || 'Customer'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "9fb8d1e7-80ea-4d99-ae62-eb7f6ffc8a1c",
      "name": "Classify Intent & Sentiment",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        1248,
        432
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  model: \"llama-3.1-8b-instant\",\n  temperature: 0,\n  response_format: { type: \"json_object\" },\n  messages: [\n    { role: \"system\", content: \"You classify messages sent to CBox, a crypto wallet app's support line. Return ONLY valid JSON, no markdown, no commentary, in this exact shape: {\\\"intent\\\": \\\"faq|transaction_issue|account_kyc|wallet_security|trading_swap\\\", \\\"sentiment\\\": \\\"neutral|frustrated|angry\\\", \\\"security_risk\\\": true|false, \\\"confidence\\\": 0.0}. Set security_risk to true if the message mentions: unauthorized or unrecognized transactions, missing/stolen funds, a suspected phishing attempt, someone asking the user for their seed phrase or private key, suspicious app behavior, or the user believing their wallet is compromised. Intent categories: faq (general how-to or policy questions with no reference to the user's own account, e.g. 'how long does KYC take', 'what networks are supported', 'what is slippage' - these should be faq even if they mention KYC, transactions, or trading by name); transaction_issue (the user is asking about the status of their own specific stuck/pending/failed transaction, or their own deposit/withdrawal not showing); account_kyc (the user is asking about their own verification status, their own account limits, or their own account access - not general KYC policy); wallet_security (2FA setup, device management, or a security_risk situation); trading_swap (a specific swap the user made failed, or gas fee/slippage/token support questions tied to their own trade). Rule of thumb: if the question could be answered the same way for any user without looking up their account, classify it as faq.\" },\n    { role: \"user\", content: $json.transcript }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "b670611c-59f6-473a-95f5-1699f23c89fa",
      "name": "Parse Classification JSON",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        272
      ],
      "parameters": {
        "jsCode": "const raw = $input.first().json.choices[0].message.content;\nconst cleaned = raw.replace(/```json|```/g, '').trim();\nlet parsed;\ntry {\n  parsed = JSON.parse(cleaned);\n} catch (e) {\n  parsed = { intent: 'faq', sentiment: 'neutral', security_risk: false, confidence: 0 };\n}\n\nlet prior;\ntry {\n  prior = $('Extract Transcript (Voice)').first().json;\n} catch (e) {\n  prior = $('Extract Transcript (Text)').first().json;\n}\n\nreturn [{\n  json: {\n    ...prior,\n    intent: parsed.intent,\n    sentiment: parsed.sentiment,\n    security_risk: !!parsed.security_risk,\n    confidence: parsed.confidence\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "10acf2e7-8118-46db-84b3-052c66a7bc61",
      "name": "Get row(s) in sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1568,
        272
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $json.chatId }}",
              "lookupColumn": "chatId"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 165582478,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit#gid=165582478",
          "cachedResultName": "Escalations"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit?usp=drivesdk",
          "cachedResultName": "CBox_Interactions_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7,
      "alwaysOutputData": true
    },
    {
      "id": "58a1841f-da08-4fef-964e-cde880c187b7",
      "name": "Evaluate Escalation Lock",
      "type": "n8n-nodes-base.code",
      "position": [
        1760,
        272
      ],
      "parameters": {
        "jsCode": "const rows = $input.all();\nconst now = Date.now();\n\nconst activeLock = rows.some(r => {\n  if (!r.json.escalatedAt) return false;\n  const escalatedAt = new Date(r.json.escalatedAt).getTime();\n  return (now - escalatedAt) < 30 * 60 * 1000; // 30 min window\n});\n\nconst context = $('Parse Classification JSON').item.json;\n\nreturn [{ json: { ...context, isLocked: activeLock } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "e4f99889-a174-48be-9cf4-7c45f492207e",
      "name": "Already Escalated?",
      "type": "n8n-nodes-base.if",
      "position": [
        1936,
        272
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "4fc78649-bc7b-4135-a21b-2ff0b31bc3d6",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isLocked }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "55aa3487-76b2-4337-920f-3ee76c6626d8",
      "name": "Holding Reply",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2144,
        256
      ],
      "parameters": {
        "text": "Still working on this with a specialist \u2014 thanks for your patience, they'll respond shortly.",
        "chatId": "={{ $json.chatId }}",
        "additionalFields": {
          "appendAttribution": false,
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "1cafda7a-455c-4785-9a69-be0bebe51221",
      "name": "Escalation Check",
      "type": "n8n-nodes-base.if",
      "position": [
        2160,
        432
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "d205dedf-7d11-456a-ba13-d3becaec2a7f",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.sentiment }}",
              "rightValue": "angry"
            },
            {
              "id": "a2fe0dac-780b-4b40-8324-b20adba88536",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.sentiment }}",
              "rightValue": "frustrated"
            },
            {
              "id": "0d6ff253-ebe1-4220-8339-4f979e197613",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.security_risk }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "83231267-4a38-4d08-a2aa-d8dfd861ab34",
      "name": "Set Escalation Lock",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2432,
        -80
      ],
      "parameters": {
        "columns": {
          "value": {
            "chatId": "={{ $json.chatId }}",
            "escalatedAt": "={{ $now.toISO() }}"
          },
          "schema": [
            {
              "id": "chatId",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "chatId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "escalatedAt",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "escalatedAt",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "chatId"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 165582478,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit#gid=165582478",
          "cachedResultName": "Escalations"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit?usp=drivesdk",
          "cachedResultName": "CBox_Interactions_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "315f56e4-cc3f-4709-b7e3-e15d3144ba64",
      "name": "Notify Human Agent",
      "type": "n8n-nodes-base.telegram",
      "position": [
        2656,
        -80
      ],
      "parameters": {
        "text": "=\ud83d\udea8 Escalation! {{ $json.security_risk ? '- SECURITY RISK' : '' }}\nFrom: {{ $('Escalation Check').item.json.userName }} (chat ID {{ $json.chatId }})\nIntent: {{ $('Escalation Check').item.json.intent }}| Sentiment: {{ $('Escalation Check').item.json.sentiment }} | Security risk: {{ $('Escalation Check').item.json.security_risk }}\n\nTranscript:\n{{ $('Escalation Check').item.json.transcript }}",
        "chatId": "={{ $('Parse Classification JSON').item.json.chatId }}",
        "additionalFields": {
          "parse_mode": "HTML",
          "appendAttribution": false,
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "9011144c-c06e-43c8-86c0-a11af52c258f",
      "name": "Generate Voice Reply (TTS)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2880,
        -80
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/audio/speech",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "jsonBody": "={{ JSON.stringify({\n  model: \"canopylabs/orpheus-v1-english\",\n  voice: \"troy\",\n  input: \"Thanks for reaching out. I'm connecting you with a specialist now \u2014 someone will respond shortly.\" + ($('Parse Classification JSON').item.json.security_risk ? \" Reminder: never share your seed phrase, private key, or password with anyone, including support. We will never ask you for it.\" : \"\"),\n  response_format: \"wav\"\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "e182d469-178a-4c77-8959-4da87b78ae50",
      "name": "Send Voice Reply to User",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3088,
        -96
      ],
      "parameters": {
        "chatId": "={{ $('Parse Classification JSON').item.json.chatId }}",
        "operation": "sendAudio",
        "binaryData": true,
        "additionalFields": {
          "caption": "",
          "fileName": "CBox support",
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "efec6e5a-8ec2-4f91-985a-a5c641d09d33",
      "name": "Log Interaction",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3792,
        1168
      ],
      "parameters": {
        "columns": {
          "value": {
            "reply": "={{ $json.reply }}",
            "chatId": "={{ $json.chatId }}",
            "intent": "={{ $json.sentiment }}",
            "userName": "={{ $json.transcript }}",
            "escalated": "={{ $json.escalated }}",
            "sentiment": "={{ $json.sentiment }}",
            "timestamp": "={{ $json.timestamp }}",
            "transcript": "={{ $json.transcript }}",
            "securityRisk": "={{ $json.securityRisk }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "chatId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "chatId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "userName",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "userName",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "transcript",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "transcript",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "intent",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "intent",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "sentiment",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "sentiment",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "securityRisk",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "securityRisk",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "escalated",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "escalated",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "reply",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "reply",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 471911948,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit#gid=471911948",
          "cachedResultName": "Interactions "
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit?usp=drivesdk",
          "cachedResultName": "CBox_Interactions_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "894aae85-fe23-4c45-b711-d570bb2bb27b",
      "name": "Handle API Error",
      "type": "n8n-nodes-base.code",
      "position": [
        3216,
        640
      ],
      "parameters": {
        "jsCode": "let chatId, transcript = '(not available - failure occurred before transcript was ready)';\n\ntry {\n  chatId = $('Parse Classification JSON').item.json.chatId;\n  transcript = $('Parse Classification JSON').item.json.transcript;\n} catch (e) {}\n\nif (!chatId) {\n  try {\n    chatId = $('Extract Transcript (Voice)').item.json.chatId;\n    transcript = $('Extract Transcript (Voice)').item.json.transcript;\n  } catch (e) {}\n}\n\nif (!chatId) {\n  try {\n    chatId = $('Extract Transcript (Text)').item.json.chatId;\n    transcript = $('Extract Transcript (Text)').item.json.transcript;\n  } catch (e) {}\n}\n\nif (!chatId) {\n  try { chatId = $('Voice Message Trigger').item.json.message.chat.id; } catch (e) {}\n}\n\nconst errItem = $input.first().json;\nconst failedNode = $prevNode.name;\nconst errorMessage = errItem.error?.message || (typeof errItem.error === 'string' ? errItem.error : JSON.stringify(errItem).slice(0, 400));\n\nreturn [{\n  json: { chatId: chatId || 'unknown', transcript, failedNode, errorMessage, timestamp: new Date().toISOString() }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3dec8445-1656-47fe-ad74-78a592357a8b",
      "name": "Alert Slack (Error)",
      "type": "n8n-nodes-base.slack",
      "position": [
        3488,
        320
      ],
      "parameters": {
        "text": "=\ud83d\udd34 CBox voice agent error\nNode: {{ $json.failedNode }}\nChat: {{ $json.chatId }}\nTime: {{ $json.timestamp }}\n\nError: {{ $json.errorMessage }}\n\nTranscript (if available): {{ $json.transcript }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0ATQN2T51T",
          "cachedResultName": "all-soclear-consult"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "1f2ab610-fff3-41a3-a74a-c826e5dc0ad2",
      "name": "Log Error to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        3600,
        640
      ],
      "parameters": {
        "columns": {
          "value": {
            "chatId": "={{ $json.chatId }}",
            "timestamp": "={{ $json.timestamp }}",
            "failedNode": "={{ $json.failedNode }}",
            "transcript": "={{ $json.transcript }}",
            "errorMessage": "={{ $json.errorMessage }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "chatId",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "chatId",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "failedNode",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "failedNode",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "errorMessage",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "errorMessage",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "transcript",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "transcript",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1638655937,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit#gid=1638655937",
          "cachedResultName": "Errors"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1519n4v45cPvcRwfxHc8kAuVt8ldZTVA3rX-V9jGuSow/edit?usp=drivesdk",
          "cachedResultName": "CBox_Interactions_Log"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "55771084-b134-4dc3-9a20-6f521bbbd446",
      "name": "Fallback Reply to User",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3552,
        816
      ],
      "parameters": {
        "text": "Sorry, I'm having trouble processing that right now. Please try again in a moment \u2014 if this keeps happening, a support specialist will follow up shortly.",
        "chatId": "={{ $json.chatId }}",
        "additionalFields": {
          "appendAttribution": false,
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5bfce863-3933-4c37-9328-04a089567c17",
      "name": "Route by Intent",
      "type": "n8n-nodes-base.switch",
      "position": [
        2432,
        464
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "id": "61191c04-8100-4501-b18e-a686de2c4817",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.intent }}",
                    "rightValue": "faq"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "id": "a0c6e44e-02ac-47f1-a0ac-055466e4fa6c",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.intent }}",
                    "rightValue": "transaction_issue"
                  },
                  {
                    "id": "0698b674-8a75-44e9-add7-e8aa96908df6",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.intent }}",
                    "rightValue": "account_kyc"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "or",
                "conditions": [
                  {
                    "id": "a7a1ed60-7c71-428c-b730-c6c9dc90c843",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.intent }}",
                    "rightValue": "wallet_security"
                  },
                  {
                    "id": "1b988da5-c152-4363-9e23-a626bc3028ef",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.intent }}",
                    "rightValue": "trading_swap"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "security_trading"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "f3ecd346-3e2d-41ed-a5e6-9da24a7bfce7",
      "name": "Fast Model Reply (FAQ)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2864,
        304
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  model: \"llama-3.1-8b-instant\",\n  max_tokens: 200,\n  messages: [\n    { role: \"system\", content: \"You are a friendly, concise support assistant for CBox, a crypto wallet app. Answer ONLY using the FAQ reference below \u2014 do not add information that isn't in it. If the question isn't covered, say you're not sure and offer to connect them with support. Keep answers to 2-3 sentences. NEVER ask the user for their seed phrase, private key, or password.\\n\\nFAQ REFERENCE:\\nCBox is a self-custody wallet for storing, sending, receiving, and swapping assets. Supported networks: Ethereum, Polygon, Arbitrum, Base, Solana (custom networks addable in Settings > Networks). To create a wallet: tap Create New Wallet, save the 12-word recovery phrase - CBox never stores a copy, so losing it means losing the funds. Existing wallets can be imported via recovery phrase or hardware wallet (Ledger, Trezor). Deposits appear after enough confirmations (~12 on Ethereum, near-instant on Solana). Withdrawals stuck pending are almost always a gas fee or network congestion issue, not a CBox issue; a fee below network minimum can stall a tx for hours. Pending transactions can be 'sped up' with higher gas on most EVM networks but not edited directly. Daily withdrawal limits: $1,000/day unverified, $5,000/day verified (raisable on request). KYC is only required for bank/card deposits, fiat withdrawals, or raising limits - not for basic wallet use. KYC verification: most complete within a few minutes automatically; manual review can take up to 1-2 business days. Losing account access (not wallet access) with recovery phrase intact: restore on any device; for login/2FA issues, contact support with registered email. A recovery/seed phrase is the master key to the wallet - anyone with it has full, irreversible control; no password reset or support override can undo this. Extra security: Settings > Security for app-lock, login 2FA, and transaction confirmation thresholds. If compromised: move funds to a new wallet immediately, revoke token approvals under Settings > Connected Apps, then contact support. Swap failures are usually slippage set too low, insufficient gas, or a stale route - CBox shows the exact revert reason. Slippage: 0.5% works for most major pairs, 1-3% for low-liquidity tokens. Gas fees reflect network congestion, not a CBox fee; Slow/Standard/Fast tiers shown before confirming. Unsupported/unpriced tokens can still be held/transferred; add via Assets > Add Custom Token. CBox will NEVER ask for a recovery phrase, private key, or password, under any circumstance, by any channel.\" },\n    { role: \"user\", content: $('Parse Classification JSON').item.json.transcript }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "d1090d69-7d22-4db2-9a38-6b58cc4dbfc0",
      "name": "Extract Reply Text",
      "type": "n8n-nodes-base.code",
      "position": [
        3152,
        1168
      ],
      "parameters": {
        "jsCode": "const replyText = $input.first().json.choices[0].message.content;\nconst context = $('Parse Classification JSON').item.json;\n\nreturn [{\n  json: {\n    ...context,\n    replyText\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ee50dd2c-cdfd-4360-a852-80298978397c",
      "name": "Send Reply to User",
      "type": "n8n-nodes-base.telegram",
      "position": [
        3376,
        1168
      ],
      "parameters": {
        "text": "={{ $json.replyText }}",
        "chatId": "={{ $json.chatId }}",
        "additionalFields": {
          "appendAttribution": false,
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "75f2ee12-d6fd-4b9e-896a-4a5f6bc88543",
      "name": "Prepare Log Data",
      "type": "n8n-nodes-base.code",
      "position": [
        3568,
        1168
      ],
      "parameters": {
        "jsCode": "let context;\ntry { context = $('Parse Classification JSON').item.json; } catch (e) { context = {}; }\n\nlet replyText;\ntry { replyText = $('Extract Reply Text').item.json.replyText; } catch (e) { replyText = null; }\n\nconst escalated = context.sentiment === 'angry' || context.sentiment === 'frustrated' || context.security_risk === true;\n\nreturn [{\n  json: {\n    timestamp: new Date().toISOString(),\n    chatId: context.chatId,\n    userName: context.userName,\n    transcript: context.transcript,\n    intent: context.intent,\n    sentiment: context.sentiment,\n    securityRisk: context.security_risk,\n    escalated,\n    reply: escalated ? 'Escalated to a human specialist; sent the user a holding voice reply.' : replyText\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3e2ab16b-8e98-40cc-ad97-5eaee1a906a9",
      "name": "Contextual Reply (Transaction/KYC)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2720,
        480
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  model: \"llama-3.3-70b-versatile\",\n  max_tokens: 300,\n  messages: [\n    { role: \"system\", content: \"You are a CBox wallet support agent handling transaction status and KYC/account-limit questions. Use the FAQ reference for general policy. Explain what typically causes the user's situation and the concrete next steps they can take; if resolving it needs their specific account data, tell them what to check in-app or offer to connect them with support. NEVER ask for a seed phrase, private key, or password.\\n\\nFAQ REFERENCE:\\nDeposits appear after enough confirmations (~12 on Ethereum, near-instant on Solana). Withdrawals stuck pending are almost always a gas fee or network congestion issue; a fee below network minimum can stall a tx for hours. Pending tx can be 'sped up' with higher gas on EVM networks. Daily withdrawal limits: $1,000/day unverified, $5,000/day verified (raisable on request). KYC required only for bank/card deposits, fiat withdrawals, or raising limits. KYC verification: a few minutes automatically; manual review up to 1-2 business days. Account access issues (not wallet access): restore via recovery phrase on any device, or contact support with registered email for login/2FA issues.\" },\n    { role: \"user\", content: `Customer message: ${$json.transcript}` }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "a522680b-40ed-4b31-997f-1cbedea93c0e",
      "name": "Strong Model Reply (Security/Trading)",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueErrorOutput",
      "position": [
        2752,
        736
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={{ JSON.stringify({\n  model: \"llama-3.3-70b-versatile\",\n  max_tokens: 400,\n  messages: [\n    { role: \"system\", content: \"You are a senior CBox support agent handling wallet security and trading/swap issues. Ground answers in the FAQ reference below. Be precise about irreversibility of on-chain transactions. NEVER ask for a seed phrase, private key, or password - explicitly remind users legitimate support never asks for these on security-related topics.\\n\\nFAQ REFERENCE:\\nA recovery/seed phrase is the master key - anyone with it has full, irreversible control; no reset or override undoes this. Extra security: Settings > Security for app-lock, login 2FA, transaction confirmation thresholds. If compromised: move funds to a new wallet immediately, revoke token approvals under Settings > Connected Apps, then contact support - speed matters most since transactions can't be reversed. Swap failures: usually slippage too low, insufficient gas, or a stale route; CBox shows the exact revert reason. Slippage: 0.5% for major pairs, 1-3% for low-liquidity tokens. Gas fees reflect network congestion, not a CBox fee. Unsupported tokens can still be held/transferred via Add Custom Token. CBox will NEVER ask for a recovery phrase, private key, or password, under any circumstance.\" },\n    { role: \"user\", content: $('Parse Classification JSON').item.json.transcript }\n  ]\n}) }}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "groqApi"
      },
      "credentials": {
        "groqApi": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.2
    },
    {
      "id": "28ac21b2-9fd3-4974-9150-59f0d2af7783",
      "name": "Has Text?",
      "type": "n8n-nodes-base.if",
      "position": [
        448,
        992
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "1ff18317-c64b-4f82-b499-ab5f7247b76d",
              "operator": {
                "type": "string",
                "operation": "exists",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.text }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "48d5732a-3ad3-4403-b41d-c8cec30d56a7",
      "name": "Extract Transcript (Text)",
      "type": "n8n-nodes-base.code",
      "position": [
        784,
        768
      ],
      "parameters": {
        "jsCode": "const msg = $('Voice Message Trigger').first().json.message;\nreturn [{\n  json: {\n    transcript: msg.text,\n    chatId: msg.chat.id,\n    userId: msg.from.id,\n    userName: msg.from.first_name || 'Customer'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "dc6fbeda-04d3-443c-bca5-5a4de1ba3b36",
      "name": "Unsupported Message Reply",
      "type": "n8n-nodes-base.telegram",
      "position": [
        784,
        1008
      ],
      "parameters": {
        "text": "I can help with voice notes or text messages describing your issue \u2014 that message type isn't supported yet",
        "chatId": "={{ $json.message.chat.id }}",
        "additionalFields": {
          "appendAttribution": false,
          "disable_notification": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "19e50b1a-0d11-44ed-b15c-f3fafc557292",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -336,
        -656
      ],
      "parameters": {
        "width": 1412,
        "height": 676,
        "content": "# \ud83c\udf99\ufe0f CBox Wallet Voice & Text Support Agent\n\nTurns Telegram voice notes and text messages into a tiered crypto-wallet support agent. Voice is transcribed, then every message is classified for intent, sentiment and security risk. The flow escalates to a human or auto-answers with the right AI model, logging all interactions.\n\n### How it works\n1. Voice transcribes via Groq Whisper; text read directly; unknown types get an unsupported reply.\n2. A Groq LLM classifies intent, sentiment and security risk.\n3. Angry or risky messages escalate to a human \u2014 30-minute dedupe lock plus voice reply.\n4. Others receive fast, contextual or strong AI replies, logged to Sheets.\n\n### Setup\n- **Telegram** \u2014 two bot credentials via BotFather: the customer-facing bot receives messages and sends replies; the internal bot (Telegram account 2) powers Notify Human Agent.\n- **Groq** \u2014 shared `groqApi` key used by all HTTP nodes.\n- **Google Sheets** \u2014 a spreadsheet with Interactions, Errors and Escalations tabs.\n- **Slack** \u2014 an alert channel.\n\n### Customization\nEdit the FAQ text in each reply node, tune escalation rules in Escalation Check, and adjust the 30-minute lock window in Evaluate Escalation Lock.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "484b73e3-9e7f-4353-80d0-d7f91346c07b",
      "name": "Demo Video",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1120,
        -656
      ],
      "parameters": {
        "color": 4,
        "width": 764,
        "height": 676,
        "content": "## \ud83c\udfa5 Demo Video\n\nWatch a full walkthrough of this workflow on YouTube:\n\n\u25b6\ufe0f **[Watch the demo](https://youtu.be/1KO_LBOGkVQ)**\n\nhttps://youtu.be/1KO_LBOGkVQ\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d4978fdd-7426-4400-851b-26c3e37479fc",
      "name": "Section - Intake",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 1044,
        "height": 814,
        "content": "## 1\ufe0f\u20e3 Message Intake & Transcription\n\nRoutes each Telegram message by type:\n- **Voice** \u2192 download, fix filename, transcribe with **Groq Whisper**.\n- **Text** \u2192 use the message text directly.\n- **Other** \u2192 reply that it is unsupported.\n\nBoth paths feed the same classifier."
      },
      "typeVersion": 1
    },
    {
      "id": "d79f603e-0fee-43c9-b38c-d001ba65d50f",
      "name": "Section - Classify",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1072,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 1268,
        "height": 446,
        "content": "## 2\ufe0f\u20e3 Understanding (Intent & Sentiment)\n\nExtract the transcript + user context, then a Groq LLM classifies **intent**, **sentiment** and **security_risk** into strict JSON, which is parsed for routing."
      },
      "typeVersion": 1
    },
    {
      "id": "998e7296-5a23-4953-a7ca-0d67b44265cd",
      "name": "Section - Escalation",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2384,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 852,
        "height": 324,
        "content": "## 3\ufe0f\u20e3 Escalation & Human Handoff\n\nIf sentiment is **angry/frustrated** OR a **security risk** is detected, notify a human agent and send the user a reassuring **voice reply (TTS)** while a specialist follows up."
      },
      "typeVersion": 1
    },
    {
      "id": "549e9db9-bce3-434f-9139-40232f9c2b9a",
      "name": "Section - Routing",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2384,
        128
      ],
      "parameters": {
        "color": 7,
        "width": 628,
        "height": 840,
        "content": "## 4\ufe0f\u20e3 Intent Routing & AI Replies\n\nNon-escalated messages are routed by intent:\n- **FAQ** \u2192 fast model (llama-3.1-8b)\n- **Transaction / KYC** \u2192 contextual model (llama-3.3-70b)\n- **Security / Trading** \u2192 strong model (llama-3.3-70b)"
      },
      "typeVersion": 1
    },
    {
      "id": "9815358b-0aab-4464-b12e-103860bce26a",
      "name": "Section - Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3072,
        1008
      ],
      "parameters": {
        "color": 7,
        "width": 852,
        "height": 360,
        "content": "## 5\ufe0f\u20e3 Reply Delivery & Logging\n\nExtract the AI reply text, send it back to the user on Telegram, and append the full interaction to the **Google Sheets** log."
      },
      "typeVersion": 1
    },
    {
      "id": "0174451c-a267-40ff-ace2-a9c4734566f3",
      "name": "Section - Errors",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3072,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 692,
        "height": 824,
        "content": "## \u26a0\ufe0f Error Handling\n\nAny transcription/classification/reply/TTS failure routes here: build an error payload \u2192 **alert Slack**, **log to the Errors sheet**, and send the user a friendly **fallback message**."
      },
      "typeVersion": 1
    }
  ],
  "active": true,
  "settings": {
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "timeSavedMode": "fixed",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "bf44a66b-bee4-49f7-91b6-41d1dc7fe1bf",
  "nodeGroups": [],
  "connections": {
    "Has Text?": {
      "main": [
        [
          {
            "node": "Extract Transcript (Text)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Unsupported Message Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Voice?": {
      "main": [
        [
          {
            "node": "Get Voice File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Has Text?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Voice File": {
      "main": [
        [
          {
            "node": "Fix Audio Filename",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Intent": {
      "main": [
        [
          {
            "node": "Fast Model Reply (FAQ)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Contextual Reply (Transaction/KYC)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Strong Model Reply (Security/Trading)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Escalation Check": {
      "main": [
        [
          {
            "node": "Set Escalation Lock",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Route by Intent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Handle API Error": {
      "main": [
        [
          {
            "node": "Alert Slack (Error)",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Error to Sheet",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fallback Reply to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Log Data": {
      "main": [
        [
          {
            "node": "Log Interaction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Already Escalated?": {
      "main": [
        [
          {
            "node": "Holding Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Escalation Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Reply Text": {
      "main": [
        [
          {
            "node": "Send Reply to User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fix Audio Filename": {
      "main": [
        [
          {
            "node": "Transcribe (Whisper)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify Human Agent": {
      "main": [
        [
          {
            "node": "Generate Voice Reply (TTS)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Reply to User": {
      "main": [
        [
          {
            "node": "Prepare Log Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get row(s) in sheet": {
      "main": [
        [
          {
            "node": "Evaluate Escalation Lock",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Escalation Lock": {
      "main": [
        [
          {
            "node": "Notify Human Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Transcribe (Whisper)": {
      "main": [
        [
          {
            "node": "Extract Transcript (Voice)",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Voice Message Trigger": {
      "main": [
        [
          {
            "node": "Has Voice?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fast Model Reply (FAQ)": {
      "main": [
        [
          {
            "node": "Extract Reply Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Escalation Lock": {
      "main": [
        [
          {
            "node": "Already Escalated?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Voice Reply to User": {
      "main": [
        [
          {
            "node": "Log Interaction",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Transcript (Text)": {
      "main": [
        [
          {
            "node": "Classify Intent & Sentiment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Classification JSON": {
      "main": [
        [
          {
            "node": "Get row(s) in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Transcript (Voice)": {
      "main": [
        [
          {
            "node": "Classify Intent & Sentiment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Voice Reply (TTS)": {
      "main": [
        [
          {
            "node": "Send Voice Reply to User",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Intent & Sentiment": {
      "main": [
        [
          {
            "node": "Parse Classification JSON",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Contextual Reply (Transaction/KYC)": {
      "main": [
        [
          {
            "node": "Extract Reply Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Strong Model Reply (Security/Trading)": {
      "main": [
        [
          {
            "node": "Extract Reply Text",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Handle API 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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow turns Telegram voice notes and text messages into a support agent by transcribing audio with Groq Whisper, classifying intent/sentiment/security risk with Groq LLMs, escalating risky cases to a human via Telegram, and logging interactions and errors to Google…

Source: https://n8n.io/workflows/17522/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

This workflow listens for Telegram bot messages, uses OpenAI (gpt-4o-mini) to detect language and classify intent, then routes requests to either lead qualification, EMI calculation, or support handli

Telegram Trigger, OpenAI, Google Sheets +4
Slack & Telegram

This workflow captures rental applications from Telegram, uses OpenAI to extract applicant details and score risk after a credit/background API check, logs everything in Google Sheets, notifies the la

Slack, Error Trigger, Telegram +5
Slack & Telegram

IR-CLU — ربات فروش (احراز هویت + هوش مصنوعی + پرداخت کارت‌به‌کارت). Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 83 nodes.

Telegram Trigger, Google Sheets, Telegram +1
Slack & Telegram

IR-CLU — ربات فروش (احراز هویت + هوش مصنوعی + پرداخت کارت‌به‌کارت). Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 76 nodes.

Telegram Trigger, Google Sheets, Telegram +1
Slack & Telegram

Weather Bot - Main Handler. Uses telegramTrigger, googleSheets, telegram, httpRequest. Event-driven trigger; 65 nodes.

Telegram Trigger, Google Sheets, Telegram +1