AutomationFlowsSlack & Telegram › Sweep Departing Staff Commitments From Google Calendar and Asana Into a…

Sweep Departing Staff Commitments From Google Calendar and Asana Into a…

Original n8n title: Sweep Departing Staff Commitments From Google Calendar and Asana Into a Notion Checklist and Slack

Sweep departing staff commitments from Google Calendar and Asana into a Notion checklist and Slack. Uses formTrigger, googleCalendar, asana, notion. Event-driven trigger; 23 nodes.

Event trigger★★★★☆ complexity23 nodesForm TriggerGoogle CalendarAsanaNotionHTTP RequestSlack
Slack & Telegram Trigger: Event Nodes: 23 Complexity: ★★★★☆ Added:

This workflow follows the Form Trigger → 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
{
  "name": "Sweep departing staff commitments from Google Calendar and Asana into a Notion checklist and Slack",
  "nodes": [
    {
      "parameters": {
        "formTitle": "Departure intake",
        "formDescription": "Submit a leaver to sweep their future calendar commitments and open Asana tasks into a handover manifest.",
        "formFields": {
          "values": [
            {
              "fieldLabel": "Leaver email",
              "fieldType": "email",
              "placeholder": "name@example.com",
              "requiredField": true
            },
            {
              "fieldLabel": "Last working day",
              "fieldType": "date",
              "requiredField": true
            },
            {
              "fieldLabel": "Asana user GID (optional)",
              "placeholder": "Numeric GID fallback if the email is not the Asana login"
            }
          ]
        },
        "options": {
          "appendAttribution": false,
          "buttonLabel": "Run sweep"
        }
      },
      "id": "0cec0023-8a2c-4286-b2f9-2a581820606c",
      "name": "Departure Intake Form",
      "type": "n8n-nodes-base.formTrigger",
      "typeVersion": 2.6,
      "position": [
        80,
        -208
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "cfg-leaver-email",
              "name": "leaverEmail",
              "type": "string",
              "value": "={{ ($json['Leaver email'] || '').toString().trim().toLowerCase() }}"
            },
            {
              "id": "cfg-last-day",
              "name": "lastWorkingDay",
              "type": "string",
              "value": "={{ $json['Last working day'] }}"
            },
            {
              "id": "cfg-sweep-start",
              "name": "sweepStartIso",
              "type": "string",
              "value": "={{ DateTime.fromISO($json['Last working day']).endOf('day').toISO() }}"
            },
            {
              "id": "cfg-asana-user",
              "name": "asanaUserIdentifier",
              "type": "string",
              "value": "={{ ($json['Asana user GID (optional)'] || $json['Leaver email']).toString().trim() }}"
            },
            {
              "id": "cfg-calendar-ids",
              "name": "programCalendarIds",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__PROGRAM_CALENDAR_IDS_COMMA_SEPARATED__>"
            },
            {
              "id": "cfg-asana-workspace",
              "name": "asanaWorkspaceGid",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__ASANA_WORKSPACE_GID__>"
            },
            {
              "id": "cfg-notion-parent",
              "name": "notionParentPageId",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__NOTION_PARENT_PAGE_ID__>"
            },
            {
              "id": "cfg-slack-channel",
              "name": "slackChannelId",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__SLACK_CHANNEL_ID__>"
            }
          ]
        },
        "options": {}
      },
      "id": "0125d5ef-4ede-4dc6-abe4-8966f8f4762f",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        368,
        -208
      ]
    },
    {
      "parameters": {
        "jsCode": "const cfg = $('Workflow Configuration').first().json;\nconst raw = String(cfg.programCalendarIds || '');\nconst ids = raw.split(',').map(s => s.trim()).filter(s => s.length > 0);\nreturn ids.map(id => ({ json: { calendarId: id } }));"
      },
      "id": "cceab0e2-4d4c-4738-ad22-dfeacdd59937",
      "name": "Expand Program Calendar List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        800,
        -208
      ]
    },
    {
      "parameters": {
        "operation": "getAll",
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.calendarId }}"
        },
        "returnAll": true,
        "timeMin": "={{ $('Workflow Configuration').first().json.sweepStartIso }}",
        "timeMax": "={{ $now.plus({ years: 2 }).toISO() }}",
        "options": {
          "fields": "*",
          "query": "={{ $('Workflow Configuration').first().json.leaverEmail }}",
          "recurringEventHandling": "first"
        }
      },
      "id": "0cfb8403-3bdc-4631-b531-d3783b2b449f",
      "name": "Fetch Future Events Per Calendar",
      "type": "n8n-nodes-base.googleCalendar",
      "typeVersion": 1.3,
      "position": [
        1088,
        -208
      ],
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// The Calendar q free text param also matches display names, so require an exact email match here.\nconst cfg = $('Workflow Configuration').first().json;\nconst leaver = String(cfg.leaverEmail || '').toLowerCase();\nconst findings = [];\nfor (const item of $input.all()) {\n  const ev = item.json;\n  if (!ev || ev.error || !ev.id) continue;\n  const organizerEmail = String((ev.organizer && ev.organizer.email) || '').toLowerCase();\n  const attendees = Array.isArray(ev.attendees) ? ev.attendees : [];\n  const isOrganizer = organizerEmail === leaver;\n  const isAttendee = attendees.some(a => String(a.email || '').toLowerCase() === leaver);\n  if (!isOrganizer && !isAttendee) continue;\n  const isRecurring = Array.isArray(ev.recurrence) && ev.recurrence.length > 0;\n  findings.push({ json: {\n    source: 'calendar',\n    title: ev.summary || '(no title)',\n    when: (ev.start && (ev.start.dateTime || ev.start.date)) || 'unknown start',\n    link: ev.htmlLink || '',\n    isRecurring: isRecurring,\n    role: isOrganizer ? 'organizer' : 'attendee',\n    bucket: (isOrganizer || isRecurring) ? 'needs_new_owner' : 'cancel_candidate'\n  } });\n}\nreturn findings;"
      },
      "id": "262a388b-32ea-40e1-b767-046c7aa0bbd6",
      "name": "Keep Exact Leaver Matches",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        -208
      ]
    },
    {
      "parameters": {},
      "id": "0589ca24-4d92-46b0-9cdd-19a7a2165d0a",
      "name": "Merge Sweep Findings",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.2,
      "position": [
        1776,
        -192
      ],
      "alwaysOutputData": true
    },
    {
      "parameters": {
        "resource": "user",
        "userId": "={{ $('Workflow Configuration').first().json.asanaUserIdentifier }}"
      },
      "id": "449c8e61-2a64-43f2-9f54-8105ee10554d",
      "name": "Resolve Leaver Asana User",
      "type": "n8n-nodes-base.asana",
      "typeVersion": 1,
      "position": [
        800,
        -16
      ],
      "credentials": {
        "asanaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "getAll",
        "returnAll": true,
        "filters": {
          "assignee": "={{ $json.gid }}",
          "opt_fields": [
            "name",
            "completed",
            "due_on",
            "due_at",
            "projects",
            "projects.name",
            "permalink_url",
            "resource_subtype"
          ],
          "workspace": "={{ $('Workflow Configuration').first().json.asanaWorkspaceGid }}",
          "completed_since": "now"
        }
      },
      "id": "e24744cf-e6cd-47f4-b5b2-d1bd7ca00b1f",
      "name": "Fetch Open Leaver Tasks",
      "type": "n8n-nodes-base.asana",
      "typeVersion": 1,
      "position": [
        1088,
        -16
      ],
      "credentials": {
        "asanaApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const cfg = $('Workflow Configuration').first().json;\nconst lastDay = String(cfg.lastWorkingDay || '');\nconst findings = [];\nfor (const item of $input.all()) {\n  const t = item.json;\n  if (!t || t.error || !t.gid) continue;\n  if (t.completed === true) continue;\n  const due = t.due_on || (t.due_at ? String(t.due_at).slice(0, 10) : null);\n  if (due !== null && due <= lastDay) continue;\n  findings.push({ json: {\n    source: 'asana',\n    title: t.name || '(untitled task)',\n    when: due || 'no due date',\n    link: t.permalink_url || '',\n    isRecurring: false,\n    role: 'assignee',\n    projects: (Array.isArray(t.projects) ? t.projects : []).map(p => p.name || p.gid).join(', '),\n    bucket: due ? 'needs_new_owner' : 'cancel_candidate'\n  } });\n}\nreturn findings;"
      },
      "id": "ee98fa40-84ec-432a-bae8-67fd80966949",
      "name": "Keep Future Or Undated Tasks",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        -16
      ]
    },
    {
      "parameters": {
        "jsCode": "const cfg = $('Workflow Configuration').first().json;\nconst findings = $input.all().map(i => i.json).filter(f => f && f.source);\nconst needsOwner = findings.filter(f => f.bucket === 'needs_new_owner');\nconst cancels = findings.filter(f => f.bucket === 'cancel_candidate');\nconst recurringCount = findings.filter(f => f.isRecurring).length;\nconst asText = (content) => [{ type: 'text', text: { content: String(content).slice(0, 1900) } }];\nconst heading = (content) => ({ object: 'block', type: 'heading_2', heading_2: { rich_text: asText(content) } });\nconst paragraph = (content) => ({ object: 'block', type: 'paragraph', paragraph: { rich_text: asText(content) } });\nconst todo = (f) => {\n  const prefix = f.isRecurring ? 'RECURRING ' : '';\n  const source = f.source === 'calendar' ? 'Calendar' : 'Asana';\n  const label = prefix + source + ': ' + f.title + ' (' + f.when + ', ' + f.role + ')';\n  const rich = [{ type: 'text', text: { content: label.slice(0, 1800) } }];\n  if (f.link) rich.push({ type: 'text', text: { content: ' open item', link: { url: f.link } } });\n  return { object: 'block', type: 'to_do', to_do: { rich_text: rich, checked: false } };\n};\nconst blocks = [];\nblocks.push(paragraph('Departure sweep for ' + cfg.leaverEmail + ', last working day ' + cfg.lastWorkingDay + '. Reassign or cancel every item, then check it off.'));\nblocks.push(heading('Needs a new owner (' + needsOwner.length + ')'));\nfor (const f of needsOwner) blocks.push(todo(f));\nblocks.push(heading('Cancel candidates (' + cancels.length + ')'));\nfor (const f of cancels) blocks.push(todo(f));\nreturn [{ json: {\n  totalFindings: findings.length,\n  needsOwnerCount: needsOwner.length,\n  cancelCount: cancels.length,\n  recurringCount: recurringCount,\n  blocks: blocks\n} }];"
      },
      "id": "aafee45d-d4bc-4e71-be0d-6a3bc6e6d634",
      "name": "Bucket Findings For Handover",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2048,
        -192
      ]
    },
    {
      "parameters": {
        "conditions": {
          "combinator": "and",
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "has-findings",
              "leftValue": "={{ $json.totalFindings }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "1e6c1571-b2f5-4217-86a8-d08f85ba4376",
      "name": "Route Empty Sweep",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.3,
      "position": [
        2288,
        -192
      ]
    },
    {
      "parameters": {
        "pageId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.notionParentPageId }}"
        },
        "title": "=Handover sweep: {{ $('Workflow Configuration').first().json.leaverEmail }}, last day {{ $('Workflow Configuration').first().json.lastWorkingDay }}",
        "options": {}
      },
      "id": "ca6efded-5273-4689-b49d-ec614fcda3c3",
      "name": "Create Handover Manifest Page",
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        2688,
        -208
      ],
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// Notion caps block appends at 100 blocks per call, so heavy leavers need chunked appends.\nconst manifest = $('Bucket Findings For Handover').first().json;\nconst page = $input.first().json;\nconst blocks = Array.isArray(manifest.blocks) ? manifest.blocks : [];\nconst chunks = [];\nfor (let i = 0; i < blocks.length; i += 100) {\n  chunks.push({ json: { pageId: page.id, chunkIndex: chunks.length, children: blocks.slice(i, i + 100) } });\n}\nreturn chunks;"
      },
      "id": "99405feb-34ae-44b8-acf9-b79cd7fa3f9e",
      "name": "Chunk Checklist Into Notion Batches",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2960,
        -208
      ]
    },
    {
      "parameters": {
        "method": "PATCH",
        "url": "=https://api.notion.com/v1/blocks/{{ $json.pageId }}/children",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "notionApi",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Notion-Version",
              "value": "2022-06-28"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify({ children: $json.children }) }}",
        "options": {
          "batching": {
            "batch": {
              "batchSize": 1,
              "batchInterval": 400
            }
          }
        }
      },
      "id": "7e9ef8cc-2b6d-40af-9db7-3ad68436e284",
      "name": "Append Checklist Chunk To Manifest",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        3248,
        -208
      ],
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const manifest = $('Bucket Findings For Handover').first().json;\nconst page = $('Create Handover Manifest Page').first().json;\nreturn [{ json: {\n  pageUrl: page.url || '',\n  totalFindings: manifest.totalFindings,\n  needsOwnerCount: manifest.needsOwnerCount,\n  cancelCount: manifest.cancelCount,\n  recurringCount: manifest.recurringCount,\n  appendCalls: $input.all().length\n} }];"
      },
      "id": "15fef6b5-7948-4408-8682-0da2445a1632",
      "name": "Collapse Appends To Single Summary",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3520,
        -208
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.slackChannelId }}"
        },
        "text": "=Departure handover sweep for {{ $('Workflow Configuration').first().json.leaverEmail }} is ready: {{ $json.totalFindings }} open commitments found, {{ $json.needsOwnerCount }} need a new owner, {{ $json.cancelCount }} are cancel candidates, {{ $json.recurringCount }} recurring. Manifest: {{ $json.pageUrl }}",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "unfurl_links": false
        }
      },
      "id": "57559caf-9bb5-45d7-907f-c401fd28b1f1",
      "name": "Post Manifest Link To Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        3792,
        -208
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.slackChannelId }}"
        },
        "text": "=Departure handover sweep for {{ $('Workflow Configuration').first().json.leaverEmail }}: no future events or open Asana tasks found after {{ $('Workflow Configuration').first().json.lastWorkingDay }} in the swept program calendars and Asana. Nothing to reassign.",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "unfurl_links": false
        }
      },
      "id": "af4871ad-f434-4811-b46b-909334e503aa",
      "name": "Post Clean Sweep Notice To Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        2688,
        16
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "# Departure Handover Sweep\n\nWhen someone leaves, their future meetings and open tasks quietly orphan. This workflow takes a departure intake form, sweeps the configured program Google Calendars and Asana for every future commitment the leaver holds, groups the findings into needs a new owner versus cancel candidate, writes the manifest as a Notion checklist page, and posts the link to Slack with counts.\n\n## How it works\n1. A coordinator submits the intake form: leaver email, last working day, optional Asana user GID.\n2. Workflow Configuration centralizes the program calendar list and every ID the sweep needs.\n3. Each configured calendar is swept for events after the last working day where the leaver is organizer or attendee. Recurring masters are kept intact and flagged, they orphan hardest.\n4. Asana resolves the leaver by email, GID as fallback, then pulls open tasks due after the last day or with no due date.\n5. Findings are bucketed: needs a new owner versus cancel candidate.\n6. A Notion manifest page is created and the checklist is appended in chunks of 100 blocks.\n7. Slack receives the manifest link with counts, or a clean sweep notice when nothing was found.\n\n## Setup\n- [ ] Replace PROGRAM_CALENDAR_IDS_COMMA_SEPARATED with the program calendar IDs to sweep, comma separated\n- [ ] Replace ASANA_WORKSPACE_GID with the Asana workspace to search\n- [ ] Replace NOTION_PARENT_PAGE_ID with the parent page that receives manifest pages\n- [ ] Replace SLACK_CHANNEL_ID with the channel that gets the manifest link\n- [ ] Connect Google Calendar, Asana, Notion, and Slack credentials, then activate",
        "height": 656,
        "width": 1500
      },
      "id": "bcc06a3f-b4ff-428e-9578-0c64791816f1",
      "name": "Sticky Overview",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -1184
      ]
    },
    {
      "parameters": {
        "content": "## Intake and configuration\n\nThe form collects leaver email, last working day, and an optional Asana GID. Every ID the sweep touches lives in Workflow Configuration, nothing is hardcoded downstream.",
        "height": 388,
        "width": 616,
        "color": 7
      },
      "id": "583fbbdd-d851-45cb-a996-405be973a53e",
      "name": "Sticky Intake",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        0,
        -416
      ]
    },
    {
      "parameters": {
        "content": "## Sweep calendars and Asana\n\nThe calendar list fans out one item per calendar. Events are fetched with fields set to star so attendees and recurrence survive the response, and recurring masters stay collapsed instead of flooding the manifest with instances. Code keeps only exact email matches because the free text query also matches display names. Asana resolves the leaver by email, then pulls open tasks with explicit opt_fields.",
        "height": 660,
        "width": 892,
        "color": 7
      },
      "id": "9417310a-4026-4d4d-b742-4bfc9974e05e",
      "name": "Sticky Sweep",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        688,
        -464
      ]
    },
    {
      "parameters": {
        "content": "## Consolidate and bucket\n\nBoth sweeps append into one stream. Findings are grouped into needs a new owner versus cancel candidate, and recurring events are counted separately since those orphan hardest. An empty sweep routes to a clean sweep notice instead of an empty manifest.",
        "height": 436,
        "width": 844,
        "color": 7
      },
      "id": "fd552f6d-77b6-47b5-a11d-57f8e3b39c93",
      "name": "Sticky Bucket",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1664,
        -416
      ]
    },
    {
      "parameters": {
        "content": "## Publish manifest and notify\n\nThe manifest is a Notion page of checklist blocks appended in chunks of 100, the Notion cap per append call. Slack gets the link with counts, or a clean sweep notice when nothing was found.",
        "height": 628,
        "width": 1484,
        "color": 7
      },
      "id": "a22ec163-83ef-47b3-b2ec-7fc45d13d45e",
      "name": "Sticky Publish",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2592,
        -384
      ]
    },
    {
      "parameters": {
        "content": "## Scope warning\n\nOnly calendars the coordinator credential can read get swept. The leaver private calendar is out of scope, so commitments that live only there will not appear in the manifest.",
        "height": 168,
        "width": 860,
        "color": 3
      },
      "id": "aa6d71f4-6a73-4341-8fe5-afe1c3ce5f60",
      "name": "Sticky Scope Warning",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1568,
        -736
      ]
    }
  ],
  "connections": {
    "Departure Intake Form": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Expand Program Calendar List",
            "type": "main",
            "index": 0
          },
          {
            "node": "Resolve Leaver Asana User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Expand Program Calendar List": {
      "main": [
        [
          {
            "node": "Fetch Future Events Per Calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Future Events Per Calendar": {
      "main": [
        [
          {
            "node": "Keep Exact Leaver Matches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keep Exact Leaver Matches": {
      "main": [
        [
          {
            "node": "Merge Sweep Findings",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Sweep Findings": {
      "main": [
        [
          {
            "node": "Bucket Findings For Handover",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Resolve Leaver Asana User": {
      "main": [
        [
          {
            "node": "Fetch Open Leaver Tasks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Open Leaver Tasks": {
      "main": [
        [
          {
            "node": "Keep Future Or Undated Tasks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Keep Future Or Undated Tasks": {
      "main": [
        [
          {
            "node": "Merge Sweep Findings",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Bucket Findings For Handover": {
      "main": [
        [
          {
            "node": "Route Empty Sweep",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Empty Sweep": {
      "main": [
        [
          {
            "node": "Create Handover Manifest Page",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Post Clean Sweep Notice To Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Handover Manifest Page": {
      "main": [
        [
          {
            "node": "Chunk Checklist Into Notion Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chunk Checklist Into Notion Batches": {
      "main": [
        [
          {
            "node": "Append Checklist Chunk To Manifest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append Checklist Chunk To Manifest": {
      "main": [
        [
          {
            "node": "Collapse Appends To Single Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Collapse Appends To Single Summary": {
      "main": [
        [
          {
            "node": "Post Manifest Link To Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": []
}

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

Sweep departing staff commitments from Google Calendar and Asana into a Notion checklist and Slack. Uses formTrigger, googleCalendar, asana, notion. Event-driven trigger; 23 nodes.

Source: https://github.com/exekyute/n8n-exekyute-templates/blob/main/pending-review/n8n-departure-handover-sweep/workflow.json — 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

Team leads, project managers, and operations staff who want to automate meeting documentation. Useful for any team that records meetings and needs structured notes with clear action items.

Form Trigger, HTTP Request, Notion +1
Slack & Telegram

This workflow collects a blog brief via an n8n form, uses Anthropic Claude to generate an outline and write each section, saves both outline and article as formatted Google Docs in Google Drive, then

Form Trigger, Google Sheets, HTTP Request +2
Slack & Telegram

This workflow runs a SEEK.com.au job search via Apify on a daily schedule or on-demand form submission, deduplicates new listings, and routes results to Google Sheets, Airtable, a webhook endpoint, an

HTTP Request, Google Sheets, Airtable +5
Slack & Telegram

This n8n template from Intuz provides a complete and automated solution for preparing and delivering context-rich briefings directly to attendees before every meeting.

Google Calendar Trigger, Notion, GitHub +3
Slack & Telegram

Upload a document (PDF, PNG, JPEG) via a web form and let easybits Extractor classify it into one of your defined categories. Based on the classification result and a confidence score, the document is

Form Trigger, HTTP Request, Google Drive +1