This workflow corresponds to n8n.io template #16833 — we link there as the canonical source.
This workflow follows the Agent → Error Trigger 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 →
{
"id": "CLlNGhBKomdx82p7",
"name": "Personal Assistant",
"tags": [],
"nodes": [
{
"id": "6466d1f1-ff9a-4b8b-9c7f-c4b124fa1bac",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
1168,
1888
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.3
},
{
"id": "06eebae2-dc52-4b9a-bccf-b9c233a3a53d",
"name": "Get many events",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1392,
1888
],
"parameters": {
"options": {},
"timeMax": "={{ $now.setZone('Asia/Colombo').endOf('day') }}",
"timeMin": "={{ $now.setZone('Asia/Colombo').startOf('day') }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "getAll",
"returnAll": true
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "0b3fb56a-ca3f-4a71-bc3f-8d5842cce6a7",
"name": "Code in JavaScript",
"type": "n8n-nodes-base.code",
"position": [
1664,
1888
],
"parameters": {
"jsCode": "const events = $input.all();\n\nif (events.length === 0) {\n return [{\n json: {\n message: `\ud83c\udf05 Good Morning Nijan\n\n\ud83d\udcc5 Today's Schedule\n\nNo events scheduled today.\n\nPerfect day for deep work.`\n }\n }];\n}\n\nconst formatTime = (dateString) => {\n return new Date(dateString).toLocaleTimeString('en-US', {\n hour: 'numeric',\n minute: '2-digit',\n hour12: true,\n timeZone: 'Asia/Colombo'\n });\n};\n\nlet message = `\ud83c\udf05 Good Morning Nijan\\n\\n\ud83d\udcc5 Today's Schedule\\n\\n`;\n\nfor (const event of events) {\n const title = event.json.summary || 'Untitled Event';\n const start = formatTime(event.json.start.dateTime);\n\n message += `\u2022 ${start} \u2014 ${title}\\n`;\n}\n\nmessage += `\\nTotal Events: ${events.length}`;\n\nreturn [{\n json: {\n message\n }\n}];"
},
"typeVersion": 2
},
{
"id": "839a1665-c38d-43d6-bbb0-607dfcd6c9ad",
"name": "Send a text message5",
"type": "n8n-nodes-base.telegram",
"position": [
1968,
1888
],
"parameters": {
"text": "={{ $json.message }}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "bc3adddb-8ca4-424a-9d18-485ab398cd93",
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
1216,
2912
],
"parameters": {
"path": "cal-events",
"options": {},
"httpMethod": "POST"
},
"typeVersion": 2.1
},
{
"id": "238d16a6-899b-4089-af7a-aac8721773f0",
"name": "Switch",
"type": "n8n-nodes-base.switch",
"position": [
1632,
2880
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "booking_created",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "10e46315-033e-486b-9ccb-ad780179eb39",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{$json.body.triggerEvent}}",
"rightValue": "BOOKING_CREATED"
}
]
},
"renameOutput": true
},
{
"outputKey": "booking_rescheduled",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d0a65510-5ce5-480a-8c9c-4f23e25474e7",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{$json.body.triggerEvent}}",
"rightValue": "BOOKING_RESCHEDULED"
}
]
},
"renameOutput": true
},
{
"outputKey": "booking_cancelled",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e51862c8-ff9c-4e6e-a3fd-57ce3d0c116a",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{$json.body.triggerEvent}}",
"rightValue": "BOOKING_CANCELLED"
}
]
},
"renameOutput": true
},
{
"outputKey": "meeting_ended",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "b966abe7-22c4-4baa-b324-5c1db8402b04",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{$json.body.triggerEvent}}",
"rightValue": "MEETING_ENDED"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "03b6a273-60ac-40a1-abdb-9bbc4b0c0c3f",
"name": "Send a text message1",
"type": "n8n-nodes-base.telegram",
"position": [
2256,
2576
],
"parameters": {
"text": "=\ud83d\udd14 New Meeting Booked\n\n\ud83d\udc64 {{$json.body.payload.attendees[0].name}}\n\n\ud83d\udce7 {{$json.body.payload.attendees[0].email}}\n\n\ud83d\udcdd {{$json.body.payload.title}}\n\n\ud83d\udcc5 {{$json.body.payload.startTime}}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a4ac5d95-60e2-4c88-ad33-88684b0ba4e8",
"name": "Send a text message2",
"type": "n8n-nodes-base.telegram",
"position": [
2256,
2800
],
"parameters": {
"text": "=\ud83d\udd04 Meeting Rescheduled\n\n\ud83d\udc64 {{$json.body.payload.attendees[0].name}}\n\n\ud83d\udce7 {{$json.body.payload.attendees[0].email}}\n\n\ud83d\udcdd {{$json.body.payload.title}}\n\n\ud83d\udcc5 {{$json.body.payload.startTime}}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "ec984139-5161-4467-91d8-d17d5124a30f",
"name": "Send a text message3",
"type": "n8n-nodes-base.telegram",
"position": [
2256,
3024
],
"parameters": {
"text": "=\u274c Meeting Cancelled\n\n\ud83d\udc64 {{$json.body.payload.attendees[0].name}}\n\n\ud83d\udce7 {{$json.body.payload.attendees[0].email}}\n\n\ud83d\udcdd {{$json.body.payload.title}}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "a7fe57da-8711-44df-9f23-796b307ec4e0",
"name": "Send a text message4",
"type": "n8n-nodes-base.telegram",
"position": [
2256,
3280
],
"parameters": {
"text": "=\u2705 Meeting Completed\n\n\ud83d\udc64 {{$json.body.payload.attendees[0].name}}\n\n\ud83d\udce7 {{$json.body.payload.attendees[0].email}}\n\n\ud83d\udcdd {{$json.body.payload.title}}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "17afe37c-1c83-4afe-913d-120dcd8c6788",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
2800,
2720
],
"parameters": {},
"typeVersion": 1
},
{
"id": "4415c39a-913d-4eec-bc24-5358b9c3d7b7",
"name": "Send a text message6",
"type": "n8n-nodes-base.telegram",
"position": [
3088,
2720
],
"parameters": {
"text": "=\ud83d\udea8 Workflow Error Alert\n\nWorkflow: {{ $json.workflow.name }}\n\nFailed Node: {{ $json.execution.lastNodeExecuted }}\n\nError: {{ $json.execution.error.message }}\n\nExecution ID: {{ $json.execution.id }}\n\nURL:\n{{ $json.execution.url }}",
"chatId": "={{ $vars.telegram_chat_id }}",
"additionalFields": {
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "88058757-b378-4b77-a4ec-0abe15f0d6b7",
"name": "Get Many Projects",
"type": "n8n-nodes-base.todoistTool",
"position": [
4320,
1328
],
"parameters": {
"resource": "project",
"operation": "getAll",
"descriptionType": "manual",
"toolDescription": "Use this tool whenever a user mentions a project name such as Delta Camp, n8n Community, HM Works, or Tillmax Project.\n\nRetrieve available Todoist projects and project IDs before creating, updating, moving, or retrieving project-specific tasks.\n\nNever assume a project exists without checking."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "8eea02b8-3717-4f59-a6b6-b9be02bdd69f",
"name": "Create Task",
"type": "n8n-nodes-base.todoistTool",
"position": [
4896,
1280
],
"parameters": {
"content": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', `Task title extracted from the user's request.\n\nExamples:\n\"Create task review Epos tomorrow\"\n\u2192 Review Epos\n\n\"Add task prepare meetup agenda\"\n\u2192 Prepare meetup agenda`, 'string') }}",
"options": {
"priority": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Priority', `Task priority if specified by the user.\n\nHighest=P1\nHigh=P2\nMedium=P3\nLow=P4\n\nLeave empty if not specified.`, 'number') }}",
"dueString": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Due_String', `Natural language due date extracted from the user's request.\n\nExamples:\ntoday\ntomorrow\nnext Monday\nFriday 3pm\n\nLeave empty if no due date is provided.`, 'string') }}"
},
"project": {
"__rl": true,
"mode": "id",
"value": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Project_Name_or_ID', `Choose the correct Todoist project ID.\n\nAvailable projects:\n- Delta Camp\n- n8n Community\n- HM Works\n- Tillmax Project\n\nFirst use Get Many Projects if project IDs are not known.\nReturn only the matching project ID.`, 'string') }}"
},
"descriptionType": "manual",
"toolDescription": "Create a new task in a Todoist project.\nUse when the user wants to add a task.\nAlways identify the correct project first.\nRetrieve available Todoist projects and project IDs before creating, updating, moving, or retrieving project-specific tasks.\n\nNever assume a project exists without checking."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "181b1454-7b84-4c5f-9363-81daa88d7417",
"name": "Get Many Tasks",
"type": "n8n-nodes-base.todoistTool",
"position": [
4480,
1328
],
"parameters": {
"filters": {
"filter": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Filter', `Generate a Todoist filter based on the user's request.\n\nExamples:\n\nProject specific:\n#Delta Camp\n#n8n Community\n#HM Works\n#Tillmax Project\n\nOverdue:\noverdue\n\nToday:\ntoday\n\nNext 7 days:\n7 days\n\nHigh priority:\np1\n\nPending tasks:\n!completed\n\nIf no filter is needed, leave empty.`, 'string') }}"
},
"operation": "getAll",
"returnAll": true,
"descriptionType": "manual",
"toolDescription": "Retrieve Todoist tasks.\n\nUse when the user wants to:\n\n- Show my tasks\n- Show pending tasks\n- Show overdue tasks\n- Show project tasks\n- What should I work on today?\n- Show Delta Camp tasks\n- Show HM Works tasks\n- Show n8n Community tasks\n- Show Tillmax Project tasks\n\nGenerate the appropriate Todoist filter automatically.\n\nAlways retrieve fresh task data before responding."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "2df3d5de-3a53-4c40-9ed6-4679893cc82d",
"name": "Update Task",
"type": "n8n-nodes-base.todoistTool",
"position": [
5088,
1280
],
"parameters": {
"taskId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Task_ID', `Use the Todoist task ID from a previously retrieved task.\n\nAlways retrieve tasks first if the task ID is unknown.\n\nNever invent task IDs.\n\nIf multiple matching tasks exist, ask the user which one should be updated.`, 'string') }}",
"operation": "update",
"updateFields": {
"content": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Content', `New task title.\n\nOnly update when the user wants to rename the task.`, 'string') }}",
"priority": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Priority', `New task priority.\n\nP1 = Highest\nP2 = High\nP3 = Medium\nP4 = Low\n\nNew task description or notes.\n\nOnly update when the user explicitly requests changes.`, 'number') }}",
"dueString": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Due_String', `New due date in natural language.\n\nExamples:\ntoday\ntomorrow\nnext Monday\nFriday 3pm\n\nOnly update when the user requests a date change.`, 'string') }}",
"description": ""
},
"descriptionType": "manual",
"toolDescription": "Update an existing Todoist task.\n\nUse when the user wants to:\n\n- rename a task\n- change a due date\n- reschedule a task\n- change priority\n- edit a task\n\nTodoist requires a task ID.\n\nBefore updating a task:\n\n1. Retrieve tasks using Get Many Tasks.\n2. Find the matching task.\n3. Use the discovered task ID.\n4. Update the requested fields.\n\nIf multiple tasks match, ask the user which task they mean.\n\nNever invent task IDs."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "d3b7e354-6aa4-41d3-91e6-b2ee40740e19",
"name": "Close Task",
"type": "n8n-nodes-base.todoistTool",
"position": [
5248,
1280
],
"parameters": {
"taskId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Task_ID', `Use the Todoist task ID from a previously retrieved task.\n\nAlways retrieve tasks first if the task ID is unknown.\n\nNever invent task IDs.\n\nIf multiple matching tasks exist, ask the user which one should be completed.`, 'string') }}",
"operation": "close",
"descriptionType": "manual",
"toolDescription": "Mark a Todoist task as completed.\n\nUse when the user wants to:\n\n- complete a task\n- mark a task done\n- finish a task\n- close a task\n- check off a task\n\nTodoist requires a task ID.\n\nBefore closing a task:\n\n1. Retrieve tasks using Get Many Tasks.\n2. Find the matching task.\n3. Use the discovered task ID.\n4. Close the task.\n\nIf multiple tasks match, ask the user which task they mean.\n\nNever invent task IDs."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "974c8769-2687-46bf-8715-e858843fe796",
"name": "Delete Task",
"type": "n8n-nodes-base.todoistTool",
"position": [
5424,
1280
],
"parameters": {
"taskId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Task_ID', `Use the Todoist task ID from a previously retrieved task.\n\nAlways retrieve tasks first if the task ID is unknown.\n\nNever invent task IDs.\n\nIf multiple matching tasks exist, ask the user which one should be deleted.`, 'string') }}",
"operation": "delete",
"descriptionType": "manual",
"toolDescription": "Delete a Todoist task permanently.\n\nUse when the user wants to:\n\n- delete a task\n- remove a task\n- cancel a task permanently\n\nBefore deleting:\n\n1. Retrieve tasks using Get Many Tasks.\n2. Find the matching task.\n3. Use the discovered task ID.\n4. Delete the task.\n\nIf multiple tasks match, ask the user which task they mean.\n\nNever invent task IDs."
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "18769823-ae3e-4acb-acde-5d20f0757d28",
"name": "Merge1",
"type": "n8n-nodes-base.merge",
"position": [
3312,
1936
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "bca005aa-d575-4985-a88e-b923ec3ba3ee",
"name": "Send a text message8",
"type": "n8n-nodes-base.telegram",
"position": [
4064,
1952
],
"parameters": {
"text": "={{ $json.message }}",
"chatId": "={{$vars.telegram_chat_id}}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "89b4d825-a0f3-41b5-832a-94300f8a2ac2",
"name": "Schedule Trigger3",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
2624,
1936
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8,
"triggerAtMinute": 30
}
]
}
},
"typeVersion": 1.3
},
{
"id": "c42d60f3-fc16-417a-8409-8a712562ba16",
"name": "Telegram summary1",
"type": "n8n-nodes-base.code",
"position": [
3696,
1952
],
"parameters": {
"jsCode": "const items = $input.all();\n\n// Separate projects and tasks\nconst projects = items.filter(\n item => item.json.name && item.json.id && !item.json.content\n);\n\nconst tasks = items.filter(\n item => item.json.content\n);\n\n// Build project lookup\nconst projectMap = {};\n\nfor (const project of projects) {\n projectMap[project.json.id] = project.json.name;\n}\n\nconst grouped = {};\nconst focusTasks = [];\n\nlet totalTasks = 0;\n\n// Process tasks\nfor (const task of tasks) {\n\n const projectName = projectMap[task.json.project_id];\n\n // Skip orphan/system tasks\n if (!projectName) continue;\n\n // Skip Inbox\n if (projectName === \"Inbox\") continue;\n\n let priorityIcon = \"\u26aa\";\n\n if (task.json.priority === 4) priorityIcon = \"\ud83d\udd34\";\n else if (task.json.priority === 3) priorityIcon = \"\ud83d\udfe0\";\n else if (task.json.priority === 2) priorityIcon = \"\ud83d\udfe1\";\n\n let dueText = \"\";\n\n if (task.json.due?.string) {\n dueText = ` \ud83d\udcc5 ${task.json.due.string}`;\n }\n\n const taskLine =\n `${priorityIcon} ${task.json.content}${dueText}`;\n\n // Focus section\n if (task.json.priority >= 3) {\n focusTasks.push(taskLine);\n }\n\n // Project grouping\n if (!grouped[projectName]) {\n grouped[projectName] = [];\n }\n\n grouped[projectName].push(taskLine);\n\n totalTasks++;\n}\n\n// Build message\nconst today = new Date().toLocaleDateString(\n 'en-GB',\n {\n day: 'numeric',\n month: 'short',\n year: 'numeric'\n }\n);\n\nlet message = \"\";\n\nmessage += `\ud83d\udccc *Daily Todoist Tasks*\\n`;\nmessage += `\ud83d\udcc5 ${today}\\n\\n`;\n\n// Focus section\nif (focusTasks.length > 0) {\n\n message += `\ud83c\udfaf *Today's Focus*\\n\\n`;\n\n focusTasks.forEach(task => {\n message += `${task}\\n`;\n });\n\n message += `\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\n}\n\n// Projects\nfor (const [project, projectTasks] of Object.entries(grouped)) {\n\n if (projectTasks.length === 0) continue;\n\n message += `\ud83d\udcc2 ${project}\\n\\n`;\n\n projectTasks.forEach(task => {\n message += `${task}\\n`;\n });\n\n message += `\\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\\n\\n`;\n}\n\nmessage += `\ud83d\udcca *Total Open Tasks:* ${totalTasks}`;\n\nreturn [\n {\n json: {\n message\n }\n }\n];"
},
"typeVersion": 2
},
{
"id": "b45f8ac3-b7c6-4e6a-9e12-b7b69a4542e9",
"name": "Get many tasks",
"type": "n8n-nodes-base.todoist",
"position": [
2992,
1856
],
"parameters": {
"filters": {
"projectId": "={{$json.id}}"
},
"operation": "getAll",
"returnAll": true
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "3ddfdc60-16ac-4e67-a345-cb64191906d8",
"name": "Get many projects",
"type": "n8n-nodes-base.todoist",
"position": [
2992,
2048
],
"parameters": {
"resource": "project",
"operation": "getAll"
},
"credentials": {
"todoistApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "fd84275c-4477-4118-82f9-6f42ff9f5dbb",
"name": "Sticky Note15",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": "#000000",
"width": 480,
"height": 1024,
"content": "## My personal Assistant\n\n### How it works\n\nThis workflow acts as a personal Telegram assistant that accepts text or voice messages, normalizes the input, and sends it to an AI agent. The agent uses OpenRouter, memory, Google Calendar tools, and Todoist tools to answer questions or manage events and tasks, then replies back in Telegram. Separate scheduled branches send calendar reminders and Todoist summaries, while webhook and error-trigger branches send Telegram notifications for external events and failures.\n\n### Setup steps\n\n- Configure Telegram bot credentials for the trigger and all Telegram send/get-file nodes, including the destination chat IDs.\n- Add OpenRouter credentials for the AI agent model nodes and select the preferred models.\n- Add a Groq API key or authorization header in the audio transcription HTTP request node.\n- Connect Google Calendar OAuth credentials and confirm the target calendars used by both the agent tools and scheduled reminder branch.\n- Connect Todoist credentials and verify the projects, task filters, and tool permissions used by the agent and summary branch.\n- Set the schedule trigger times for calendar reminders and Todoist summaries.\n- Configure the webhook URL consumers and switch conditions for the routed Telegram notifications.\n- Enable the error workflow and point its Telegram alert node to the desired admin chat.\n\n### Customization\n\nYou can adjust the AI agent prompt, model choice, memory window, Todoist and Calendar tool permissions, schedule timing, webhook switch routes, and the formatting code used for daily summaries or reminders."
},
"typeVersion": 1
},
{
"id": "412dcf50-7e77-44d4-a841-948816480396",
"name": "Telegram Trigger1",
"type": "n8n-nodes-base.telegramTrigger",
"position": [
1104,
768
],
"parameters": {
"updates": [
"message"
],
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.1
},
{
"id": "ae94d03b-0bd3-4025-8dc6-33f14e62cf74",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
2912,
784
],
"parameters": {
"text": "=reply to the user message {{$json.message}}",
"options": {
"systemMessage": "=You are Nijan's Personal Productivity Assistant.\n\nCurrent Date: {{$now.setZone('Asia/Colombo').toFormat('yyyy-MM-dd')}}\nCurrent Time: {{$now.setZone('Asia/Colombo').toFormat('HH:mm')}}\nTimezone: Asia/Colombo\n\nYou manage:\n\n\u2022 Google Calendar\n\u2022 Todoist\n\nYour responsibility is to help manage schedules, meetings, projects, tasks, priorities, and daily planning accurately.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nCORE PRINCIPLE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nTools are the source of truth.\n\nNever:\n\n\u2022 Assume\n\u2022 Guess\n\u2022 Invent\n\u2022 Simulate tool execution\n\u2022 Use memory as factual data\n\nIf a tool exists for the requested action, use it.\n\nIf a tool was not executed, do not claim success.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nDATE HANDLING\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nAlways resolve relative dates before using tools.\n\nExamples:\n\n\u2022 today\n\u2022 tomorrow\n\u2022 next Monday\n\u2022 this Friday\n\nConvert them into explicit dates before tool execution.\n\nUse ISO format whenever supported by the tool.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nGOOGLE CALENDAR RULES\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nFor availability, event creation, updates, deletions, and meeting management:\n\nAlways use Calendar tools.\n\nWhen creating events:\n\nExtract:\n\n\u2022 Title\n\u2022 Date\n\u2022 Time\n\u2022 Duration\n\u2022 Attendees\n\nDefault duration:\n30 minutes if not provided.\n\nIf attendee email is required but missing:\n\nAsk for the email.\n\nDo not create the event until required information is available.\n\nIf multiple matching events exist for update/delete operations:\n\nAsk which event they mean.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTODOIST RULES\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nProject names:\n\n\u2022 Delta Camp\n\u2022 n8n Community\n\u2022 HM Works\n\u2022 Tillmax Project\n\nTodoist tools are the source of truth.\n\nNever assume:\n\n\u2022 Project existence\n\u2022 Project IDs\n\u2022 Task IDs\n\u2022 Due dates\n\u2022 Priorities\n\u2022 Task status\n\u2022 Task existence\n\nAlways retrieve them using tools.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nPROJECT DISCOVERY\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nWhenever a user references a project:\n\nExamples:\n\n\u2022 Delta Camp\n\u2022 n8n Community\n\u2022 HM Works\n\u2022 Tillmax Project\n\nUse:\n\nGet Many Projects\n\nIdentify the correct project before continuing.\n\nNever invent project IDs.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK CREATION\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nWhen creating a task:\n\nExtract:\n\n\u2022 Task title\n\u2022 Project\n\u2022 Due date\n\u2022 Priority\n\nRequired workflow:\n\n1. Identify project\n2. Create task\n3. Verify task exists\n4. Report success\n\nIf project is unclear:\n\nAsk the user.\n\nNever claim success without verification.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK RETRIEVAL\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nWhen the user asks:\n\n\u2022 Show my tasks\n\u2022 Show today's tasks\n\u2022 Show overdue tasks\n\u2022 Show pending tasks\n\u2022 Show project tasks\n\u2022 What should I work on today?\n\u2022 What is due this week?\n\nRetrieve fresh Todoist data before responding.\n\nNever answer from memory.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK UPDATE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nRequired workflow:\n\n1. Locate task\n2. Update task\n3. Retrieve task again\n4. Verify changes\n5. Report success\n\nNever claim update success without verification.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK COMPLETION\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nRequired workflow:\n\n1. Locate task\n2. Close task\n3. Verify task is completed\n4. Report success\n\nNever claim completion without verification.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK REOPEN\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nRequired workflow:\n\n1. Locate task\n2. Reopen task\n3. Verify task is active again\n4. Report success\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nTASK DELETION\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nRequired workflow:\n\n1. Locate task\n2. Delete task\n3. Verify task no longer exists\n4. Report success\n\nNever claim deletion success without verification.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nAMBIGUITY RULE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nIf multiple tasks match:\n\nAsk the user which task they mean.\n\nNever choose automatically.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nVERIFICATION RULE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nIf the user asks:\n\n\u2022 Verify\n\u2022 Confirm\n\u2022 Check again\n\u2022 Did it create?\n\u2022 Did it update?\n\u2022 Did it complete?\n\u2022 Did it reopen?\n\u2022 Did it delete?\n\nPerform a fresh retrieval.\n\nNever answer from memory.\n\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\nSUCCESS RULE\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\n\nOnly report success when:\n\n1. Action tool succeeded\n2. Verification succeeded\n3. Retrieved data confirms the result\n\nOtherwise explain what failed or what information is missing.\n"
},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "f426c340-bafc-444e-b6e5-b5f06c43e13d",
"name": "Send a text message9",
"type": "n8n-nodes-base.telegram",
"position": [
3472,
784
],
"parameters": {
"text": "={{ $json.output }}",
"chatId": "={{ $('Telegram Trigger1').item.json.message.chat.id }}",
"additionalFields": {
"parse_mode": "HTML",
"appendAttribution": false
}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "0fd91430-9f6e-4b92-bb70-85749e660e45",
"name": "Simple Memory1",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
2832,
960
],
"parameters": {
"sessionKey": "={{$json.userId}}",
"sessionIdType": "customKey",
"contextWindowLength": 30
},
"typeVersion": 1.3
},
{
"id": "3fdb539d-113f-477f-8bbf-a7b1a10d8381",
"name": "OpenRouter Gemini 2.5 flash1",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
2640,
960
],
"parameters": {
"model": "google/gemini-2.5-flash",
"options": {}
},
"credentials": {
"openRouterApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "320b52a8-f584-4922-9891-20253a09e743",
"name": "Create an event1",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
3264,
1280
],
"parameters": {
"end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', `Event end date and time in ISO format`, 'string') }}",
"start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', `Event start date and time in ISO format`, 'string') }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"descriptionType": "manual",
"toolDescription": "Create an event in Google Calendar",
"additionalFields": {
"summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', `Event title`, 'string') }}",
"attendees": [
"={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('attendees0_Attendees', `[\u2728 AI generated]\n`, 'string') }}"
],
"description": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Description', `[\u2728 AI generated]\n`, 'string') }}"
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "a773a8fd-4781-4a21-b4bf-98bf828272a9",
"name": "Delete an event1",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
3424,
1280
],
"parameters": {
"eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
"options": {},
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "delete",
"descriptionType": "manual",
"toolDescription": "Delete an event in Google Calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "473f54df-764a-4c30-b5ae-def45959dbbe",
"name": "Get an event1",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
3600,
1280
],
"parameters": {
"eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
"options": {},
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "get",
"descriptionType": "manual",
"toolDescription": "Get an event in Google Calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "a82d82d4-b8f6-41a0-a410-4e30125c33e4",
"name": "Update an event1",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
3760,
1280
],
"parameters": {
"eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "update",
"updateFields": {},
"descriptionType": "manual",
"toolDescription": "Update an event in Google Calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "c3d7fb10-41d0-4183-969b-fefe5c6caeb5",
"name": "Get many event1",
"type": "n8n-nodes-base.googleCalendarTool",
"position": [
3936,
1280
],
"parameters": {
"limit": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Limit', ``, 'number') }}",
"options": {},
"timeMax": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Before', ``, 'string') }}",
"timeMin": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('After', ``, 'string') }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "getAll",
"descriptionType": "manual",
"toolDescription": "Get many events in Google Calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "aec2af8f-b2b5-40fc-833e-e39b27f20f7d",
"name": "Switch2",
"type": "n8n-nodes-base.switch",
"position": [
1424,
768
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "66dc2029-0b36-48ba-bdd0-a153060af0d5",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.message.voice?.file_id }}",
"rightValue": ""
}
]
}
},
{
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "3e10df7d-280f-4143-9af0-764d7837c18f",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.message.text }}",
"rightValue": ""
}
]
}
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "630e9bd7-ef8b-4bd0-8f1f-66dc4b2b76ee",
"name": "Get a file1",
"type": "n8n-nodes-base.telegram",
"position": [
1648,
192
],
"parameters": {
"fileId": "={{ $json.message.voice.file_id }}",
"resource": "file",
"additionalFields": {}
},
"credentials": {
"telegramApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "337683d3-df4e-456d-92ef-311536ad5179",
"name": "Groq Transcribe1",
"type": "n8n-nodes-base.httpRequest",
"position": [
2336,
192
],
"parameters": {
"url": "=https://api.groq.com/openai/v1/audio/transcriptions",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"sendBody": true,
"contentType": "multipart-form-data",
"sendHeaders": true,
"authentication": "genericCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "file",
"parameterType": "formBinaryData",
"inputDataFieldName": "data"
},
{
"name": "model",
"value": "whisper-large-v3-turbo"
}
]
},
"genericAuthType": "httpCustomAuth",
"headerParameters": {
"parameters": [
{}
]
}
},
"credentials": {
"httpCustomAuth": {
"name": "<your credential>"
}
},
"typeVersion": 4.4
},
{
"id": "4108cdcc-a4e1-4b0b-83ee-437a2a7c1a07",
"name": "Download Audio1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1872,
192
],
"parameters": {
"url": "={{ `https://api.telegram.org/file/bot${$vars.TELEGRAM_BOT_TOKEN}/${$json.result.file_path}` }}",
"options": {
"response": {
"response": {
"responseFormat": "file"
}
}
}
},
"typeVersion": 4.4
},
{
"id": "aa6ede7f-740e-4b0c-bc48-15efac2feb4e",
"name": "Fix Metadata1",
"type": "n8n-nodes-base.code",
"position": [
2096,
192
],
"parameters": {
"jsCode": "const item = $input.first();\n\nitem.binary.data.fileName = \"voice.ogg\";\nitem.binary.data.fileExtension = \"ogg\";\nitem.binary.data.mimeType = \"audio/ogg\";\n\nreturn [item];"
},
"typeVersion": 2
},
{
"id": "65cc8410-7091-4cd9-a6c8-df21a063ac68",
"name": "Text Path1",
"type": "n8n-nodes-base.set",
"position": [
1808,
784
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1121d710-13ba-4619-b28f-e8095eeb6920",
"name": "message",
"type": "string",
"value": "={{$json.message.text}}"
},
{
"id": "eb514a35-7e80-48df-a0dd-8646c91b2933",
"name": "userId",
"type": "string",
"value": "={{$json.message.from.id}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "74d5912b-c9b1-4614-b2af-00b303acb28d",
"name": "Voice Path1",
"type": "n8n-nodes-base.set",
"position": [
2544,
192
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1121d710-13ba-4619-b28f-e8095eeb6920",
"name": "message",
"type": "string",
"value": "={{$json.text}}"
},
{
"id": "adb45706-3ea6-4aa0-b067-dbbaf2a8a396",
"name": "userId",
"type": "string",
"value": "={{$node['Telegram Trigger1'].json.message.from.id}}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "4177b89e-dd19-478e-abd6-c616f79fa6e3",
"name": "Sticky Note22",
"type": "n8n-nodes-base.stickyNote",
"position": [
1056,
624
],
"parameters": {
"color": 4,
"width": 944,
"height": 368,
"content": "## Telegram input routing\n\nReceives incoming Telegram updates, switches by message type, and prepares plain text messages for the assistant."
},
"typeVersion": 1
},
{
"id": "da4e6a72-627c-4aba-9454-9c66e1c428c5",
"name": "Sticky Note23",
"type": "n8n-nodes-base.stickyNote",
"position": [
1568,
32
],
"parameters": {
"color": "#1C0707",
"width": 672,
"height": 384,
"content": "## Retrieve Telegram audio\n\nFetches voice-message file metadata and downloads the audio payload from Telegram, then fixes binary metadata before transcription."
},
"typeVersion": 1
},
{
"id": "cbffa8fd-7544-42b4-b785-00669be3ce67",
"name": "Sticky Note24",
"type": "n8n-nodes-base.stickyNote",
"position": [
2272,
32
],
"parameters": {
"color": "#1E1D01",
"width": 512,
"height": 384,
"content": "## Transcribe voice input\n\nSends downloaded audio to Groq for transcription and maps the transcript into the same message/user format expected by the AI agent."
},
"typeVersion": 1
},
{
"id": "6249c3e4-d4a2-451b-8982-7100a6b7f390",
"name": "Sticky Note25",
"type": "n8n-nodes-base.stickyNote",
"position": [
2560,
640
],
"parameters": {
"color": "#320622",
"width": 1200,
"height": 448,
"content": "## Assistant chat core\n\nRuns the central AI agent with memory and an OpenRouter model, then sends the generated response back to Telegram."
},
"typeVersion": 1
},
{
"id": "c0021598-f21b-4211-b390-98d68475421f",
"name": "Sticky Note26",
"type": "n8n-nodes-base.stickyNote",
"position": [
3168,
1168
],
"parameters": {
"color": "#032106",
"width": 896,
"height": 320,
"content": "## Calendar agent tools\n\nGoogle Calendar tools available to the agent for creating, deleting, reading, updating, and listing calendar events."
},
"typeVersion": 1
},
{
"id": "4d75e3ce-816d-4080-92ea-b9fe2b9d3a1c",
"name": "Sticky Note27",
"type": "n8n-nodes-base.stickyNote",
"position": [
4160,
1168
],
"parameters": {
"color": "#011818",
"width": 528,
"height": 320,
"content": "## Todoist lookup tools\n\nTodoist tools clustered near the agent for finding projects and tasks, plus creating new tasks when requested."
},
"typeVersion": 1
},
{
"id": "d48026b6-65b4-498a-95b7-0a12454de08e",
"name": "Sticky Note28",
"type": "n8n-nodes-base.stickyNote",
"position": [
4832,
1168
],
"parameters": {
"color": 7,
"width": 720,
"height": 320,
"content": "## Todoist task actions\n\nTodoist tools for modifying task state, including updating, closing, and deleting existing tasks."
},
"typeVersion": 1
},
{
"id": "779e4bcd-6ce1-48f0-ba87-e2853b97bc05",
"name": "Sticky Note29",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
1728
],
"parameters": {
"color": "#070113",
"width": 1120,
"height": 368,
"content": "## Calendar reminder digest\n\nScheduled branch that retrieves upcoming calendar events, formats them with JavaScript, and sends the reminder digest through Telegram."
},
"typeVersion": 1
},
{
"id": "fef69044-7f00-4bf5-b57e-c394e5b41ec0",
"name": "Sticky Note30",
"type": "n8n-nodes-base.stickyNote",
"position": [
2560,
1728
],
"parameters": {
"color": "#0E1301",
"width": 960,
"height": 496,
"content": "## Todoist summary fetch\n\nScheduled Todoist summary branch that fetches tasks and projects in parallel, then merges the results for formatting."
},
"typeVersion": 1
},
{
"id": "c6f152c6-6fbf-4fbf-878e-c9156d9aec5d",
"name": "Sticky Note31",
"type": "n8n-nodes-base.stickyNote",
"position": [
3600,
1776
],
"parameters": {
"color": "#0D010E",
"width": 720,
"height": 464,
"content": "## Todoist summary delivery\n\nFormats the merged Todoist data into a Telegram-friendly summary and sends it as a message."
},
"typeVersion": 1
},
{
"id": "e3057a52-a482-46e9-a959-d4c60af916eb",
"name": "Sticky Note32",
"type": "n8n-nodes-base.stickyNote",
"position": [
2720,
2560
],
"parameters": {
"color": 3,
"width": 640,
"height": 352,
"content": "## Workflow error alerts\n\nCatches workflow errors and sends an alert message to Telegram for monitoring and troubleshooting."
},
"typeVersion": 1
},
{
"id": "954db7ac-8aba-4223-86ee-576cf2a457fa",
"name": "Sticky Note33",
"type": "n8n-nodes-base.stickyNote",
"position": [
1072,
2704
],
"parameters": {
"color": 7,
"width": 848,
"height": 464,
"content": "## Cal.com Webhook notification router\n\nReceives CAL webhook calls and routes them through a switch to one of several Telegram notification paths."
},
"typeVersion": 1
},
{
"id": "8a104773-6936-4e74-9ae7-5e72f2047b7c",
"name": "Sticky Note34",
"type": "n8n-nodes-base.stickyNote",
"position": [
2144,
2320
],
"parameters": {
"color": 7,
"width": 304,
"height": 1136,
"content": "## CAL Booking Telegram alerts\n\nFour Telegram send nodes that deliver different webhook-triggered notification messages based on the router output."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "36832b9f-c8bb-41e0-a428-c42cd61a4e03",
"nodeGroups": [],
"connections": {
"Merge1": {
"main": [
[
{
"node": "Telegram summary1",
"type": "main",
"index": 0
}
]
]
},
"Switch": {
"main": [
[
{
"node": "Send a text message1",
"type": "main",
"index": 0
}
],
[
{
"node": "Send a text message2",
"type": "main",
"index": 0
}
],
[
{
"node": "Send a text message3",
"type": "main",
"index": 0
}
],
[
{
"node": "Send a text message4",
"type": "main",
"index": 0
}
]
]
},
"Switch2": {
"main": [
[
{
"node": "Get a file1",
"type": "main",
"index": 0
}
],
[
{
"node": "Text Path1",
"type": "main",
"index": 0
}
]
]
},
"Webhook": {
"main": [
[
{
"node": "Switch",
"type": "main",
"index": 0
}
]
]
},
"AI Agent1": {
"main": [
[
{
"node": "Send a text message9",
"type": "main",
"index": 0
}
]
]
},
"Close Task": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Text Path1": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Create Task": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Delete Task": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get a file1": {
"main": [
[
{
"node": "Download Audio1",
"type": "main",
"index": 0
}
]
]
},
"Update Task": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Voice Path1": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Send a text message6",
"type": "main",
"index": 0
}
]
]
},
"Fix Metadata1": {
"main": [
[
{
"node": "Groq Transcribe1",
"type": "main",
"index": 0
}
]
]
},
"Get an event1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get Many Tasks": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get many tasks": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory1": {
"ai_memory": [
[
{
"node": "AI Agent1",
"type": "ai_memory",
"index": 0
}
]
]
},
"Download Audio1": {
"main": [
[
{
"node": "Fix Metadata1",
"type": "main",
"index": 0
}
]
]
},
"Get many event1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get many events": {
"main": [
[
{
"node": "Code in JavaScript",
"type": "main",
"index": 0
}
]
]
},
"Create an event1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Delete an event1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Groq Transcribe1": {
"main": [
[
{
"node": "Voice Path1",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Get many events",
"type": "main",
"index": 0
}
]
]
},
"Update an event1": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get Many Projects": {
"ai_tool": [
[
{
"node": "AI Agent1",
"type": "ai_tool",
"index": 0
}
]
]
},
"Get many projects": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
}
]
]
},
"Schedule Trigger3": {
"main": [
[
{
"node": "Get many projects",
"type": "main",
"index": 0
},
{
"node": "Get many tasks",
"type": "main",
"index": 0
}
]
]
},
"Telegram Trigger1": {
"main": [
[
{
"node": "Switch2",
"type": "main",
"index": 0
}
]
]
},
"Telegram summary1": {
"main": [
[
{
"node": "Send a text message8",
"type": "main",
"index": 0
}
]
]
},
"Code in JavaScript": {
"main": [
[
{
"node": "Send a text message5",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Gemini 2.5 flash1": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"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.
googleCalendarOAuth2ApihttpCustomAuthopenRouterApitelegramApitodoistApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow turns Telegram into a personal assistant that manages your Google Calendar and Todoist, sends daily briefings, and alerts you when meetings are booked or things break. Morning briefing - Every day at a set time, the workflow checks your Google Calendar for today's…
Source: https://n8n.io/workflows/16833/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Template Name: AI Personal Assistant - Task & Email Management Price: $27 Category: Productivity & Automation Difficulty: Intermediate Use Case: Personal productivity automation for busy professionals
The CA - Tele Assistant workflow is an intelligent Telegram bot designed to help you manage your Google Calendar effortlessly through natural language and voice commands. Hands-free calendar managemen
Arvifund - Supabase (Fixed v6). Uses httpRequest, telegram, supabase, telegramTrigger. Event-driven trigger; 92 nodes.
Arvifund - Supabase (Fixed v5). Uses httpRequest, telegram, googleSheets, telegramTrigger. Event-driven trigger; 91 nodes.
Arvifund - Supabase. Uses httpRequest, telegram, googleSheets, telegramTrigger. Event-driven trigger; 90 nodes.