AutomationFlowsSlack & Telegram › Channel Intent Router (template)

Channel Intent Router (template)

Channel Intent Router (Template). Uses redis, httpRequest, telegram. Webhook trigger; 16 nodes.

Webhook trigger★★★★☆ complexity16 nodesRedisHTTP RequestTelegram
Slack & Telegram Trigger: Webhook Nodes: 16 Complexity: ★★★★☆ Added:

This workflow follows the HTTP Request → Redis 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
{
  "name": "Channel Intent Router (Template)",
  "tags": [
    "staging",
    "template",
    "channel-router"
  ],
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "{{$env.WEBHOOK_PATH}}",
        "responseMode": "lastNode",
        "options": {}
      },
      "id": "router-trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 1,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// HMAC-SHA256 verification Code node\n// Verifies x-signature header against HMAC_SECRET env var\n// Returns early (401) if mismatch\n\nconst crypto = require('crypto');\nconst signature = $input.item.json.headers?.['x-signature'] || $input.item.json.headers?.['x-hub-signature-256'] || '';\nconst hmacSecret = process.env.HMAC_SECRET;\nconst body = JSON.stringify($input.item.json.body || $input.item.json);\n\nif (!hmacSecret) {\n  // No secret configured - skip verification in dev mode\n  return { json: { ...$input.item.json, hmac_verified: true, skip_verify: true } };\n}\n\nconst expectedSignature = 'sha256=' + crypto.createHmac('sha256', hmacSecret).update(body).digest('hex');\nconst isValid = crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));\n\nif (!isValid && signature) {\n  // Invalid signature - return error response\n  throw new Error('HMAC verification failed');\n}\n\nreturn { json: { ...$input.item.json, hmac_verified: true } };"
      },
      "id": "hmac-verify",
      "name": "Verify HMAC Signature",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        470,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse message from either Telegram or Baileys format\n// Normalize to standard format for MiniMax LLM parsing\n\nconst body = $input.item.json.body || $input.item.json;\n\n// Detect channel\nlet message = '';\nlet userId = '';\nlet channel = 'unknown';\n\n// Telegram format\nif (body.message?.text) {\n  message = body.message.text;\n  userId = body.message?.chat?.id?.toString() || '';\n  channel = 'telegram';\n}\n// Baileys format (WhatsApp)\nelse if (body.messages && body.messages[0]) {\n  const msg = body.messages[0];\n  message = msg.message?.conversation || msg.message?.extendedTextMessage?.text || '';\n  userId = msg.key?.remoteJid || '';\n  channel = 'baileys';\n}\n// WhatsApp Cloud API format\nelse if (body.entry && body.entry[0]?.changes) {\n  const changes = body.entry[0].changes[0];\n  const msg = changes.value?.messages?.[0];\n  message = msg?.text?.body || '';\n  userId = msg?.from || '';\n  channel = 'whatsapp';\n}\n\n// Extract intent keyword patterns for routing\nconst messageLower = message.toLowerCase().trim();\n\nconst orderKeywords = ['order', 'buy', 'purchase', 'get proxy', 'want proxy'];\nconst trialKeywords = ['free trial', 'trial', 'free plan', 'try free'];\nconst statusKeywords = ['status', 'check', 'track', 'where'];\nconst helpKeywords = ['help', 'menu', 'start', 'hello', 'hi'];\n\nconst intent = \n  orderKeywords.some(k => messageLower.includes(k)) ? 'order' :\n  trialKeywords.some(k => messageLower.includes(k)) ? 'free_trial' :\n  statusKeywords.some(k => messageLower.includes(k)) ? 'status' :\n  helpKeywords.some(k => messageLower.includes(k)) ? 'help' :\n  'unknown';\n\nreturn {\n  json: {\n    channel,\n    user_id: userId,\n    message,\n    message_raw: body,\n    intent,\n    reply_node_type: process.env.REPLY_NODE_TYPE || 'telegram'\n  }\n};"
      },
      "id": "parse-message",
      "name": "Parse & Normalize Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        690,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Idempotency check using Redis\n// Key prefix is configurable via IDEMPOTENCY_PREFIX env var\n// Default uses staging: prefix for staging environment\n\nconst crypto = require('crypto');\nconst body = $input.item.json.body || $input.item.json;\n\n// Generate idempotency key from message data\nconst messageId = body.update_id || body.messages?.[0]?.key?.id || body.entry?.[0]?.changes?.[0]?.value?.messages?.[0]?.id || crypto.randomBytes(8).toString('hex');\nconst prefix = process.env.IDEMPOTENCY_PREFIX || 'staging:';\nconst idempotencyKey = `${prefix}idempotency:${messageId}`;\n\n// Store the key in Redis (we'll set via Redis node in actual execution)\n// This Code node prepares the key for the Redis Set node\n\nreturn {\n  json: {\n    ...$input.item.json,\n    idempotency_key: idempotencyKey,\n    already_processed: false\n  }\n};"
      },
      "id": "idempotency-prep",
      "name": "Prepare Idempotency Key",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        910,
        300
      ]
    },
    {
      "parameters": {
        "rule": "set",
        "key": "{{$json.idempotency_key}}",
        "value": "1",
        "options": {
          "ttl": 86400,
          "setNX": true
        }
      },
      "id": "idempotency-check",
      "name": "Idempotency Redis Check",
      "type": "n8n-nodes-base.redis",
      "typeVersion": 1,
      "position": [
        1130,
        300
      ],
      "notes": "Check if message already processed. Skip if key exists (already_processed=true)"
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "id": "cond-already-done",
              "leftValue": "={{$json.already_processed}}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "if-not-processed",
      "name": "If Not Already Processed",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        1350,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.minimax.chat/v1/chat/completions",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{$env.MINIMAX_API_KEY}}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "MiniMax-M2"
            },
            {
              "name": "messages",
              "value": [
                {
                  "role": "system",
                  "content": "You are Styxproxy, a WhatsApp/Telegram proxy reseller assistant. Parse customer messages and extract intent. Available intents: order, renewal, status, help, free_trial, recovery, how_to_use, check_data, referral_share, unknown. Respond with JSON: { intent, entities, original_message }"
                },
                {
                  "role": "user",
                  "content": "={{$json.message}}"
                }
              ]
            }
          ]
        },
        "options": {
          "timeout": 10000
        }
      },
      "id": "llm-parse",
      "name": "MiniMax LLM Parser",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        1570,
        300
      ],
      "notes": "Extract intent + entities using LLM"
    },
    {
      "parameters": {
        "jsCode": "// Parse LLM response and extract intent\n// Handle both JSON string and object responses\n\nlet content = $input.item.json.choices?.[0]?.message?.content || '';\nlet parsed = {};\n\ntry {\n  // Try to parse as JSON\n  if (typeof content === 'string') {\n    // Handle potential markdown code blocks\n    content = content.replace(/^```json\\n?/, '').replace(/\\n?```$/, '');\n    parsed = JSON.parse(content);\n  } else {\n    parsed = content;\n  }\n} catch (e) {\n  // Fallback: keyword-based intent detection\n  const msg = ($input.item.json.message || '').toLowerCase();\n  parsed = {\n    intent: msg.includes('order') ? 'order' : \n            msg.includes('trial') ? 'free_trial' : \n            msg.includes('status') ? 'status' : \n            msg.includes('help') ? 'help' : 'unknown',\n    entities: {},\n    original_message: msg\n  };\n}\n\nreturn {\n  json: {\n    ...$input.item.json,\n    intent: parsed.intent || 'unknown',\n    entities: parsed.entities || {},\n    llm_raw: content\n  }\n};"
      },
      "id": "parse-llm",
      "name": "Parse LLM Response",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1790,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Route reply based on REPLY_NODE_TYPE env var\n// Switches between telegram and baileys (WhatsApp) reply nodes\n\nconst replyType = process.env.REPLY_NODE_TYPE || 'telegram';\nconst channel = $input.item.json.channel;\n\n// Determine reply configuration\nconst replyConfig = {\n  node_type: replyType,\n  // For Telegram: use Telegram node\n  // For Baileys: use HTTP webhook to Baileys runtime\n  use_telegram: replyType === 'telegram' || channel === 'telegram',\n  use_baileys: replyType === 'baileys' || channel === 'baileys' || channel === 'whatsapp'\n};\n\nreturn {\n  json: {\n    ...$input.item.json,\n    reply_config: replyConfig,\n    will_use_telegram: replyConfig.use_telegram,\n    will_use_baileys: replyConfig.use_baileys\n  }\n};"
      },
      "id": "route-reply",
      "name": "Route Reply Channel",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2010,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-use-tg",
              "leftValue": "={{$json.will_use_telegram}}",
              "rightValue": true,
              "operation": "equals"
            }
          ]
        },
        "options": {}
      },
      "id": "if-telegram",
      "name": "If Telegram Reply",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        2230,
        200
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond-use-baileys",
              "leftValue": "={{$json.will_use_baileys}}",
              "rightValue": true,
              "operation": "equals"
            }
          ]
        },
        "options": {}
      },
      "id": "if-baileys",
      "name": "If Baileys Reply",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        2230,
        500
      ]
    },
    {
      "parameters": {
        "jsCode": "// Generate help menu message\nconst message = `\ud83c\uddf3\ud83c\uddec **Styxproxy Proxy**\n\nI can help you with:\n\n\ud83d\uded2 **Order** \u2014 ISP, Residential, Mobile, Datacenter\n\ud83d\udcb3 **Check Status** \u2014 Track your order\n\ud83d\udcb0 **Pricing** \u2014 See all plans\n\u2753 **Help** \u2014 How to get started\n\ud83d\udd17 **Free Trial** \u2014 Get a free proxy\n\nWhat would you like to do?`;\n\nreturn { json: { ...$input.item.json, reply_message: message } };"
      },
      "id": "gen-help",
      "name": "Generate Help Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2450,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "// Generate fallback message for unknown intent\nconst message = `\ud83e\udd16 I'm not sure I understood that. Could you rephrase?\n\nYou can say things like:\n- \"Order ISP UK\"\n- \"Check my order status\"\n- \"Help\"\n- \"How do I use proxies?\"`;\n\nreturn { json: { ...$input.item.json, reply_message: message } };"
      },
      "id": "gen-fallback",
      "name": "Generate Fallback Message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2450,
        420
      ]
    },
    {
      "parameters": {
        "chatId": "={{$json.user_id}}",
        "message": "={{$json.reply_message}}",
        "options": {}
      },
      "id": "telegram-reply",
      "name": "Reply via Telegram",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1,
      "position": [
        2670,
        200
      ],
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "{{$env.BAILEYS_RUNTIME_URL}}/send-message",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "phone",
              "value": "={{$json.user_id}}"
            },
            {
              "name": "message",
              "value": "={{$json.reply_message}}"
            }
          ]
        },
        "options": {}
      },
      "id": "baileys-reply",
      "name": "Reply via Baileys HTTP",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 3,
      "position": [
        2670,
        500
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\":\"ok\"}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "respond-200",
      "name": "Respond 200 OK",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1,
      "position": [
        2890,
        300
      ]
    }
  ],
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Verify HMAC Signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Verify HMAC Signature": {
      "main": [
        [
          {
            "node": "Parse & Normalize Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse & Normalize Message": {
      "main": [
        [
          {
            "node": "Prepare Idempotency Key",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Idempotency Key": {
      "main": [
        [
          {
            "node": "Idempotency Redis Check",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Idempotency Redis Check": {
      "main": [
        [
          {
            "node": "If Not Already Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Not Already Processed": {
      "main": [
        [
          {
            "node": "MiniMax LLM Parser",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "MiniMax LLM Parser": {
      "main": [
        [
          {
            "node": "Parse LLM Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse LLM Response": {
      "main": [
        [
          {
            "node": "Route Reply Channel",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Reply Channel": {
      "main": [
        [
          {
            "node": "If Telegram Reply",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "If Baileys Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Telegram Reply": {
      "main": [
        [
          {
            "node": "Generate Help Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Fallback Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "If Baileys Reply": {
      "main": [
        [
          {
            "node": "Generate Help Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Generate Fallback Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Help Message": {
      "main": [
        [
          {
            "node": "Reply via Telegram",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reply via Baileys HTTP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Fallback Message": {
      "main": [
        [
          {
            "node": "Reply via Telegram",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Reply via Baileys HTTP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reply via Telegram": {
      "main": [
        [
          {
            "node": "Respond 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Reply via Baileys HTTP": {
      "main": [
        [
          {
            "node": "Respond 200 OK",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

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

Channel Intent Router (Template). Uses redis, httpRequest, telegram. Webhook trigger; 16 nodes.

Source: https://github.com/sonnyagent30-beep/Styxproxy/blob/878d93ddb0424068ef90bf013fa3a31461b471a6/.n8n/workflows/staging/01-channel-intent-router.json — 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

[](https://www.linkedin.com/in/mosaab-yassir-lafrimi/)[](https://t.me/joevenner)

HTTP Request, Redis, S3 +1
Slack & Telegram

Shared Checkout Staging Handler. Uses redis, httpRequest, telegram. Webhook trigger; 20 nodes.

Redis, HTTP Request, Telegram
Slack & Telegram

Telegram Order Staging Handler. Uses redis, httpRequest, telegram. Webhook trigger; 17 nodes.

Redis, HTTP Request, Telegram
Slack & Telegram

WF_UNIFIED_LEGAL_AUTOMATION. Uses googleSheets, httpRequest, telegram, telegramTrigger. Webhook trigger; 53 nodes.

Google Sheets, HTTP Request, Telegram +1
Slack & Telegram

qualiopi. Uses airtable, telegram, emailSend, httpRequest. Webhook trigger; 51 nodes.

Airtable, Telegram, Email Send +3