AutomationFlowsSlack & Telegram › Capture and Structure Telegram Notes for Obsidian with Groq and Github

Capture and Structure Telegram Notes for Obsidian with Groq and Github

ByAman @amajas on n8n.io

This workflow captures Telegram voice notes or text messages, uses Groq (Whisper and Llama) to transcribe and structure them, converts the result into an Obsidian-ready Markdown note, commits it into a GitHub-hosted vault, and replies in Telegram with the saved note details.…

Event trigger★★★★☆ complexity16 nodesTelegram TriggerTelegramHTTP Request
Slack & Telegram Trigger: Event Nodes: 16 Complexity: ★★★★☆ Added:

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

This workflow follows the HTTP Request → Telegram 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
{
  "nodes": [
    {
      "id": "b3449770-f27d-47c9-a105-668ff035aadc",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        8864,
        2592
      ],
      "parameters": {
        "color": 7,
        "width": 640,
        "height": 544,
        "content": "## Telegram entry routing\n\nReceives Telegram messages, handles the /start command with a welcome reply, and routes non-start messages based on whether they contain audio or text."
      },
      "typeVersion": 1
    },
    {
      "id": "6de57950-3e52-4525-940e-73415fcabfdb",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        9536,
        2736
      ],
      "parameters": {
        "color": 7,
        "width": 624,
        "height": 304,
        "content": "## Voice download transcription\n\nDownloads Telegram voice messages, renames the audio file from OGA to OGG, and sends it to Groq Whisper for transcription."
      },
      "typeVersion": 1
    },
    {
      "id": "69335ce9-4e08-4572-bd55-9540d3371728",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        10192,
        2800
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 336,
        "content": "## Generate Obsidian markdown\n\nSends either typed text or transcribed audio text to Groq Llama to structure it as wiki-style content, then parses and formats the response into Obsidian-ready Markdown."
      },
      "typeVersion": 1
    },
    {
      "id": "5901f6d4-2810-4215-850a-0100310d9c4f",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        10656,
        2800
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 336,
        "content": "## Publish and notify\n\nCommits the generated Markdown file to a GitHub-based vault and sends a Telegram message confirming that the prepared post or note is ready."
      },
      "typeVersion": 1
    },
    {
      "id": "eb1b96cd-bc69-490a-80cf-d0422063b96c",
      "name": "Convert OGA to OGG Format",
      "type": "n8n-nodes-base.code",
      "position": [
        9792,
        2864
      ],
      "parameters": {
        "jsCode": "$input.first().binary.data.fileName = $input.first().binary.data.fileName.replace('.oga', '.ogg');\nreturn $input.first();"
      },
      "typeVersion": 2
    },
    {
      "id": "92a4f300-d4c2-49c9-a858-a02bbf3d1b28",
      "name": "Telegram Bot Trigger",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        8912,
        2976
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "8e0ee3fc-2fc8-4a1f-8e20-ecc900eccc60",
      "name": "Check for /start Command",
      "type": "n8n-nodes-base.if",
      "position": [
        9152,
        2976
      ],
      "parameters": {
        "conditions": {
          "string": [
            {
              "value1": "={{ $json.message.text || '' }}",
              "value2": "/start",
              "operation": "startsWith"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "1cc770e5-829a-4437-a0e6-1fc554c96eb1",
      "name": "Send Telegram Welcome Message",
      "type": "n8n-nodes-base.telegram",
      "position": [
        9360,
        2752
      ],
      "parameters": {
        "text": "=\ud83d\udc4b **Welcome to your Obsidian LLM-Wiki Bot!**\n\nSend a voice note or text message containing your ideas, raw thoughts, or problem statements.\n\nI will transcribe it, extract the logical structure, route it to the correct folder (`01 Inbox`, `02 Ideas`, or `03 Open Questions`), and commit it to your Obsidian Vault automatically!",
        "chatId": "={{ $json.message.chat.id }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "ba917a3c-8450-4b40-8095-c6ccd48c2f36",
      "name": "Route by Message Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        9360,
        2976
      ],
      "parameters": {
        "rules": {
          "rules": [
            {
              "value2": "voice"
            },
            {
              "output": 1,
              "value2": "text"
            }
          ]
        },
        "value1": "={{ $json.message.voice ? 'voice' : 'text' }}",
        "dataType": "string"
      },
      "typeVersion": 1
    },
    {
      "id": "30a50aee-fb53-4e96-b35c-39d7fae367d2",
      "name": "Download Telegram Voice File",
      "type": "n8n-nodes-base.telegram",
      "position": [
        9584,
        2864
      ],
      "parameters": {
        "fileId": "={{ $json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "91a6c318-ca4f-472b-967e-41099e576793",
      "name": "Post to Audio Transcription API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10016,
        2864
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/audio/transcriptions",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "contentType": "multipart-form-data",
        "authentication": "genericCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "whisper-large-v3-turbo"
            },
            {
              "name": "file",
              "parameterType": "formBinaryData",
              "inputDataFieldName": "data"
            }
          ]
        },
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "44edd936-8bd5-41bd-b257-ef0b78738787",
      "name": "Post to Chat Completion API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10240,
        2976
      ],
      "parameters": {
        "url": "https://api.groq.com/openai/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={{\n  {\n    \"model\": \"llama-3.3-70b-versatile\",\n    \"response_format\": { \"type\": \"json_object\" },\n    \"messages\": [\n      {\n        \"role\": \"system\",\n        \"content\": \"You are an expert Knowledge Architect for an Obsidian LLM-Wiki system. Your job is to extract, structure, and preserve every nuance, idea, and question from raw transcripts or text.\\n\\nCRITICAL EXTRACTION RULES:\\n1. target_folder:\\n   - 'inbox': Raw, unorganized, rambling, or incomplete thoughts.\\n   - 'ideas': Software architectures, product concepts, tools, features, or project strategies.\\n   - 'questions': Standalone research queries, technical friction points, or unresolved bugs.\\n2. thought_steps: Deconstruct the raw stream of consciousness into sequential logical reasoning steps (minimum 2-4 steps).\\n3. ideas_for_recall: EXPLICITLY extract every project idea, feature, system concept, or work item mentioned or implied. Include the context so the user can easily recall why they wanted to build or explore it.\\n4. open_questions: ALWAYS extract or infer 1-3 unresolved questions, friction points, technical edge cases, or potential bottlenecks.\\n5. wikilinks: Identify key domain concepts, technology stacks, or architectural components to link across Obsidian (e.g., 'Groq API', 'Vector Database', 'n8n Workflow').\\n6. tags: 2-3 hierarchical tags (e.g., 'ai/pipeline', 'ideas/backend').\\n\\nReply ONLY with a valid JSON object matching this schema:\\n{\\n  \\\"target_folder\\\": \\\"inbox | ideas | questions\\\",\\n  \\\"title\\\": \\\"kebab-case-short-title\\\",\\n  \\\"display_title\\\": \\\"Human Readable Title\\\",\\n  \\\"executive_hook\\\": \\\"1-2 sentence core insight summary\\\",\\n  \\\"trigger\\\": \\\"Context, conversation context, or problem that sparked this input\\\",\\n  \\\"thought_steps\\\": [\\\"Step 1: ...\\\", \\\"Step 2: ...\\\"],\\n  \\\"ideas_for_recall\\\": [\\\"Idea 1: Short description + recall context\\\", \\\"Idea 2: ...\\\"],\\n  \\\"open_questions\\\": [\\\"Question 1...\\\", \\\"Question 2...\\\"],\\n  \\\"wikilinks\\\": [\\\"Concept 1\\\", \\\"Concept 2\\\"],\\n  \\\"tags\\\": [\\\"category/subcategory\\\"]\\n}\"\n      },\n      {\n        \"role\": \"user\",\n        \"content\": \"RAW INPUT:\\n\" + ($json.text || $json.message?.text || \"\")\n      }\n    ]\n  }\n}}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "b5905842-a45c-431d-80da-572d2fd2d8a1",
      "name": "Format Obsidian Markdown",
      "type": "n8n-nodes-base.code",
      "position": [
        10464,
        2976
      ],
      "parameters": {
        "jsCode": "let rawContent = $input.first().json.choices[0].message.content;\nrawContent = rawContent.replace(/```json/g, '').replace(/```/g, '').trim();\n\nlet data;\ntry {\n  data = JSON.parse(rawContent);\n} catch (e) {\n  data = {\n    target_folder: \"inbox\",\n    title: \"unstructured-thought\",\n    display_title: \"Unstructured Thought\",\n    executive_hook: rawContent.substring(0, 100),\n    trigger: \"Telegram raw input\",\n    thought_steps: [rawContent],\n    ideas_for_recall: [\"Raw input logged\u2014review for actionable concepts.\"],\n    open_questions: [\"What are the actionable next steps for this raw input?\"],\n    wikilinks: [],\n    tags: [\"inbox/raw\"]\n  };\n}\n\n// Dynamic Folder Routing Mapping\nconst folderMapping = {\n  'inbox': '01 Inbox',\n  'ideas': '02 Ideas',\n  'questions': '03 Open Questions'\n};\n\nconst rawFolder = (data.target_folder || 'ideas').toLowerCase();\nconst folderName = folderMapping[rawFolder] || '02 Ideas';\nconst noteType = rawFolder === 'questions' ? 'question' : (rawFolder === 'inbox' ? 'raw_note' : 'idea');\n\nconst dateStr = new Date().toISOString().split('T')[0];\nconst sanitizeTitle = (data.title || 'untitled-thought').toLowerCase().replace(/[^a-z0-9-]/g, '-');\nconst filePath = `${folderName}/${dateStr}-${sanitizeTitle}.md`;\n\nconst tagsArray = (data.tags || ['uncategorized']).map(t => `\"${t}\"`).join(', ');\n\n// Thought Steps Formatting\nconst thoughtStepsText = (data.thought_steps && data.thought_steps.length > 0)\n  ? data.thought_steps.map((s, i) => `- **Step ${i + 1}:** ${s}`).join('\\n')\n  : '- **Step 1:** Raw input captured and indexed.';\n\n// Ideas for Recall Formatting\nconst ideasRecallText = (data.ideas_for_recall && data.ideas_for_recall.length > 0)\n  ? data.ideas_for_recall.map(i => `- \ud83d\udca1 **${i}**`).join('\\n')\n  : '- No specific project ideas explicitly detected.';\n\n// Open Questions Formatting (Dataview '- [ ]' task format)\nconst openQuestionsText = (data.open_questions && data.open_questions.length > 0)\n  ? data.open_questions.map(q => `- [ ] ${q}`).join('\\n')\n  : '- [ ] What are the long-term trade-offs or next steps for this concept?';\n\n// Formatting Wikilinks with explicit folder path and alias\nconst wikilinksText = (data.wikilinks && data.wikilinks.length > 0)\n  ? data.wikilinks.map(w => `- [[04 MOCs/MOC/${w}|${w}]]`).join('\\n')\n  : '- [[04 MOCs/MOC - Concept Hub|MOC - Concept Hub]]';\n\nconst markdown = `---\ntype: ${noteType}\nstatus: unprocessed\ndate: ${dateStr}\ntags: [${tagsArray}]\nspark_trigger: \"${(data.trigger || '').replace(/\"/g, '\\\\\"')}\"\n---\n\n# ${data.display_title || 'New Note'}\n\n> [!abstract] Executive Summary\n> **${data.executive_hook || 'No executive summary generated.'}**\n\n### \ud83e\udde0 Thought Trail\n${thoughtStepsText}\n\n---\n\n### \ud83d\udca1 Ideas & Work Items for Recall\n> [!lightbulb]+ Extracted Concepts\n${ideasRecallText}\n\n---\n\n### \u2753 Open Questions & Friction\n${openQuestionsText}\n\n---\n\n### \ud83d\udd17 Concept Maps & Wikilinks\n${wikilinksText}\n`;\n\nconst base64Content = Buffer.from(markdown).toString('base64');\n\nreturn [{\n  json: {\n    filePath: filePath,\n    markdownContent: markdown,\n    base64Content: base64Content,\n    displayTitle: data.display_title || 'New Note',\n    executiveHook: data.executive_hook || '',\n    openQuestionsCount: (data.open_questions || []).length,\n    ideasCount: (data.ideas_for_recall || []).length,\n    chatId: $('Telegram Bot Trigger').first().json.message.chat.id\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "af9803a7-8489-4c58-8d56-935dc1586c81",
      "name": "Upload to GitHub Vault",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        10704,
        2976
      ],
      "parameters": {
        "url": "=https://api.github.com/repos/Progressive-Programmer/obsidian-vault/contents/{{ $json.filePath }}",
        "method": "PUT",
        "options": {},
        "jsonBody": "={{\n  {\n    \"message\": \"feat(wiki): add note - \" + $json.displayTitle,\n    \"content\": $json.base64Content\n  }\n}}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Accept",
              "value": "application/vnd.github+json"
            }
          ]
        }
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ad0f1506-1b83-4b63-9a34-f9ec3a3f2190",
      "name": "Notify Telegram with Posts Ready",
      "type": "n8n-nodes-base.telegram",
      "position": [
        10928,
        2976
      ],
      "parameters": {
        "text": "=\u2705 **Note Captured & Vault Updated!**\n\n\ud83d\udccc **Title:** {{ $('Format Obsidian Markdown').item.json.displayTitle }}\n\ud83d\udca1 **Hook:** {{ $('Format Obsidian Markdown').item.json.executiveHook }}\n\u2753 **Open Questions:** {{ $('Format Obsidian Markdown').item.json.openQuestionsCount }}\n\ud83d\udcc1 **Vault Path:** `{{ $('Format Obsidian Markdown').item.json.filePath }}`",
        "chatId": "={{ $('Format Obsidian Markdown').item.json.chatId }}",
        "additionalFields": {
          "parse_mode": "Markdown"
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4eec4623-5a5a-4f24-80f6-654ba868ac86",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        8304,
        2592
      ],
      "parameters": {
        "width": 480,
        "height": 864,
        "content": "## Untitled workflow\n\n### How it works\n\nThis workflow turns Telegram text or voice messages into structured Obsidian-style wiki notes. It greets users who send /start, routes text directly to an LLM, and downloads/transcribes voice messages before sending them to the same structuring step. The resulting Markdown is committed to a GitHub vault, and the user is notified in Telegram when the file is ready.\n\n### Setup steps\n\n- Configure Telegram credentials for the trigger, message sending, and voice file download nodes.\n- Add Groq API authentication for both the Whisper transcription HTTP request and the Llama chat completion HTTP request.\n- Configure the GitHub API request with a valid token, target repository, branch, file path, and commit metadata for the vault.\n- Review the code nodes to ensure the audio filename conversion and Markdown parsing match the exact data shape returned by Telegram and Groq.\n\n### Customization\n\nAdjust the Groq prompts to change the wiki structure, note style, headings, or metadata. Update the GitHub repository/path logic to route notes into different Obsidian folders or naming conventions."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Telegram Bot Trigger": {
      "main": [
        [
          {
            "node": "Check for /start Command",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Message Type": {
      "main": [
        [
          {
            "node": "Download Telegram Voice File",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Post to Chat Completion API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload to GitHub Vault": {
      "main": [
        [
          {
            "node": "Notify Telegram with Posts Ready",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for /start Command": {
      "main": [
        [
          {
            "node": "Send Telegram Welcome Message",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Route by Message Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Obsidian Markdown": {
      "main": [
        [
          {
            "node": "Upload to GitHub Vault",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert OGA to OGG Format": {
      "main": [
        [
          {
            "node": "Post to Audio Transcription API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Chat Completion API": {
      "main": [
        [
          {
            "node": "Format Obsidian Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Download Telegram Voice File": {
      "main": [
        [
          {
            "node": "Convert OGA to OGG Format",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Audio Transcription API": {
      "main": [
        [
          {
            "node": "Post to Chat Completion API",
            "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 captures Telegram voice notes or text messages, uses Groq (Whisper and Llama) to transcribe and structure them, converts the result into an Obsidian-ready Markdown note, commits it into a GitHub-hosted vault, and replies in Telegram with the saved note details.…

Source: https://n8n.io/workflows/17896/ — 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

N8N Complete Final. Uses telegramTrigger, dataTable, telegram, mqtt. Event-driven trigger; 58 nodes.

Telegram Trigger, Data Table, Telegram +3
Slack & Telegram

Pede Ai. Uses httpRequest, telegram, postgres, telegramTrigger. Event-driven trigger; 57 nodes.

HTTP Request, Telegram, Postgres +1
Slack & Telegram

TextMain. Uses telegramTrigger, stopAndError, telegram, httpRequest. Event-driven trigger; 56 nodes.

Telegram Trigger, Stop And Error, Telegram +2
Slack & Telegram

Pede Ai. Uses httpRequest, telegram, postgres, telegramTrigger. Event-driven trigger; 53 nodes.

HTTP Request, Telegram, Postgres +1
Slack & Telegram

📄 Documentation: Notion Guide

Telegram Trigger, @Blotato/N8N Nodes Blotato, Telegram +1