{ "updatedAt": "2026-05-14T00:01:24.692Z", "createdAt": "2026-03-18T20:17:45.262Z", "id": "QRCCdHNXZUHc2Oz4", "name": "Calendar to Obsidian Notes", "description": null, "active": true, "isArchived": false, "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "hours", "hoursInterval": 6 } ] } }, "id": "schedule-trigger", "name": "Schedule Trigger", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1, "position": [ 240, 304 ] }, { "parameters": { "operation": "getAll", "calendar": { "__rl": true, "value": "william.valentin.info@gmail.com", "mode": "list", "cachedResultName": "Perso" }, "limit": 20, "options": { "timeMin": "={{ new Date().toISOString() }}", "timeMax": "={{ new Date(Date.now() + 7*24*60*60*1000).toISOString() }}", "singleEvents": true, "orderBy": "startTime" } }, "id": "get-events", "name": "Get Upcoming Events", "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1, "position": [ 464, 304 ], "credentials": { "googleCalendarOAuth2Api": { "id": "458fY4bs1z49OTeZ", "name": "Google Calendar account" } }, "continueOnFail": true, "alwaysOutputData": true }, { "parameters": { "jsCode": "const event = $input.item.json || {};\nconst now = new Date();\nconst today = now.toISOString().slice(0, 10);\nconst hasUsableEvent = event.start && (event.summary || event.id || event.htmlLink);\nif (event.error || event.message || !hasUsableEvent) {\n const detail = String(event.error?.message || event.message || event.error || 'Google Calendar returned no usable event; credentials may need reauthorization.').replace(/`/g, \"'\").slice(0, 1000);\n const content = `---\ntitle: \"Google Calendar sync needs attention\"\narea: notes\ntags: [calendar, automation, degraded]\ncreated: ${today}\nupdated: ${today}\nstatus: needs-reauth\n---\n\n# Google Calendar sync needs attention\n\nThe n8n Calendar to Obsidian workflow could not read Google Calendar events.\n\nLikely cause: expired Google OAuth credentials in n8n.\n\nAction: reauthorize the Google Calendar credential used by workflow QRCCdHNXZUHc2Oz4, then run the workflow manually.\n\nLast observed detail:\n\n> ${detail}\n`;\n return [{ json: { path: `Notes/Calendar Sync Status/${today} Google Calendar Needs Reauth.md`, content, title: 'Google Calendar sync needs attention', date: today, degraded: true } }];\n}\nconst event = $input.item.json;\nconst startRaw = event.start?.dateTime || event.start?.date || \"\";\nconst date = startRaw.split(\"T\")[0];\nconst title = (event.summary || \"Untitled Event\").replace(/[\\/\\\\?%*:|\"<>]/g, \"-\").substring(0, 80);\nconst location = event.location || \"\";\nconst description = event.description || \"\";\nconst attendees = (event.attendees || []).map(a => a.email).join(\", \");\nconst endRaw = event.end?.dateTime || event.end?.date || \"\";\nconst startTime = startRaw.includes(\"T\") ? startRaw.split(\"T\")[1].substring(0,5) : \"All day\";\nconst endTime = endRaw.includes(\"T\") ? endRaw.split(\"T\")[1].substring(0,5) : \"\";\nconst timeStr = endTime ? `${startTime} – ${endTime}` : startTime;\nconst frontmatter = `---\\ntitle: \"${title}\"\\narea: notes\\ntags: [calendar, event]\\ncreated: ${date}\\nupdated: ${date}\\nstatus: active\\nevent_date: ${date}\\nevent_time: \"${timeStr}\"\\n---`;\nconst content = `${frontmatter}\\n\\n# ${title}\\n\\n**Date:** ${date}\\n**Time:** ${timeStr}\\n${location ? `**Location:** ${location}\\n` : \"\"}${attendees ? `**Attendees:** ${attendees}\\n` : \"\"}\\n## Description\\n\\n${description || \"_No description_\"}\\n\\n## Notes\\n\\n_Add notes here_\\n`;\nreturn [{ json: { path: `Notes/${date} ${title}.md`, content, title, date, timeStr } }];" }, "id": "format-note", "name": "Format Event Note", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 688, 304 ] }, { "parameters": { "method": "PUT", "url": "=http://192.168.153.130:27123/vault/{{ encodeURIComponent($json.path).replace(/%2F/g, \"/\") }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "contentType": "raw", "rawContentType": "text/markdown", "body": "={{ $json.content }}", "options": { "response": { "response": { "neverError": true } } } }, "id": "write-to-vault", "name": "Write to Vault", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [ 912, 304 ], "credentials": { "httpHeaderAuth": { "id": "465Swz2b71O2KRAK", "name": "Obsidian Local REST API" } } } ], "connections": { "Schedule Trigger": { "main": [ [ { "node": "Get Upcoming Events", "type": "main", "index": 0 } ] ] }, "Get Upcoming Events": { "main": [ [ { "node": "Format Event Note", "type": "main", "index": 0 } ] ] }, "Format Event Note": { "main": [ [ { "node": "Write to Vault", "type": "main", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "callerPolicy": "workflowsFromSameOwner", "availableInMCP": false }, "staticData": { "node:Schedule Trigger": { "recurrenceRules": [ 6 ] } }, "meta": null, "pinData": {}, "versionId": "40b22838-7ce4-4632-b186-b78ccda438c4", "activeVersionId": "40b22838-7ce4-4632-b186-b78ccda438c4", "versionCounter": 1636, "triggerCount": 1, "shared": [ { "updatedAt": "2026-03-18T20:17:45.264Z", "createdAt": "2026-03-18T20:17:45.264Z", "role": "workflow:owner", "workflowId": "QRCCdHNXZUHc2Oz4", "projectId": "WGdp8QunI1tHpjXa", "project": { "updatedAt": "2026-03-11T21:08:10.005Z", "createdAt": "2026-03-11T21:05:11.541Z", "id": "WGdp8QunI1tHpjXa", "name": "will will ", "type": "personal", "icon": null, "description": null, "creatorId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5" } } ], "tags": [ { "updatedAt": "2026-03-19T04:40:29.915Z", "createdAt": "2026-03-19T04:40:29.915Z", "id": "GLr9Awuvw8uO7ZRP", "name": "calendar" }, { "updatedAt": "2026-03-19T04:40:29.892Z", "createdAt": "2026-03-19T04:40:29.892Z", "id": "VfqIkUpiu2YMBSHw", "name": "obsidian-sync" } ], "activeVersion": { "updatedAt": "2026-05-14T00:01:24.693Z", "createdAt": "2026-05-14T00:01:24.693Z", "versionId": "40b22838-7ce4-4632-b186-b78ccda438c4", "workflowId": "QRCCdHNXZUHc2Oz4", "nodes": [ { "parameters": { "rule": { "interval": [ { "field": "hours", "hoursInterval": 6 } ] } }, "id": "schedule-trigger", "name": "Schedule Trigger", "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1, "position": [ 240, 304 ] }, { "parameters": { "operation": "getAll", "calendar": { "__rl": true, "value": "william.valentin.info@gmail.com", "mode": "list", "cachedResultName": "Perso" }, "limit": 20, "options": { "timeMin": "={{ new Date().toISOString() }}", "timeMax": "={{ new Date(Date.now() + 7*24*60*60*1000).toISOString() }}", "singleEvents": true, "orderBy": "startTime" } }, "id": "get-events", "name": "Get Upcoming Events", "type": "n8n-nodes-base.googleCalendar", "typeVersion": 1, "position": [ 464, 304 ], "credentials": { "googleCalendarOAuth2Api": { "id": "458fY4bs1z49OTeZ", "name": "Google Calendar account" } }, "continueOnFail": true, "alwaysOutputData": true }, { "parameters": { "jsCode": "const event = $input.item.json || {};\nconst now = new Date();\nconst today = now.toISOString().slice(0, 10);\nconst hasUsableEvent = event.start && (event.summary || event.id || event.htmlLink);\nif (event.error || event.message || !hasUsableEvent) {\n const detail = String(event.error?.message || event.message || event.error || 'Google Calendar returned no usable event; credentials may need reauthorization.').replace(/`/g, \"'\").slice(0, 1000);\n const content = `---\ntitle: \"Google Calendar sync needs attention\"\narea: notes\ntags: [calendar, automation, degraded]\ncreated: ${today}\nupdated: ${today}\nstatus: needs-reauth\n---\n\n# Google Calendar sync needs attention\n\nThe n8n Calendar to Obsidian workflow could not read Google Calendar events.\n\nLikely cause: expired Google OAuth credentials in n8n.\n\nAction: reauthorize the Google Calendar credential used by workflow QRCCdHNXZUHc2Oz4, then run the workflow manually.\n\nLast observed detail:\n\n> ${detail}\n`;\n return [{ json: { path: `Notes/Calendar Sync Status/${today} Google Calendar Needs Reauth.md`, content, title: 'Google Calendar sync needs attention', date: today, degraded: true } }];\n}\nconst event = $input.item.json;\nconst startRaw = event.start?.dateTime || event.start?.date || \"\";\nconst date = startRaw.split(\"T\")[0];\nconst title = (event.summary || \"Untitled Event\").replace(/[\\/\\\\?%*:|\"<>]/g, \"-\").substring(0, 80);\nconst location = event.location || \"\";\nconst description = event.description || \"\";\nconst attendees = (event.attendees || []).map(a => a.email).join(\", \");\nconst endRaw = event.end?.dateTime || event.end?.date || \"\";\nconst startTime = startRaw.includes(\"T\") ? startRaw.split(\"T\")[1].substring(0,5) : \"All day\";\nconst endTime = endRaw.includes(\"T\") ? endRaw.split(\"T\")[1].substring(0,5) : \"\";\nconst timeStr = endTime ? `${startTime} – ${endTime}` : startTime;\nconst frontmatter = `---\\ntitle: \"${title}\"\\narea: notes\\ntags: [calendar, event]\\ncreated: ${date}\\nupdated: ${date}\\nstatus: active\\nevent_date: ${date}\\nevent_time: \"${timeStr}\"\\n---`;\nconst content = `${frontmatter}\\n\\n# ${title}\\n\\n**Date:** ${date}\\n**Time:** ${timeStr}\\n${location ? `**Location:** ${location}\\n` : \"\"}${attendees ? `**Attendees:** ${attendees}\\n` : \"\"}\\n## Description\\n\\n${description || \"_No description_\"}\\n\\n## Notes\\n\\n_Add notes here_\\n`;\nreturn [{ json: { path: `Notes/${date} ${title}.md`, content, title, date, timeStr } }];" }, "id": "format-note", "name": "Format Event Note", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ 688, 304 ] }, { "parameters": { "method": "PUT", "url": "=http://192.168.153.130:27123/vault/{{ encodeURIComponent($json.path).replace(/%2F/g, \"/\") }}", "authentication": "genericCredentialType", "genericAuthType": "httpHeaderAuth", "sendBody": true, "contentType": "raw", "rawContentType": "text/markdown", "body": "={{ $json.content }}", "options": { "response": { "response": { "neverError": true } } } }, "id": "write-to-vault", "name": "Write to Vault", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4, "position": [ 912, 304 ], "credentials": { "httpHeaderAuth": { "id": "465Swz2b71O2KRAK", "name": "Obsidian Local REST API" } } } ], "connections": { "Schedule Trigger": { "main": [ [ { "node": "Get Upcoming Events", "type": "main", "index": 0 } ] ] }, "Get Upcoming Events": { "main": [ [ { "node": "Format Event Note", "type": "main", "index": 0 } ] ] }, "Format Event Note": { "main": [ [ { "node": "Write to Vault", "type": "main", "index": 0 } ] ] } }, "authors": "will will", "name": null, "description": null, "autosaved": false, "workflowPublishHistory": [ { "createdAt": "2026-05-14T00:01:24.723Z", "id": 1466, "workflowId": "QRCCdHNXZUHc2Oz4", "versionId": "40b22838-7ce4-4632-b186-b78ccda438c4", "event": "activated", "userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5" }, { "createdAt": "2026-05-14T00:01:24.711Z", "id": 1465, "workflowId": "QRCCdHNXZUHc2Oz4", "versionId": "40b22838-7ce4-4632-b186-b78ccda438c4", "event": "deactivated", "userId": "5ad50ead-6e6a-4d12-ab5b-e5db15835bb5" } ] } }