AutomationFlowsAI & RAG › Get a Daily Financial News Digest on Telegram with Mistral and RSS Feeds

Get a Daily Financial News Digest on Telegram with Mistral and RSS Feeds

ByCordexa Technologies @cordexa on n8n.io

Automatically fetch, rank, and summarize the top financial stories from curated RSS feeds each day, then deliver a concise AI-written digest to Telegram and log the run to Google Sheets. Runs on a daily schedule and reads 8 curated financial RSS feeds. Loops through each feed…

Cron / scheduled trigger★★★★☆ complexity27 nodesGoogle SheetsHTTP RequestRSS Feed Read
AI & RAG Trigger: Cron / scheduled Nodes: 27 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #14172 — 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
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "293a2733-fefb-4587-a7fd-c503effb4a3a",
      "name": "Digest Complete",
      "type": "n8n-nodes-base.set",
      "position": [
        2848,
        -144
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "dc1",
              "name": "status",
              "type": "string",
              "value": "Digest delivered"
            },
            {
              "id": "dc2",
              "name": "timestamp",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            },
            {
              "id": "dc3",
              "name": "storiesSent",
              "type": "number",
              "value": "={{ $('Build Telegram Payload').item.json.topStories.length }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "a4144121-78d9-46b9-9243-624c3c74e701",
      "name": "Log Digest to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2624,
        -144
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ new Date().toLocaleDateString('en-US') }}",
            "Run ID": "={{ $execution.id }}",
            "Timestamp": "={{ new Date().toISOString() }}",
            "Stories Count": "={{ $('Build Telegram Payload').item.json.topStories.length }}",
            "Story 1 Title": "={{ $('Build Telegram Payload').item.json.topStories[0]?.title || '' }}",
            "Story 2 Title": "={{ $('Build Telegram Payload').item.json.topStories[1]?.title || '' }}",
            "Story 3 Title": "={{ $('Build Telegram Payload').item.json.topStories[2]?.title || '' }}",
            "Story 4 Title": "={{ $('Build Telegram Payload').item.json.topStories[3]?.title || '' }}",
            "Story 5 Title": "={{ $('Build Telegram Payload').item.json.topStories[4]?.title || '' }}",
            "Telegram Status": "={{ $('Send to Telegram').item.json.ok ? 'SENT' : 'FAILED' }}",
            "Total Articles Collected": "={{ $('Build Telegram Payload').item.json.totalCollected }}"
          },
          "schema": [
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Stories Count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Stories Count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Story 1 Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Story 1 Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Story 2 Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Story 2 Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Story 3 Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Story 3 Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Story 4 Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Story 4 Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Story 5 Title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Story 5 Title",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Articles Collected",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Total Articles Collected",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Telegram Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Telegram Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Run ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Run ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Digest_Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('\ud83d\udccb RSS Feed Config1').first().json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "e9cc7653-2c62-48a4-b842-4d70411f95ba",
      "name": "Send to Telegram",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2224,
        -128
      ],
      "parameters": {
        "url": "={{ 'https://api.telegram.org/bot' + $('\ud83d\udccb RSS Feed Config1').first().json.telegramBotToken + '/sendMessage' }}",
        "body": "={{ $json.telegramPayload }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "756014c1-876b-45c2-a264-1a01dd05767a",
      "name": "Extract Digest",
      "type": "n8n-nodes-base.set",
      "position": [
        1872,
        -128
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ed1",
              "name": "digestText",
              "type": "string",
              "value": "={{ $json.choices && $json.choices[0] ? $json.choices[0].message.content.trim() : 'Digest generation failed' }}"
            },
            {
              "id": "ed2",
              "name": "topStories",
              "type": "array",
              "value": "={{ $('Build NIM Payload').item.json.topStories }}"
            },
            {
              "id": "ed3",
              "name": "totalCollected",
              "type": "number",
              "value": "={{ $('Build NIM Payload').item.json.totalCollected }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "437127c2-f8d7-4605-9807-67875f422eb0",
      "name": "Generate Digest (NIM)",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1648,
        -80
      ],
      "parameters": {
        "url": "https://integrate.api.nvidia.com/v1/chat/completions",
        "body": "={{ $json.nimPayload }}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "rawContentType": "application/json",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "821a7e7a-c6f8-41a8-b808-8d4a63ce2e8d",
      "name": "No Stories Alert",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1552,
        368
      ],
      "parameters": {
        "url": "={{ 'https://api.telegram.org/bot' + $('\ud83d\udccb RSS Feed Config1').first().json.telegramBotToken + '/sendMessage' }}",
        "body": "={\n  \"chat_id\": \"{{ $('\ud83d\udccb RSS Feed Config1').first().json.telegramChatId }}\",\n  \"text\": \"No fresh finance stories were found in the current freshness window. Check the feeds or increase freshnessHours in \ud83d\udccb RSS Feed Config1.\"\n}",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "raw",
        "rawContentType": "application/json"
      },
      "typeVersion": 4.2,
      "continueOnFail": true
    },
    {
      "id": "10687201-bec2-4505-9479-76a4be5770c6",
      "name": "Any Stories Today?",
      "type": "n8n-nodes-base.if",
      "position": [
        960,
        -64
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "c1",
              "operator": {
                "name": "filter.operator.gt",
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.topStories ? $json.topStories.length : 0 }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "5ce23e1a-ae6c-460e-a91f-dd143074fc7f",
      "name": "\ud83d\udccb RSS Feed Config1",
      "type": "n8n-nodes-base.set",
      "position": [
        400,
        -64
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a1",
              "name": "rssFeeds",
              "type": "array",
              "value": [
                {
                  "url": "https://feeds.a.dj.com/rss/RSSMarketsMain.xml",
                  "tier": 1,
                  "source": "WSJ Markets"
                },
                {
                  "url": "https://feeds.marketwatch.com/marketwatch/topstories/",
                  "tier": 1,
                  "source": "MarketWatch"
                },
                {
                  "url": "https://www.investing.com/rss/news.rss",
                  "tier": 2,
                  "source": "Investing.com All News"
                },
                {
                  "url": "https://seekingalpha.com/market_currents.xml",
                  "tier": 1,
                  "source": "Seeking Alpha All News"
                },
                {
                  "url": "https://www.cnbc.com/id/1+1234567890/device/rss/rss.html",
                  "tier": 1,
                  "source": "CNBC Top News"
                },
                {
                  "url": "https://www.investing.com/rss/news_25.rss",
                  "tier": 2,
                  "source": "Investing.com Stock Market News"
                },
                {
                  "url": "https://seekingalpha.com/tag/wall-st-breakfast.xml",
                  "tier": 2,
                  "source": "Seeking Alpha Wall Street Breakfast"
                },
                {
                  "url": "https://feeds.a.dj.com/rss/WSJcomUSBusiness.xml",
                  "tier": 1,
                  "source": "WSJ U.S. Business"
                }
              ]
            },
            {
              "id": "a3",
              "name": "telegramBotToken",
              "type": "string",
              "value": "YOUR_TELEGRAM_BOT_TOKEN"
            },
            {
              "id": "a4",
              "name": "telegramChatId",
              "type": "string",
              "value": "YOUR_TELEGRAM_CHAT_ID_OR_@CHANNELNAME"
            },
            {
              "id": "a5",
              "name": "maxStoriesInDigest",
              "type": "number",
              "value": 5
            },
            {
              "id": "a6",
              "name": "freshnessHours",
              "type": "number",
              "value": 24
            },
            {
              "id": "a7",
              "name": "googleSheetId",
              "type": "string",
              "value": "REPLACE_WITH_YOUR_GOOGLE_SHEET_ID"
            },
            {
              "id": "a8",
              "name": "runId",
              "type": "string",
              "value": "={{ $execution.id }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f8b220ba-ff59-4654-9e77-b3eb2404bcfd",
      "name": "\u23f0 Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        192,
        -64
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 10 * * *"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "39afbb3e-6bf5-46d0-a38a-31807633428a",
      "name": "Generate Feed Items",
      "type": "n8n-nodes-base.code",
      "position": [
        640,
        -64
      ],
      "parameters": {
        "jsCode": "const config = $input.first().json;\nconst feeds = config.rssFeeds;\nreturn feeds.map(feed => ({\n  json: {\n    feedUrl: feed.url,\n    feedSource: feed.source,\n    feedTier: feed.tier\n  }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "7029c4a0-787c-46e5-9e7c-3b9c807ce480",
      "name": "Loop Over Feeds",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        944,
        -272
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "7e21c963-8d51-4c54-a074-416c5db63e45",
      "name": "Read RSS Feed",
      "type": "n8n-nodes-base.rssFeedRead",
      "position": [
        1328,
        -384
      ],
      "parameters": {
        "url": "={{ $json.feedUrl }}",
        "options": {}
      },
      "typeVersion": 1.1,
      "continueOnFail": true
    },
    {
      "id": "6b0de010-3697-4f15-8576-b873e9bc26c4",
      "name": "Tag Articles",
      "type": "n8n-nodes-base.code",
      "position": [
        1680,
        -320
      ],
      "parameters": {
        "jsCode": "const items = $input.all();\nreturn items.map(item => {\n  const feedSource = $('Loop Over Feeds').item.json.feedSource || 'Unknown';\n  const feedTier = $('Loop Over Feeds').item.json.feedTier || 3;\n  return {\n    json: {\n      title: item.json.title || '',\n      link: item.json.link || '',\n      pubDate: item.json.pubDate || item.json.isoDate || '',\n      description: (item.json.contentSnippet || item.json.content || item.json.summary || '').slice(0, 400),\n      sourceName: feedSource,\n      tier: feedTier\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "852bc0e4-c1b9-4f0e-b90c-2e3689cb150b",
      "name": "Aggregate and Rank",
      "type": "n8n-nodes-base.code",
      "position": [
        1808,
        288
      ],
      "parameters": {
        "jsCode": "const staticData = $getWorkflowStaticData('global');\nconst config = $('\ud83d\udccb RSS Feed Config1').first().json;\nconst currentRunId = config.runId;\n\nif (staticData.lastRunId !== currentRunId) {\n  staticData.collected = [];\n  staticData.lastRunId = currentRunId;\n  staticData.feedCount = 0;\n}\n\nconst totalFeeds = config.rssFeeds.length;\n\nconst newItems = $input.all().map(i => i.json).filter(a => a.title && a.link);\nstaticData.collected.push(...newItems);\nstaticData.feedCount = (staticData.feedCount || 0) + 1;\n\nconst allFeedsProcessed = staticData.feedCount >= totalFeeds;\n\nif (!allFeedsProcessed) {\n  return [{ json: { waiting: true, feedsProcessed: staticData.feedCount, totalFeeds } }];\n}\n\nconst freshnessMs = (config.freshnessHours || 24) * 60 * 60 * 1000;\nconst cutoff = Date.now() - freshnessMs;\nconst maxStories = config.maxStoriesInDigest || 5;\nconst bannedWords = ['sponsored', 'advertisement', 'partner content', 'paid post'];\n\nconst valid = staticData.collected.filter(a => {\n  if (!a.title || !a.link) return false;\n  const pub = a.pubDate ? new Date(a.pubDate).getTime() : 0;\n  if (pub && pub < cutoff) return false;\n  const titleLower = a.title.toLowerCase();\n  if (bannedWords.some(w => titleLower.includes(w))) return false;\n  return true;\n});\n\nconst seenLinks = new Set();\nconst deduped = valid.filter(a => {\n  if (seenLinks.has(a.link)) return false;\n  seenLinks.add(a.link);\n  return true;\n});\n\nconst scored = deduped.map(a => {\n  let score = 0;\n  if (a.tier === 1) score += 3;\n  else if (a.tier === 2) score += 2;\n  else score += 1;\n\n  const age = a.pubDate ? Date.now() - new Date(a.pubDate).getTime() : 999999999;\n  const hours = age / (1000 * 60 * 60);\n  if (hours <= 6) score += 3;\n  else if (hours <= 12) score += 2;\n  else if (hours <= 18) score += 1;\n\n  const titleLower = (a.title || '').toLowerCase();\n  const keywords = [\n    'fed', 'federal reserve', 'inflation', 'cpi', 'ppi', 'jobs', 'payrolls',\n    'earnings', 'guidance', 'revenue', 'profit', 'margin', 'forecast',\n    'stocks', 'shares', 'bond', 'bonds', 'yield', 'treasury', 'oil', 'gold',\n    'crypto', 'bitcoin', 'merger', 'acquisition', 'ipo', 'tariff', 'rate cut',\n    'rate hike', 'downgrade', 'upgrade', 'beats', 'misses', 'announce'\n  ];\n  keywords.forEach(k => { if (titleLower.includes(k)) score += 1; });\n\n  return { ...a, score };\n});\n\nconst seenTitles = new Set();\nconst topStories = scored\n  .filter(a => {\n    const key = a.title.toLowerCase().slice(0, 40);\n    if (seenTitles.has(key)) return false;\n    seenTitles.add(key);\n    return true;\n  })\n  .sort((a, b) => b.score - a.score)\n  .slice(0, maxStories);\n\nstaticData.collected = [];\nstaticData.feedCount = 0;\n\nif (topStories.length === 0) {\n  return [{ json: { topStories: [], empty: true, totalCollected: deduped.length } }];\n}\n\nreturn [{ json: { topStories, totalCollected: deduped.length } }];"
      },
      "typeVersion": 2
    },
    {
      "id": "112bfa39-9a02-43d8-819c-74cf9daa40e4",
      "name": "Is Processing Done?",
      "type": "n8n-nodes-base.if",
      "position": [
        2000,
        48
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "done_check",
              "operator": {
                "name": "filter.operator.notEquals",
                "type": "boolean",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.waiting }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "6f8bd1f6-da0f-4399-bd35-ba83e9961238",
      "name": "Build NIM Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        1440,
        -80
      ],
      "parameters": {
        "jsCode": "const stories = $input.first().json.topStories;\n\nconst userContent = 'Write a daily finance digest from these top ' +\n  stories.length + ' stories:\\n\\n' +\n  stories.map((s, i) => {\n    const title = (s.title || '').replace(/[\\r\\n]/g, ' ').trim();\n    const source = (s.sourceName || '').trim();\n    const published = (s.pubDate || '').trim();\n    const summary = (s.description || '').replace(/[\\r\\n]/g, ' ').trim().slice(0, 300);\n    const link = (s.link || '').trim();\n    return (i + 1) + '. Title: ' + title +\n      '\\nSource: ' + source +\n      '\\nPublished: ' + published +\n      '\\nSummary: ' + summary +\n      '\\nLink: ' + link;\n  }).join('\\n\\n');\n\nconst systemContent = 'You write a daily finance news digest for investors and operators. Write a sharp, direct digest with one clear insight per story. Format exactly like this in plain text:\\n\\n1. [Story Title]\\n[2-3 sentence summary. What happened, why it matters, one sharp insight.]\\nSource: [Source Name]\\nLink: [Article URL]\\n\\n2. [Story Title]\\n[2-3 sentence summary.]\\nSource: [Source Name]\\nLink: [Article URL]\\n\\n3. [Story Title]\\n[2-3 sentence summary.]\\nSource: [Source Name]\\nLink: [Article URL]\\n\\n4. [Story Title]\\n[2-3 sentence summary.]\\nSource: [Source Name]\\nLink: [Article URL]\\n\\n5. [Story Title]\\n[2-3 sentence summary.]\\nSource: [Source Name]\\nLink: [Article URL]\\n\\nToday\\'s Signal: [One sharp sentence about the overall market or business theme]\\n\\nRules: No em dashes. No hype words. Use plain text only. Each summary max 50 words. Never use HTML tags.';\n\nconst payload = {\n  model: 'mistralai/mistral-large-3-675b-instruct-2512',\n  max_tokens: 1500,\n  temperature: 0.7,\n  top_p: 0.9,\n  messages: [\n    { role: 'system', content: systemContent },\n    { role: 'user', content: userContent }\n  ]\n};\n\nreturn [{\n  json: {\n    nimPayload: JSON.stringify(payload),\n    topStories: stories,\n    totalCollected: $input.first().json.totalCollected\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "3e26bf8f-6404-42f8-9a7e-9538cb9e7053",
      "name": "Build Telegram Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        2048,
        -128
      ],
      "parameters": {
        "jsCode": "const rawDigest = $input.first().json.digestText || 'No digest available';\nconst chatId = $('\ud83d\udccb RSS Feed Config1').first().json.telegramChatId;\nconst feedCount = $('\ud83d\udccb RSS Feed Config1').first().json.rssFeeds.length;\n\n// Edit header and footer here if you want to rebrand the digest\nconst header = 'DAILY FINANCE DIGEST\\n' +\n               'Your signal in the financial noise\\n' +\n               '\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n\\n';\n\nconst footer = '\\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\\n' +\n               `Today\\'s digest curated from ${feedCount} finance feeds.\\n` +\n               'Built by Cordexa Technologies\\n' +\n               'https://cordexa.tech';\n\nconst digestText = header + rawDigest + footer;\n\nconst payload = {\n  chat_id: chatId,\n  text: digestText,\n  disable_web_page_preview: true\n};\n\nreturn [{\n  json: {\n    telegramPayload: JSON.stringify(payload),\n    digestText,\n    topStories: $input.first().json.topStories,\n    totalCollected: $input.first().json.totalCollected\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f24db22a-40e6-423e-99df-9d296d455c32",
      "name": "Telegram Send OK?",
      "type": "n8n-nodes-base.if",
      "position": [
        2400,
        -128
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ok_check",
              "operator": {
                "name": "filter.operator.equals",
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.ok === true }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4fad0fa3-c295-415a-8475-9d8baf0f67c3",
      "name": "Build Error Log Row",
      "type": "n8n-nodes-base.set",
      "position": [
        2448,
        208
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "er1",
              "name": "Timestamp",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            },
            {
              "id": "er2",
              "name": "Run ID",
              "type": "string",
              "value": "={{ $execution.id }}"
            },
            {
              "id": "er3",
              "name": "Stage",
              "type": "string",
              "value": "Send to Telegram"
            },
            {
              "id": "er4",
              "name": "Error Message",
              "type": "string",
              "value": "={{ $json.message || $json.error || $json.description || 'Telegram request failed' }}"
            },
            {
              "id": "er5",
              "name": "HTTP Status",
              "type": "string",
              "value": "={{ $json.statusCode || '' }}"
            },
            {
              "id": "er6",
              "name": "Total Articles Collected",
              "type": "number",
              "value": "={{ $('Build Telegram Payload').item.json.totalCollected || 0 }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f1524be6-cf67-41e2-a2d6-28f4d9e4cf90",
      "name": "Log Error to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2640,
        208
      ],
      "parameters": {
        "columns": {
          "value": {
            "Stage": "={{ $json.Stage }}",
            "Run ID": "={{ $json['Run ID'] }}",
            "Timestamp": "={{ $json.Timestamp }}",
            "HTTP Status": "={{ $json['HTTP Status'] }}",
            "Error Message": "={{ $json['Error Message'] }}",
            "Total Articles Collected": "={{ $json['Total Articles Collected'] }}"
          },
          "schema": [
            {
              "id": "Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Run ID",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Run ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Stage",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Stage",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Error Message",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Error Message",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "HTTP Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "HTTP Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Total Articles Collected",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Total Articles Collected",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Error_Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('\ud83d\udccb RSS Feed Config1').first().json.googleSheetId }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5,
      "continueOnFail": true
    },
    {
      "id": "f801e595-cbf0-4594-8bea-3e80b03874fa",
      "name": "Digest Failed",
      "type": "n8n-nodes-base.set",
      "position": [
        2848,
        208
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "df1",
              "name": "status",
              "type": "string",
              "value": "Digest delivery failed"
            },
            {
              "id": "df2",
              "name": "timestamp",
              "type": "string",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "024b6d54-1b76-4a92-8f76-49922b78f7ce",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -560,
        -544
      ],
      "parameters": {
        "color": "#133FA4",
        "width": 680,
        "height": 712,
        "content": "## Overview\n\n**Who it's for:** Operators, investors, analysts, founders, and solo builders who want a daily finance news digest delivered to Telegram without manually checking multiple RSS feeds.\n\n**What it does:** Runs once per day, reads recent stories from curated finance RSS feeds, ranks the strongest items, uses NVIDIA NIM with Mistral Large 3 to write a concise digest, sends the digest to Telegram, and logs the run to Google Sheets.\n\n**How it works:**\n1. `Schedule Trigger1` starts the workflow on a daily cron.\n2. `RSS Feed Config1` defines feeds, thresholds, Telegram values, and the target Google Sheet ID.\n3. `Generate Feed Items` and `Loop Over Feeds` process each RSS feed one at a time.\n4. `Read RSS Feed`, `Tag Articles`, and `Aggregate and Rank` collect, score, filter, deduplicate, and rank stories.\n5. `Any Stories Today?` decides whether to generate a digest or send a no-stories alert.\n6. `Build NIM Payload` and `Generate Digest (NIM)` create the AI-written digest.\n7. `Build Telegram Payload` and `Send to Telegram` deliver the final message.\n8. `Log Digest to Sheets` records successful runs, and `Log Error to Sheets` records delivery failures.\n\n**Required setup:**\n- NVIDIA NIM API key via HTTP Header Auth\n- Google Sheets OAuth2 credential\n- Telegram bot token\n- Telegram chat ID or `@channelname`\n- A Google Sheet with `Digest_Log` and `Error_Log` tabs\n\nBuilt by Cordexa Technologies  \nhttps://cordexa.tech  \ncordexatech@gmail.com"
      },
      "typeVersion": 1
    },
    {
      "id": "c2af8166-03eb-4214-90ca-1c450077b426",
      "name": "Step 1 \u2014 Config",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        176,
        -816
      ],
      "parameters": {
        "color": 7,
        "width": 644,
        "height": 1100,
        "content": "## Step 1 \u2014 Config\n\nOpen `RSS Feed Config1` and update these values before testing:\n\n- `rssFeeds` \u2014 add, remove, or replace feed URLs\n- `maxStoriesInDigest` \u2014 number of stories to include in each digest\n- `freshnessHours` \u2014 recency window for article selection\n- `telegramBotToken` \u2014 your Telegram bot token\n- `telegramChatId` \u2014 your chat ID or `@channelname`\n- `googleSheetId` \u2014 target Google Sheet ID for logs\n\nFeed format:\n- `url` \u2014 RSS feed URL\n- `source` \u2014 display name used in the digest\n- `tier` \u2014 source weight used during ranking\n\nTier meaning:\n- Tier 1 = highest-priority sources\n- Tier 2 = good secondary sources\n- Tier 3 = lower-priority or niche sources\n\nFor testing, you can temporarily increase `freshnessHours` so older articles are still eligible."
      },
      "typeVersion": 1
    },
    {
      "id": "36b62d2a-7e5a-47d5-9d2d-e0c37c192f5d",
      "name": "Step 2 \u2014 Credentials",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        864,
        -832
      ],
      "parameters": {
        "color": 7,
        "width": 972,
        "height": 1108,
        "content": "## Step 2 \u2014 Credentials\n\nConnect these credentials before going live:\n\n- **HTTP Header Auth** on `Generate Digest (NIM)`\n  - Header name: `Authorization`\n  - Value: `Bearer YOUR_NVIDIA_API_KEY`\n\n- **Google Sheets OAuth2** on both Sheets nodes\n  - `Log Digest to Sheets`\n  - `Log Error to Sheets`\n\nThis workflow does **not** use a Telegram credential node. Telegram delivery uses the bot token stored in `RSS Feed Config1`, and the HTTP Request nodes read that value directly.\n\nAlso confirm `Generate Digest (NIM)` still sends:\n- `Content-Type: application/json`\n- POST request to `https://integrate.api.nvidia.com/v1/chat/completions`"
      },
      "typeVersion": 1
    },
    {
      "id": "b107921c-7442-433a-b912-f32e546cadec",
      "name": "Optional \u2014 Telegram Channel Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1888,
        -448
      ],
      "parameters": {
        "color": 7,
        "width": 620,
        "height": 288,
        "content": "## Optional \u2014 Telegram Channel Setup\n\nUse a personal chat ID for testing first.\n\nFor a channel:\n1. Create the channel\n2. Add the bot as an admin\n3. Set `telegramChatId` to `@channelname`\n\nAll Telegram nodes read the token and chat ID from `\ud83d\udccb RSS Feed Config1`."
      },
      "typeVersion": 1
    },
    {
      "id": "09c70b5c-0f85-4fc4-9c4f-d3c0cf4636a7",
      "name": "Step 3 \u2014 Delivery",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2432,
        384
      ],
      "parameters": {
        "color": 7,
        "width": 540,
        "height": 466,
        "content": "## Step 3 \u2014 Delivery\n\nThis workflow writes to Google Sheets and sends the digest to Telegram.\n\nBefore going live:\n- Create a Google Sheet with two tabs:\n  - `Digest_Log`\n  - `Error_Log`\n- Make sure `googleSheetId` is set in `RSS Feed Config1`\n- Confirm both Sheets nodes point to the same target sheet\n- Run one manual test and confirm a new row appears in `Digest_Log`\n- Force one Telegram delivery failure and confirm a row appears in `Error_Log`\n\nDelivery behavior:\n- `Log Digest to Sheets` records successful runs\n- `Log Error to Sheets` records Telegram delivery failures\n- `No Stories Alert` sends a Telegram message when no fresh stories qualify for the digest"
      },
      "typeVersion": 1
    },
    {
      "id": "fd69712f-4f83-4370-b146-39ee2729a996",
      "name": "Step 4 \u2014 Activate",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3056,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 388,
        "height": 380,
        "content": "## Step 4 \u2014 Activate\n\nBefore activating the schedule:\n\n- Run the workflow manually once\n- Confirm the digest reaches Telegram\n- Confirm `Digest_Log` receives a new row\n- Confirm story count and titles are recorded correctly\n- Confirm the no-stories branch works when no fresh items qualify\n- Confirm `Error_Log` receives a row when Telegram delivery fails\n\nActivate the workflow only after both success and error paths behave as expected."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Tag Articles": {
      "main": [
        [
          {
            "node": "Aggregate and Rank",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read RSS Feed": {
      "main": [
        [
          {
            "node": "Tag Articles",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Digest": {
      "main": [
        [
          {
            "node": "Build Telegram Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Loop Over Feeds": {
      "main": [
        [],
        [
          {
            "node": "Read RSS Feed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send to Telegram": {
      "main": [
        [
          {
            "node": "Telegram Send OK?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build NIM Payload": {
      "main": [
        [
          {
            "node": "Generate Digest (NIM)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Send OK?": {
      "main": [
        [
          {
            "node": "Log Digest to Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build Error Log Row",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate and Rank": {
      "main": [
        [
          {
            "node": "Is Processing Done?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Stories Today?": {
      "main": [
        [
          {
            "node": "Build NIM Payload",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Stories Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Error Log Row": {
      "main": [
        [
          {
            "node": "Log Error to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Feed Items": {
      "main": [
        [
          {
            "node": "Loop Over Feeds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Processing Done?": {
      "main": [
        [
          {
            "node": "Any Stories Today?",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Loop Over Feeds",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Error to Sheets": {
      "main": [
        [
          {
            "node": "Digest Failed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Digest to Sheets": {
      "main": [
        [
          {
            "node": "Digest Complete",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Digest (NIM)": {
      "main": [
        [
          {
            "node": "Extract Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\u23f0 Schedule Trigger1": {
      "main": [
        [
          {
            "node": "\ud83d\udccb RSS Feed Config1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "\ud83d\udccb RSS Feed Config1": {
      "main": [
        [
          {
            "node": "Generate Feed Items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Telegram Payload": {
      "main": [
        [
          {
            "node": "Send to Telegram",
            "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

Automatically fetch, rank, and summarize the top financial stories from curated RSS feeds each day, then deliver a concise AI-written digest to Telegram and log the run to Google Sheets. Runs on a daily schedule and reads 8 curated financial RSS feeds. Loops through each feed…

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

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

This workflow automatically creates a daily market intelligence brief for your stock portfolio. Instead of checking prices, news, and social media separately, it brings everything together into one cl

HTTP Request, RSS Feed Read, Google Sheets +2
AI & RAG

Free Support: Setting up and getting the workflow tailord to your needs. One small free adjustment included.

HTTP Request, Google Cloud Storage, YouTube +2
AI & RAG

This workflow aims to help you and your team track your expenses with OpenAI It automatically collects your OpenAI organization’s API usage and cost data every few days and saves it to a ready-to-use

HTTP Request, Google Sheets
AI & RAG

Stay on top of what’s happening in your community without drowning in endless RSS feeds.

RSS Feed Read, HTTP Request, Discord
AI & RAG

Founder's Discovery Engine. Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 18 nodes.

Google Sheets, Google Drive, HTTP Request +1