Workflow: Telegram channel to Readeck & Hoarder
Integrations: code, httpRequest, scheduleTrigger, set, splitOut, stickyNote

{"id": "Gd4MsAZGnSGfBwaw", "meta": {"instanceId": "workflow-cfc36d28", "versionId": "1.0.0", "createdAt": "2025-09-29T07:07:54.059612", "updatedAt": "2025-09-29T07:07:54.059620", "owner": "n8n-user", "license": "MIT", "category": "automation", "status": "active", "priority": "high", "environment": "production"}, "name": "Telegram channel to Readeck & Hoarder", "tags": ["automation", "n8n", "production-ready", "excellent", "optimized"], "nodes": [{"id": "6e50d52e-8b9e-4c92-82a1-af366c7a2ccf", "name": "Schedule Trigger", "type": "n8n-nodes-base.scheduleTrigger", "position": [-440, -700], "parameters": {"rule": {"interval": [{"field": "hours"}]}}, "typeVersion": 1.2, "notes": "This scheduleTrigger node performs automated tasks as part of the workflow."}, {"id": "bb7430a2-a7b7-47f2-9ba3-a3e43c8da004", "name": "Split Out", "type": "n8n-nodes-base.splitOut", "position": [-100, -120], "parameters": {"options": {}, "fieldToSplitOut": "bookmarks"}, "typeVersion": 1, "notes": "This splitOut node performs automated tasks as part of the workflow."}, {"id": "922aeb0b-29b1-46c6-9b18-76c02eca5a9e", "name": "Sticky Note", "type": "n8n-nodes-base.stickyNote", "position": [-460, -480], "parameters": {"width": 1120, "height": 220, "content": "## Readeck"}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "64d4ca0b-2c16-441e-9461-5707be877132", "name": "Sticky Note1", "type": "n8n-nodes-base.stickyNote", "position": [-220, -740], "parameters": {"width": 480, "height": 200, "content": "## Telegram"}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "13ae24ec-ac11-470a-bad4-76403861f632", "name": "Sticky Note2", "type": "n8n-nodes-base.stickyNote", "position": [-460, -180], "parameters": {"width": 1120, "height": 220, "content": "## Hoarder"}, "typeVersion": 1, "notes": "This stickyNote node performs automated tasks as part of the workflow."}, {"id": "c606f434-d37b-4406-997a-1e7f17319281", "name": "not_saved_links_hd", "type": "n8n-nodes-base.code", "position": [260, -120], "parameters": {"jsCode": "const linksCanalItems = $('channel_links_tg').all();\nconst saved_links_items = $('saved_links_hd').all();\n\n// Extract links\nconst saved_links = new Set(\n    saved_links_items.map(item => String(item.json.content.url))\n);\n\n// Filter\nconst filteredLinks = linksCanalItems.filter(item => {\n    return !saved_links.has(String(item.json.url));\n});\n\nreturn filteredLinks;\n\n\n\n\n\n\n\n\n"}, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow."}, {"id": "d0f61836-798c-4835-ae8f-8f184b6720ed", "name": "not_saved_links_rd", "type": "n8n-nodes-base.code", "position": [260, -420], "parameters": {"jsCode": "const linksCanalItems = $('channel_links_tg').all();\nconst saved_links_items = $('saved_links_rd').all();\n\n// Extract urls\nconst saved_urls = new Set(\n    saved_links_items.map(item => String(item.json.url))\n);\n\n// Filter\nconst filteredLinks = linksCanalItems.filter(item => {\n    return !saved_urls.has(String(item.json.url));\n});\n\nreturn filteredLinks;\n\n\n\n\n\n\n\n\n"}, "typeVersion": 2, "notes": "This code node performs automated tasks as part of the workflow."}, {"id": "f33349a7-361a-4b0f-844b-1ca5ded2aeab", "name": "saved_links_rd", "type": "n8n-nodes-base.set", "position": [80, -420], "parameters": {"options": {}, "assignments": {"assignments": [{"id": "8c6f3806-0fb8-4c76-a0bc-19b588717430", "name": "id", "type": "string", "value": "={{ $json.id }}"}, {"id": "ef41cba3-2844-479c-9467-6b94ae24c98b", "name": "url", "type": "string", "value": "={{ $json.url }}"}]}}, "typeVersion": 3.4, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "63d45b19-e878-418e-8eb5-c16b50af9669", "name": "save_link_rd", "type": "n8n-nodes-base.httpRequest", "position": [460, -420], "parameters": {"url": "{{ $env.BASE_URL }}", "method": "POST", "options": {}, "sendBody": true, "sendHeaders": true, "bodyParameters": {"parameters": [{"name": "url", "value": "={{ $json.url }}"}]}, "headerParameters": {"parameters": [{"name": "accept", "value": "application/json"}, {"name": "authorization", "value": "=Bearer {{$env.READECK_API_KEY}}"}]}}, "typeVersion": 4.2, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "9416a858-1a25-4c3e-a49e-153118c268a7", "name": "save_link_hd", "type": "n8n-nodes-base.httpRequest", "position": [460, -120], "parameters": {"url": "{{ $env.BASE_URL }}", "method": "POST", "options": {}, "sendBody": true, "sendHeaders": true, "bodyParameters": {"parameters": [{"name": "type", "value": "link"}, {"name": "url", "value": "={{ $json.url }}"}]}, "headerParameters": {"parameters": [{"name": "Authorization", "value": "=Bearer {{$env.HOARDER_API_KEY}}"}]}}, "typeVersion": 4.2, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "13693467-cd75-4774-9072-832419606ab2", "name": "get_links_rd", "type": "n8n-nodes-base.httpRequest", "position": [-280, -420], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {}, "sendHeaders": true, "headerParameters": {"parameters": [{"name": "accept", "value": "application/json"}, {"name": "authorization", "value": "=Bearer {{$env.READECK_API_KEY}}"}]}}, "typeVersion": 4.2, "alwaysOutputData": true, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "e4ed315d-d065-425a-b30d-eca1509670cc", "name": "get_links_hd", "type": "n8n-nodes-base.httpRequest", "position": [-280, -120], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {}, "sendHeaders": true, "headerParameters": {"parameters": [{"name": "Authorization", "value": "=Bearer {{$env.HOARDER_API_KEY}}"}]}}, "typeVersion": 4.2, "alwaysOutputData": true, "notes": "This httpRequest node performs automated tasks as part of the workflow."}, {"id": "f54d9a4d-f00b-41bf-988a-8920d0046424", "name": "saved_links_hd", "type": "n8n-nodes-base.set", "position": [80, -120], "parameters": {"options": {}, "assignments": {"assignments": [{"id": "b07ce8e5-0b67-4c9c-831a-7a52f92f5744", "name": "content.url", "type": "string", "value": "={{ $json.content.url }}"}]}}, "typeVersion": 3.4, "notes": "This set node performs automated tasks as part of the workflow."}, {"id": "d4e83b9d-5988-46f4-b853-86daec274dba", "name": "channel_links_tg", "type": "n8n-nodes-base.code", "position": [120, -700], "parameters": {"jsCode": "// Define the chatId from the environment variable\nconst chatId = parseInt($env.TG_SHERLINK_ID, 10);\n// Access the \"result\" field from the previous node's output\nconst updates = $node[\"channel_items_tg\"].json[\"result\"];\n// Check if \"result\" is an array\nif (!Array.isArray(updates)) {\n  return []; // Return empty if there are no messages\n}\n// Filter and process the messages\nconst filteredUpdates = updates\n  .map(update => {\n    // Ensure message from the specified channel\n    if (update.channel_post && update.channel_post.chat && update.channel_post.chat.id === chatId) {\n      return {\n        id: update.channel_post.message_id,\n        url: update.channel_post.text\n      };\n    }\n    return null;\n  })\n  \n  .filter(item => item !== null) // Filter nulls\n  .filter(item => {\n    // Filter only with hyperlink in text\n    const text = item.url || \"\"; // Defined text\n    return /https?:\\/\\/[^\\s]+/.test(text); // hyperlink\n  });\n// Convert each array element into an individual item\nreturn filteredUpdates.map(update => ({ json: update }));\n"}, "typeVersion": 2, "alwaysOutputData": false, "notes": "This code node performs automated tasks as part of the workflow."}, {"id": "ca306aed-e682-4c35-a257-3b65bcfde895", "name": "channel_items_tg", "type": "n8n-nodes-base.httpRequest", "position": [-80, -700], "parameters": {"url": "{{ $env.BASE_URL }}", "options": {}, "sendQuery": true, "queryParameters": {"parameters": [{}]}}, "typeVersion": 4.2, "notes": "This httpRequest node performs automated tasks as part of the workflow."}], "active": true, "pinData": {}, "settings": {"callerPolicy": "workflowsFromSameOwner", "executionOrder": "v1", "saveManualExecutions": true, "errorWorkflow": null, "timezone": "UTC", "executionTimeout": 3600, "maxExecutions": 1000, "retryOnFail": true, "retryCount": 3, "retryDelay": 1000}, "versionId": "85dd3731-0772-4b8b-b828-ae6a034d5419", "connections": {"63d45b19-e878-418e-8eb5-c16b50af9669": {"main": [[{"node": "error-handler-63d45b19-e878-418e-8eb5-c16b50af9669", "type": "main", "index": 0}], [{"node": "error-handler-63d45b19-e878-418e-8eb5-c16b50af9669-0691e201", "type": "main", "index": 0}], [{"node": "error-handler-63d45b19-e878-418e-8eb5-c16b50af9669-65c2c97f", "type": "main", "index": 0}], [{"node": "error-handler-63d45b19-e878-418e-8eb5-c16b50af9669-f18aeecc", "type": "main", "index": 0}], [{"node": "error-handler-63d45b19-e878-418e-8eb5-c16b50af9669-e3e73071", "type": "main", "index": 0}]]}, "9416a858-1a25-4c3e-a49e-153118c268a7": {"main": [[{"node": "error-handler-9416a858-1a25-4c3e-a49e-153118c268a7", "type": "main", "index": 0}], [{"node": "error-handler-9416a858-1a25-4c3e-a49e-153118c268a7-0cce38ef", "type": "main", "index": 0}], [{"node": "error-handler-9416a858-1a25-4c3e-a49e-153118c268a7-f5474bdc", "type": "main", "index": 0}], [{"node": "error-handler-9416a858-1a25-4c3e-a49e-153118c268a7-e7eebe2f", "type": "main", "index": 0}], [{"node": "error-handler-9416a858-1a25-4c3e-a49e-153118c268a7-8baeab24", "type": "main", "index": 0}]]}, "13693467-cd75-4774-9072-832419606ab2": {"main": [[{"node": "error-handler-13693467-cd75-4774-9072-832419606ab2", "type": "main", "index": 0}], [{"node": "error-handler-13693467-cd75-4774-9072-832419606ab2-ac4023f9", "type": "main", "index": 0}], [{"node": "error-handler-13693467-cd75-4774-9072-832419606ab2-50574df2", "type": "main", "index": 0}], [{"node": "error-handler-13693467-cd75-4774-9072-832419606ab2-4763b7f5", "type": "main", "index": 0}], [{"node": "error-handler-13693467-cd75-4774-9072-832419606ab2-16b60249", "type": "main", "index": 0}]]}, "e4ed315d-d065-425a-b30d-eca1509670cc": {"main": [[{"node": "error-handler-e4ed315d-d065-425a-b30d-eca1509670cc", "type": "main", "index": 0}], [{"node": "error-handler-e4ed315d-d065-425a-b30d-eca1509670cc-4e492879", "type": "main", "index": 0}], [{"node": "error-handler-e4ed315d-d065-425a-b30d-eca1509670cc-f476277a", "type": "main", "index": 0}], [{"node": "error-handler-e4ed315d-d065-425a-b30d-eca1509670cc-0a335c77", "type": "main", "index": 0}], [{"node": "error-handler-e4ed315d-d065-425a-b30d-eca1509670cc-21aa2c00", "type": "main", "index": 0}]]}, "ca306aed-e682-4c35-a257-3b65bcfde895": {"main": [[{"node": "error-handler-ca306aed-e682-4c35-a257-3b65bcfde895", "type": "main", "index": 0}], [{"node": "error-handler-ca306aed-e682-4c35-a257-3b65bcfde895-3abc7893", "type": "main", "index": 0}], [{"node": "error-handler-ca306aed-e682-4c35-a257-3b65bcfde895-ca1f7896", "type": "main", "index": 0}], [{"node": "error-handler-ca306aed-e682-4c35-a257-3b65bcfde895-1054356a", "type": "main", "index": 0}], [{"node": "error-handler-ca306aed-e682-4c35-a257-3b65bcfde895-70cfa463", "type": "main", "index": 0}]]}}, "description": "Automated workflow: Telegram channel to Readeck & Hoarder. This workflow integrates 7 different services: stickyNote, httpRequest, code, scheduleTrigger, splitOut. It contains 25 nodes and follows best practices for error handling and security.", "notes": "Excellent quality workflow: Telegram channel to Readeck & Hoarder. This workflow has been optimized for production use with comprehensive error handling, security, and documentation."}