This workflow corresponds to n8n.io template #16925 — we link there as the canonical source.
This workflow follows the Gmail → Google Sheets 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": "3G84Vc8f3LHo8MzB",
"name": "HR Onboarding Automation \u2014 Slack + Google Sheets",
"tags": [],
"nodes": [
{
"id": "dabcbac8-894f-4c3f-9831-5bfc46d668cf",
"name": "Sticky Note \u2014 Workflow Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
912
],
"parameters": {
"width": 468,
"height": 624,
"content": "# \ud83c\udfe2 HR Onboarding Automation\n## Workflow 1 \u2014 Employee Invite Sender\n\n**What this workflow does:**\nWhen HR submits a new employee form, this workflow:\n1. Validates the submitted data\n2. Saves employee record to Google Sheets\n3. Maps department \u2192 Slack channels\n4. Sends a welcome email with Slack invite link\n5. Notifies the manager on Slack\n6. Updates employee status in the sheet\n\n**Trigger:** POST webhook from HR dashboard/form\n**Required fields:** full_name, email, department, role, manager_email, start_date\n\n**Tech Stack:**\n- n8n (automation engine)\n- Google Sheets (employee database)\n- Gmail (welcome email)\n- Slack (manager notification)"
},
"typeVersion": 1
},
{
"id": "6f593284-e3eb-4643-ac11-23e4d4aa58d8",
"name": "Sticky Note \u2014 Webhook",
"type": "n8n-nodes-base.stickyNote",
"position": [
2096,
1280
],
"parameters": {
"color": 6,
"width": 344,
"height": 476,
"content": "## \ud83d\udce5 Step 1 \u2014 Webhook Trigger\n\nThis node listens for POST requests from the HR form/dashboard.\n\n**Endpoint:**\n`POST /webhook/onboard-employee`\n\n**Expected JSON Body:**\n```json\n{\n \"full_name\": \"Ali Raza\",\n \"email\": \"ali@company.com\",\n \"department\": \"Engineering\",\n \"role\": \"Backend Developer\",\n \"manager_email\": \"mgr@company.com\",\n \"start_date\": \"2026-07-15\"\n}\n```\n\n\u26a0\ufe0f Use `/webhook-test/` URL while testing.\nUse `/webhook/` URL in production (workflow must be Active)."
},
"typeVersion": 1
},
{
"id": "1c6da62e-0e9f-4ff4-8c09-9020f9b6f17d",
"name": "Sticky Note \u2014 Validation",
"type": "n8n-nodes-base.stickyNote",
"position": [
2544,
1280
],
"parameters": {
"color": 6,
"width": 320,
"height": 448,
"content": "## \u2705 Step 2 \u2014 Validation\n\nChecks that these 3 fields are not empty:\n- `full_name`\n- `email`\n- `department`\n\n**TRUE branch \u2192** Continue onboarding\n**FALSE branch \u2192** Return 400 error response\n\nNote: Fields come from `$json.body.*` because n8n wraps webhook payloads in a `body` object."
},
"typeVersion": 1
},
{
"id": "7becf4be-8618-47ee-88cf-332522fbaf53",
"name": "Sticky Note \u2014 Google Sheets Save",
"type": "n8n-nodes-base.stickyNote",
"position": [
2960,
1280
],
"parameters": {
"color": 4,
"width": 356,
"height": 484,
"content": "## \ud83d\udcbe Step 3 \u2014 Save to Google Sheets\n\nAppends a new row to the **Sheet1** tab.\n\n**Columns written:**\nfull_name, email, department, role, manager_email, start_date\n\n**Auto-filled later:**\n- `status` \u2192 updated by this workflow + WF2\n- `slack_invited_at` \u2192 timestamp when invite sent\n- `slack_user_id` \u2192 filled when employee joins Slack\n\n\ud83d\udccc Sheet ID: `1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo`"
},
"typeVersion": 1
},
{
"id": "17a57b68-b33b-47d4-b69b-e29df0c03917",
"name": "Sticky Note \u2014 Channel Mapping",
"type": "n8n-nodes-base.stickyNote",
"position": [
3424,
1280
],
"parameters": {
"color": 4,
"width": 392,
"height": 520,
"content": "## \ud83d\uddc2\ufe0f Step 4 \u2014 Department \u2192 Channel Mapping\n\nMaps each department to relevant Slack channels.\n\n**Current Mapping:**\n- Engineering \u2192 all-testn8n, new-channel\n- Sales \u2192 all-testn8n, social\n- Marketing \u2192 all-testn8n, social\n- HR \u2192 all-testn8n, new-channel\n- Design \u2192 all-testn8n, social\n\nAlso attaches the static **Slack Workspace Invite Link**.\n\n\u26a0\ufe0f Update `SLACK_INVITE_LINK` with a fresh link from:\nSlack \u2192 Workspace name \u2192 Invite people \u2192 Get invite link"
},
"typeVersion": 1
},
{
"id": "19ef6658-b7c1-4cf7-b26a-7601a1ab7065",
"name": "Sticky Note \u2014 Welcome Email",
"type": "n8n-nodes-base.stickyNote",
"position": [
3920,
1280
],
"parameters": {
"color": 3,
"width": 336,
"height": 532,
"content": "## \ud83d\udce7 Step 5 \u2014 Welcome Email\n\nSends a welcome email to the new employee.\n\n**Contains:**\n- Personalized greeting with name, role, department\n- Start date\n- Slack workspace invite link (static link)\n- Instructions to click and join\n\n**Gmail credential required.**\n\n\u26a0\ufe0f Non-Enterprise Slack limitation:\nWe cannot auto-create Slack accounts via API.\nEmployee must click the invite link themselves.\nWorkflow 2 handles the rest once they join."
},
"typeVersion": 1
},
{
"id": "2b006a9b-25d0-43d3-a16e-9f33cf17c78b",
"name": "Sticky Note \u2014 Manager Notify",
"type": "n8n-nodes-base.stickyNote",
"position": [
4352,
1280
],
"parameters": {
"color": 3,
"width": 336,
"height": 468,
"content": "## \ud83d\udd14 Step 6 \u2014 Notify Manager\n\nSends a Slack DM to the employee's manager.\n\n**Message includes:**\n- Employee name, department, role\n- Start date\n- Channels they'll be added to\n- Confirmation that invite email was sent\n\n**Slack OAuth2 credential required.**\n\nCurrently set to user ID `U0BDTGNCMJQ` for testing.\nIn production: resolve manager's Slack user ID dynamically from their email."
},
"typeVersion": 1
},
{
"id": "a17dc09a-3ffa-4918-9797-3b426e0ac7e0",
"name": "Sticky Note \u2014 Status Update",
"type": "n8n-nodes-base.stickyNote",
"position": [
4784,
1280
],
"parameters": {
"color": 4,
"width": 336,
"height": 432,
"content": "## \ud83d\udcdd Step 7 \u2014 Update Sheet Status\n\nUpdates the employee row in Google Sheets:\n- `status` \u2192 \"Invite Sent\"\n- `slack_invited_at` \u2192 current timestamp\n\nMatches row by `email` column (must be unique).\n\nHR can see in real-time:\n- **Invite Sent** = email sent, waiting to join\n- **Joined** = added to channels \u2713 (set by WF2)"
},
"typeVersion": 1
},
{
"id": "f943f1c0-85fc-4647-9713-cba19db83525",
"name": "Sticky Note \u2014 Setup Checklist",
"type": "n8n-nodes-base.stickyNote",
"position": [
5216,
1280
],
"parameters": {
"color": 2,
"width": 436,
"height": 616,
"content": "## \u2699\ufe0f Setup Checklist\n\n**Before going live, make sure:**\n\n\u2705 Google Sheets has columns:\nfull_name, email, department, role, manager_email, start_date, status, slack_invited_at, slack_user_id\n\n\u2705 Slack App has scopes:\nusers:read, users:read.email, channels:read, channels:manage, chat:write\n\n\u2705 Slack App \u2192 Event Subscriptions \u2192 team_join subscribed\n\n\u2705 Workflow 2 is **Active** (toggle ON in n8n)\n\n\u2705 Bot invited to all target channels (`/invite @DemoApp`)\n\n\u2705 Static Slack invite link updated in 'Map Department + Attach Invite Link' node\n\n\u2705 Department names match exactly:\nEngineering, Sales, Marketing, HR, Design"
},
"typeVersion": 1
},
{
"id": "f32264e5-4c61-410b-b7f5-3560e25f035f",
"name": "Webhook - New Employee Form",
"type": "n8n-nodes-base.webhook",
"notes": "POST /webhook/onboard-employee \u2014 HR form trigger",
"position": [
2096,
2176
],
"parameters": {
"path": "onboard-employee",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "4f951e64-cfb0-4ab2-a874-7fd84835664b",
"name": "Validate Required Fields",
"type": "n8n-nodes-base.if",
"position": [
2448,
2176
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-001",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.full_name }}",
"rightValue": ""
},
{
"id": "cond-002",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.email }}",
"rightValue": ""
},
{
"id": "cond-003",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.department }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "ff397acc-bf2c-4987-9efb-18fd1212c4c8",
"name": "Respond Validation Error",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2448,
2432
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "={{ { \"success\": false, \"message\": \"Missing required fields: full_name, email, or department\" } }}"
},
"typeVersion": 1.2
},
{
"id": "f3dee535-3be8-4dad-aeb6-25bdcccbc590",
"name": "Save Employee to Google Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
2800,
2176
],
"parameters": {
"columns": {
"value": {
"role": "={{ $json.body.role }}",
"email": "={{ $json.body.email }}",
"full_name": "={{ $json.body.full_name }}",
"department": "={{ $json.body.department }}",
"start_date": "={{ $json.body.start_date }}",
"manager_email": "={{ $json.body.manager_email }}"
},
"schema": [
{
"id": "full_name",
"type": "string",
"display": true,
"required": false,
"displayName": "full_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "department",
"type": "string",
"display": true,
"required": false,
"displayName": "department",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "role",
"type": "string",
"display": true,
"required": false,
"displayName": "role",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "manager_email",
"type": "string",
"display": true,
"required": false,
"displayName": "manager_email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "start_date",
"type": "string",
"display": true,
"required": false,
"displayName": "start_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_invited_at",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "slack_invited_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_user_id",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "slack_user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "bd69ddd4-8639-4622-9604-83a2a1c115d6",
"name": "Map Department + Attach Invite Link",
"type": "n8n-nodes-base.code",
"position": [
3152,
2176
],
"parameters": {
"jsCode": "const departmentChannelMap = {\n 'Engineering': ['all-testn8n', 'new-channel'],\n 'Sales': ['all-testn8n', 'social'],\n 'Marketing': ['all-testn8n', 'social'],\n 'HR': ['all-testn8n', 'new-channel'],\n 'Design': ['all-testn8n', 'social']\n};\n\nconst dept = $input.first().json.department;\nconst channels = departmentChannelMap[dept] || ['all-testn8n'];\n\nconst SLACK_INVITE_LINK = 'https://join.slack.com/t/testn8n-6i17414/shared_invite/zt-429tad5xx-6dmoOUMbNCJ_TmQpYUrUzA';\n\nreturn [{\n json: {\n ...$input.first().json,\n target_channels: channels,\n slack_invite_link: SLACK_INVITE_LINK\n }\n}];"
},
"typeVersion": 2
},
{
"id": "71679aa6-9c29-43de-9a3f-eae57b0131eb",
"name": "Send Welcome Email with Slack Invite Link",
"type": "n8n-nodes-base.gmail",
"position": [
3504,
2176
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=<h2>Welcome aboard, {{ $json.full_name }}!</h2><p>We're thrilled to have you join us as <strong>{{ $json.role }}</strong> in the <strong>{{ $json.department }}</strong> team, starting <strong>{{ $json.start_date }}</strong>.</p><p>Step 1: Click the link below to join our Slack workspace:</p><p><a href=\"{{ $json.slack_invite_link }}\">{{ $json.slack_invite_link }}</a></p><p>Once you join, you'll automatically be added to your team's channels and our bot will say hi!</p><p>See you soon!</p>",
"options": {},
"subject": "=Welcome to the team, {{ $json.full_name }}! \ud83c\udf89 Join us on Slack"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "3bfbe1a8-b545-4fef-8f59-8a869af52b32",
"name": "Notify Manager on Slack",
"type": "n8n-nodes-base.slack",
"position": [
3856,
2176
],
"parameters": {
"text": "=:bust_in_silhouette: Heads up! *{{ $('Map Department + Attach Invite Link').item.json.full_name }}* has been sent a Slack invite link.\n\nDepartment: {{ $('Map Department + Attach Invite Link').item.json.department }}\nRole: {{ $('Map Department + Attach Invite Link').item.json.role }}\nStart Date: {{ $('Map Department + Attach Invite Link').item.json.start_date }}\nManager: {{ $('Map Department + Attach Invite Link').item.json.manager_email }}\n\nThey'll be auto-added to: {{ $('Map Department + Attach Invite Link').item.json.target_channels.join(', ') }} once they join the workspace.",
"user": {
"__rl": true,
"mode": "list",
"value": "U0BDTGNCMJQ",
"cachedResultName": "umartkd989"
},
"select": "user",
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "1766ac45-0bbc-4567-a1a6-d5bab01ef5b3",
"name": "Update Status: Invite Sent",
"type": "n8n-nodes-base.googleSheets",
"position": [
4208,
2176
],
"parameters": {
"columns": {
"value": {
"email": "={{ $('Map Department + Attach Invite Link').item.json.email }}",
"status": "Invite Sent",
"slack_invited_at": "={{ $now.toISO() }}"
},
"schema": [
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_invited_at",
"type": "string",
"display": true,
"required": false,
"displayName": "slack_invited_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_user_id",
"type": "string",
"display": true,
"required": false,
"displayName": "slack_user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "f5aa5ea6-1835-4513-b992-4a8b6bdd4003",
"name": "Respond Success",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
4560,
2176
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"success\": true, \"message\": \"Onboarding invite sent\", \"employee\": $json.full_name } }}"
},
"typeVersion": 1.2
},
{
"id": "3917c684-423c-4c39-9650-fabb544e7154",
"name": "Sticky Note \u2014 WF2 Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
2976
],
"parameters": {
"width": 488,
"height": 440,
"content": "# \ud83d\udd17 Workflow 2 \u2014 Slack Team Join Listener\n\n**What this workflow does:**\nListens for Slack's `team_join` event (fired when anyone joins the workspace). When triggered:\n1. Verifies it's a real event (not URL verification challenge)\n2. Extracts new user's email + Slack user ID\n3. Looks up their record in Google Sheets\n4. Maps department to channels\n5. Adds user to each channel one by one\n6. Sends a welcome DM on Slack\n7. Updates sheet status to \"Joined\"\n\n**Setup Required:**\n- Slack App \u2192 Event Subscriptions \u2192 Enable\n- Request URL: `https://umarimran99999.app.n8n.cloud/webhook/slack-team-join`\n- Subscribe to bot event: `team_join`\n- This workflow must be **Active** (toggle ON)\n\n**Required Slack Scopes:**\n`users:read`, `users:read.email`, `channels:read`, `channels:manage`, `chat:write`"
},
"typeVersion": 1
},
{
"id": "4659064d-1a52-44d3-a70e-6998e49ee25c",
"name": "Sticky Note \u2014 Challenge",
"type": "n8n-nodes-base.stickyNote",
"position": [
2160,
2976
],
"parameters": {
"color": 6,
"width": 524,
"height": 456,
"content": "## \ud83e\udd1d URL Verification Challenge\n\nWhen you first save the Request URL in Slack's Event Subscriptions, Slack sends a one-time verification request:\n```json\n{ \"type\": \"url_verification\", \"challenge\": \"abc123\" }\n```\n\nThis IF node checks for that.\n\n**TRUE \u2192** Echo back the challenge (Slack marks URL as Verified \u2713)\n**FALSE \u2192** It's a real event, continue processing\n\n\u26a0\ufe0f This workflow must be **Active** and use the production `/webhook/` URL for Slack verification to work."
},
"typeVersion": 1
},
{
"id": "2b62e2ce-cdc8-421e-b242-e803af0389d9",
"name": "Sticky Note \u2014 Acknowledge",
"type": "n8n-nodes-base.stickyNote",
"position": [
5376,
2976
],
"parameters": {
"color": 7,
"width": 336,
"height": 392,
"content": "## \u26a1 Acknowledge First, Process Later\n\nSlack requires a response within **3 seconds** or it retries the event (causing duplicate processing).\n\nSo we:\n1. Immediately respond `{ ok: true }` (this node)\n2. Then continue with the actual processing below\n\nThis is standard Slack Events API best practice."
},
"typeVersion": 1
},
{
"id": "c5e88551-4348-4c73-96ba-ae7e5d409fd5",
"name": "Sticky Note \u2014 Extract User",
"type": "n8n-nodes-base.stickyNote",
"position": [
2784,
2976
],
"parameters": {
"color": 6,
"width": 300,
"height": 412,
"content": "## \ud83d\udc64 Extract User Info\n\nExtracts from the `team_join` Slack event payload:\n- `slack_user_id` \u2192 user.id (e.g. U0XXXXXXX)\n- `email` \u2192 user.profile.email\n- `real_name` \u2192 user's display name\n\nThese are used to look up the employee in Google Sheets and to send them a welcome DM."
},
"typeVersion": 1
},
{
"id": "9d126926-7aab-47a2-b36f-134a2bfd5440",
"name": "Sticky Note \u2014 Sheet Lookup",
"type": "n8n-nodes-base.stickyNote",
"position": [
3184,
2976
],
"parameters": {
"color": 4,
"width": 276,
"height": 516,
"content": "## \ud83d\udd0d Lookup in Google Sheets\n\nSearches Sheet1 for a row where `email` matches the email from Slack's event.\n\nThis connects the Slack join event back to the original onboarding record created by Workflow 1.\n\nReturns: full_name, department, role, manager_email, start_date.\n\n\u26a0\ufe0f If no match found (employee joined via a different email than HR entered), the workflow will fail here. HR should ensure emails match."
},
"typeVersion": 1
},
{
"id": "2101f212-0da8-45d5-972e-fdc73715d044",
"name": "Sticky Note \u2014 Channel Resolution",
"type": "n8n-nodes-base.stickyNote",
"position": [
3552,
2976
],
"parameters": {
"color": 4,
"width": 284,
"height": 536,
"content": "## \ud83d\udd04 Split Channels + Get IDs\n\n**Split Out Channels:**\nBreaks the `target_channels` array into individual items so each channel is processed separately (Slack API accepts one channel per invite call).\n\n**Get Channel ID by Name:**\nCalls `conversations.list` to fetch all workspace channels with their IDs.\n\n**Match Channel Name to ID:**\nFinds the channel whose `name` matches our target, extracts its ID.\n\n\u26a0\ufe0f Channel names must exactly match Slack channel names (no `#` prefix, lowercase)."
},
"typeVersion": 1
},
{
"id": "a9887f70-4059-4d27-9fe1-0286b87fe03c",
"name": "Sticky Note \u2014 Add + DM",
"type": "n8n-nodes-base.stickyNote",
"position": [
3936,
2976
],
"parameters": {
"color": 3,
"width": 920,
"height": 424,
"content": "## \u2795 Add to Channel + Welcome DM\n\n**Add User to Channel:**\nCalls Slack's `conversations.invite` with the resolved channel ID and the new user's Slack ID.\n\n`continueOnFail: true` \u2014 if one channel fails (bot not in channel, wrong ID), it continues to the next instead of stopping.\n\n**Send Welcome DM:**\nSends a personalized direct message to the new employee on Slack with their role and department.\n\n\u26a0\ufe0f Bot must be manually invited to each target channel first:\n`/invite @YourBotName` in each channel"
},
"typeVersion": 1
},
{
"id": "a2ed4fa2-7b5b-440a-9627-0a814fece47c",
"name": "Sticky Note \u2014 Final Update",
"type": "n8n-nodes-base.stickyNote",
"position": [
4960,
2976
],
"parameters": {
"color": 4,
"width": 320,
"height": 220,
"content": "## \u2705 Final Status Update\n\nUpdates the employee's row in Google Sheets:\n- `status` \u2192 \"Joined\"\n- `slack_invited_at` \u2192 current timestamp\n\nMatches by `email` column.\n\nHR can now see in the sheet:\n- **Invite Sent** = email sent, waiting for employee to join\n- **Joined** = employee has joined Slack and been added to channels \u2713"
},
"typeVersion": 1
},
{
"id": "98c15458-258c-4d08-b0d1-cbfa3eb72a23",
"name": "Slack Events Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
2096,
3984
],
"parameters": {
"path": "slack-team-join",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "b85cd5c9-15cb-4c16-bab3-073d2b662c9a",
"name": "Is URL Verification?",
"type": "n8n-nodes-base.if",
"position": [
2448,
3984
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "is-challenge",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.body.type }}",
"rightValue": "url_verification"
}
]
}
},
"typeVersion": 2
},
{
"id": "2639b8e5-5b2a-432b-8a10-c66ef09553b1",
"name": "Respond with Challenge",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2800,
3824
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"challenge\": $json.body.challenge } }}"
},
"typeVersion": 1.2
},
{
"id": "f71938af-97cd-42bd-801a-b2426c8b61c3",
"name": "Acknowledge Event",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
2800,
4128
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"ok\": true } }}"
},
"typeVersion": 1.2
},
{
"id": "6d4ec863-5649-43fa-9ed2-5fc0cda5c71d",
"name": "Extract New User Info",
"type": "n8n-nodes-base.code",
"position": [
3152,
4128
],
"parameters": {
"jsCode": "const body = $input.first().json.body;\nconst user = body.event.user;\n\nreturn [{\n json: {\n slack_user_id: user.id,\n email: user.profile.email,\n real_name: user.profile.real_name || user.real_name\n }\n}];"
},
"typeVersion": 2
},
{
"id": "9b11e812-6b86-4398-8b8b-c25d5e2185bd",
"name": "Find Employee Row by Email",
"type": "n8n-nodes-base.googleSheets",
"position": [
3504,
4128
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "={{ $json.email }}",
"lookupColumn": "email"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "bc8df802-0a9e-4f15-b22c-51c5265fcabf",
"name": "Map Department to Channels",
"type": "n8n-nodes-base.code",
"position": [
3856,
4128
],
"parameters": {
"jsCode": "const departmentChannelMap = {\n 'Engineering': ['all-testn8n', 'new-channel'],\n 'Sales': ['all-testn8n', 'social'],\n 'Marketing': ['all-testn8n', 'social'],\n 'HR': ['all-testn8n', 'new-channel'],\n 'Design': ['all-testn8n', 'social']\n};\n\nconst employee = $input.first().json;\nconst slackUser = $('Extract New User Info').first().json;\nconst channels = departmentChannelMap[employee.department] || ['all-testn8n'];\n\nreturn [{\n json: {\n ...employee,\n slack_user_id: slackUser.slack_user_id,\n target_channels: channels\n }\n}];"
},
"typeVersion": 2
},
{
"id": "180435af-e0f9-4a3a-a2e7-3286785a00b2",
"name": "Split Out Channels",
"type": "n8n-nodes-base.splitOut",
"position": [
4208,
4128
],
"parameters": {
"options": {},
"fieldToSplitOut": "target_channels"
},
"typeVersion": 1
},
{
"id": "5225f452-cdb3-4401-8d9e-bed004c05edc",
"name": "Get Channel ID by Name",
"type": "n8n-nodes-base.httpRequest",
"position": [
4560,
4128
],
"parameters": {
"url": "https://slack.com/api/conversations.list",
"options": {},
"sendQuery": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "limit",
"value": "200"
}
]
},
"nodeCredentialType": "slackOAuth2Api"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.2
},
{
"id": "ce615af1-c4c4-401c-82c6-12fed79f8b95",
"name": "Match Channel Name to ID",
"type": "n8n-nodes-base.code",
"position": [
4896,
4128
],
"parameters": {
"jsCode": "const channelName = $('Split Out Channels').first().json.target_channels.replace('#', '');\nconst channels = $input.first().json.channels;\n\nconst match = channels.find(c => c.name === channelName || c.name_normalized === channelName);\n\nif (!match) {\n return [{\n json: {\n ...$('Split Out Channels').first().json,\n channel_id: null,\n error: `Channel '${channelName}' not found \u2014 check bot is in the channel and name matches exactly`\n }\n }];\n}\n\nreturn [{\n json: {\n ...$('Split Out Channels').first().json,\n channel_id: match.id\n }\n}];"
},
"typeVersion": 2
},
{
"id": "5070170a-4014-4e27-8620-e1215160a482",
"name": "Add User to Channel",
"type": "n8n-nodes-base.slack",
"position": [
5248,
4128
],
"parameters": {
"userIds": "={{ $('Extract New User Info').item.json.slack_user_id }}",
"resource": "channel",
"channelId": "={{ $json.channel_id }}",
"operation": "invite",
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2,
"continueOnFail": true
},
{
"id": "04930277-8963-457b-8ec8-75e2e01c36d6",
"name": "Send Welcome DM",
"type": "n8n-nodes-base.slack",
"position": [
5600,
4128
],
"parameters": {
"text": "=:wave: Welcome to the team, *{{ $('Find Employee Row by Email').item.json.full_name }}*! :tada:\n\nYou've been added to your team's channels. Glad to have you here as *{{ $('Find Employee Row by Email').item.json.role }}* in *{{ $('Find Employee Row by Email').item.json.department }}*!\n\nFeel free to say hi in your channels \u2014 the team is excited to meet you! :rocket:",
"user": {
"__rl": true,
"mode": "id",
"value": "={{ $('Extract New User Info').item.json.slack_user_id }}"
},
"select": "user",
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "c372f9a2-8b2a-4da0-9b3a-0b12175ae836",
"name": "Update Status: Joined",
"type": "n8n-nodes-base.googleSheets",
"position": [
5952,
4128
],
"parameters": {
"columns": {
"value": {
"email": "={{ $('Extract New User Info').item.json.email }}",
"status": "Joined",
"slack_invited_at": "={{ $now.toISO() }}"
},
"schema": [
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_invited_at",
"type": "string",
"display": true,
"required": false,
"displayName": "slack_invited_at",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "c5390541-0c1b-47fb-9f87-e9ef4a961a60",
"name": "Sticky Note \u2014 Workflow Overview1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2528,
-5168
],
"parameters": {
"width": 468,
"height": 672,
"content": "# \ud83c\udfe2 HR Onboarding Automation\n## Workflow 1 \u2014 Employee Invite Sender\n\n**What this workflow does:**\nWhen HR submits a new employee form, this workflow:\n1. Validates the submitted data\n2. Saves employee record to Google Sheets\n3. Maps department \u2192 Slack channels\n4. Sends a welcome email with Slack invite link\n5. Notifies the manager on Slack\n6. Updates employee status in the sheet\n\n**Trigger:** POST webhook from HR dashboard/form\n**Required fields:** full_name, email, department, role, manager_email, start_date\n\n**Tech Stack:**\n- n8n (automation engine)\n- Google Sheets (employee database)\n- Gmail (welcome email)\n- Slack (manager notification)"
},
"typeVersion": 1
},
{
"id": "e6d7a04b-abaa-4b35-aac3-a681eb775409",
"name": "Sticky Note \u2014 Webhook1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2304,
-4496
],
"parameters": {
"color": 6,
"width": 344,
"height": 668,
"content": "## \ud83d\udce5 Step 1 \u2014 Webhook Trigger\n\nThis node listens for POST requests from the HR form/dashboard.\n\n**Endpoint:**\n`POST /webhook/onboard-employee`\n\n**Expected JSON Body:**\n```json\n{\n \"full_name\": \"Ali Raza\",\n \"email\": \"ali@company.com\",\n \"department\": \"Engineering\",\n \"role\": \"Backend Developer\",\n \"manager_email\": \"mgr@company.com\",\n \"start_date\": \"2026-07-15\"\n}\n```\n\n\u26a0\ufe0f Use `/webhook-test/` URL while testing.\nUse `/webhook/` URL in production (workflow must be Active)."
},
"typeVersion": 1
},
{
"id": "0a769790-d8ba-4bfc-a6e5-071e485b2908",
"name": "Sticky Note \u2014 Validation1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3040,
-4928
],
"parameters": {
"color": 6,
"width": 320,
"height": 448,
"content": "## \u2705 Step 2 \u2014 Validation\n\nChecks that these 3 fields are not empty:\n- `full_name`\n- `email`\n- `department`\n\n**TRUE branch \u2192** Continue onboarding\n**FALSE branch \u2192** Return 400 error response\n\nNote: Fields come from `$json.body.*` because n8n wraps webhook payloads in a `body` object."
},
"typeVersion": 1
},
{
"id": "d259b0c1-e6c5-43ea-861d-491775248a79",
"name": "Sticky Note \u2014 Google Sheets Save1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3392,
-4928
],
"parameters": {
"color": 4,
"width": 356,
"height": 484,
"content": "## \ud83d\udcbe Step 3 \u2014 Save to Google Sheets\n\nAppends a new row to the **Sheet1** tab.\n\n**Columns written:**\nfull_name, email, department, role, manager_email, start_date\n\n**Auto-filled later:**\n- `status` \u2192 updated by this workflow + WF2\n- `slack_invited_at` \u2192 timestamp when invite sent\n- `slack_user_id` \u2192 filled when employee joins Slack\n\n\ud83d\udccc Sheet ID: `1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo`"
},
"typeVersion": 1
},
{
"id": "5e79d7e5-395f-41a3-9e5f-e4c81caa6244",
"name": "Sticky Note \u2014 Channel Mapping1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3792,
-4928
],
"parameters": {
"color": 4,
"width": 392,
"height": 520,
"content": "## \ud83d\uddc2\ufe0f Step 4 \u2014 Department \u2192 Channel Mapping\n\nMaps each department to relevant Slack channels.\n\n**Current Mapping:**\n- Engineering \u2192 all-testn8n, new-channel\n- Sales \u2192 all-testn8n, social\n- Marketing \u2192 all-testn8n, social\n- HR \u2192 all-testn8n, new-channel\n- Design \u2192 all-testn8n, social\n\nAlso attaches the static **Slack Workspace Invite Link**.\n\n\u26a0\ufe0f Update `SLACK_INVITE_LINK` with a fresh link from:\nSlack \u2192 Workspace name \u2192 Invite people \u2192 Get invite link"
},
"typeVersion": 1
},
{
"id": "81686501-347b-42d9-9d26-a85df2329785",
"name": "Sticky Note \u2014 Welcome Email1",
"type": "n8n-nodes-base.stickyNote",
"position": [
4208,
-4928
],
"parameters": {
"color": 3,
"width": 336,
"height": 580,
"content": "## \ud83d\udce7 Step 5 \u2014 Welcome Email\n\nSends a welcome email to the new employee.\n\n**Contains:**\n- Personalized greeting with name, role, department\n- Start date\n- Slack workspace invite link (static link)\n- Instructions to click and join\n\n**Gmail credential required.**\n\n\u26a0\ufe0f Non-Enterprise Slack limitation:\nWe cannot auto-create Slack accounts via API.\nEmployee must click the invite link themselves.\nWorkflow 2 handles the rest once they join."
},
"typeVersion": 1
},
{
"id": "ff108019-87bc-42b7-a705-d40049994f1d",
"name": "Sticky Note \u2014 Manager Notify1",
"type": "n8n-nodes-base.stickyNote",
"position": [
4576,
-4928
],
"parameters": {
"color": 3,
"width": 336,
"height": 468,
"content": "## \ud83d\udd14 Step 6 \u2014 Notify Manager\n\nSends a Slack DM to the employee's manager.\n\n**Message includes:**\n- Employee name, department, role\n- Start date\n- Channels they'll be added to\n- Confirmation that invite email was sent\n\n**Slack OAuth2 credential required.**\n\nCurrently set to user ID `U0BDTGNCMJQ` for testing.\nIn production: resolve manager's Slack user ID dynamically from their email."
},
"typeVersion": 1
},
{
"id": "176bc57a-9041-43b6-b29a-34219bcc2083",
"name": "Sticky Note \u2014 Status Update1",
"type": "n8n-nodes-base.stickyNote",
"position": [
4944,
-4928
],
"parameters": {
"color": 4,
"width": 336,
"height": 432,
"content": "## \ud83d\udcdd Step 7 \u2014 Update Sheet Status\n\nUpdates the employee row in Google Sheets:\n- `status` \u2192 \"Invite Sent\"\n- `slack_invited_at` \u2192 current timestamp\n\nMatches row by `email` column (must be unique).\n\nHR can see in real-time:\n- **Invite Sent** = email sent, waiting to join\n- **Joined** = added to channels \u2713 (set by WF2)"
},
"typeVersion": 1
},
{
"id": "e433099b-615d-4446-84c4-e59643211ccc",
"name": "Sticky Note \u2014 Setup Checklist1",
"type": "n8n-nodes-base.stickyNote",
"position": [
5328,
-4928
],
"parameters": {
"color": 2,
"width": 436,
"height": 712,
"content": "## \u2699\ufe0f Setup Checklist\n\n**Before going live, make sure:**\n\n\u2705 Google Sheets has columns:\nfull_name, email, department, role, manager_email, start_date, status, slack_invited_at, slack_user_id\n\n\u2705 Slack App has scopes:\nusers:read, users:read.email, channels:read, channels:manage, chat:write\n\n\u2705 Slack App \u2192 Event Subscriptions \u2192 team_join subscribed\n\n\u2705 Workflow 2 is **Active** (toggle ON in n8n)\n\n\u2705 Bot invited to all target channels (`/invite @DemoApp`)\n\n\u2705 Static Slack invite link updated in 'Map Department + Attach Invite Link' node\n\n\u2705 Department names match exactly:\nEngineering, Sales, Marketing, HR, Design"
},
"typeVersion": 1
},
{
"id": "75c34ff8-a3bb-462b-a62e-58f763990ac1",
"name": "Webhook - New Employee Form1",
"type": "n8n-nodes-base.webhook",
"notes": "POST /webhook/onboard-employee \u2014 HR form trigger",
"position": [
2880,
-4192
],
"parameters": {
"path": "onboard-employee",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "83f307fa-3ee1-4b87-8449-040c9c419ce8",
"name": "Validate Required Fields1",
"type": "n8n-nodes-base.if",
"position": [
3104,
-4192
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-001",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.full_name }}",
"rightValue": ""
},
{
"id": "cond-002",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.email }}",
"rightValue": ""
},
{
"id": "cond-003",
"operator": {
"type": "string",
"operation": "notEmpty"
},
"leftValue": "={{ $json.body.department }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2
},
{
"id": "1e110181-6850-449d-82fc-f01b0d0d5f0a",
"name": "Respond Validation Error1",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
3328,
-4096
],
"parameters": {
"options": {
"responseCode": 400
},
"respondWith": "json",
"responseBody": "={{ { \"success\": false, \"message\": \"Missing required fields: full_name, email, or department\" } }}"
},
"typeVersion": 1.2
},
{
"id": "24067974-454f-4615-915c-8b72c6290430",
"name": "Save Employee to Google Sheet1",
"type": "n8n-nodes-base.googleSheets",
"position": [
3328,
-4288
],
"parameters": {
"columns": {
"value": {
"role": "={{ $json.body.role }}",
"email": "={{ $json.body.email }}",
"full_name": "={{ $json.body.full_name }}",
"department": "={{ $json.body.department }}",
"start_date": "={{ $json.body.start_date }}",
"manager_email": "={{ $json.body.manager_email }}"
},
"schema": [
{
"id": "full_name",
"type": "string",
"display": true,
"required": false,
"displayName": "full_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "department",
"type": "string",
"display": true,
"required": false,
"displayName": "department",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "role",
"type": "string",
"display": true,
"required": false,
"displayName": "role",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "manager_email",
"type": "string",
"display": true,
"required": false,
"displayName": "manager_email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "start_date",
"type": "string",
"display": true,
"required": false,
"displayName": "start_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_invited_at",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "slack_invited_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_user_id",
"type": "string",
"display": true,
"removed": true,
"required": false,
"displayName": "slack_user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "d0c0f242-cb56-4112-8812-fb8b973e6598",
"name": "Map Department + Attach Invite Link1",
"type": "n8n-nodes-base.code",
"position": [
3552,
-4288
],
"parameters": {
"jsCode": "const departmentChannelMap = {\n 'Engineering': ['all-testn8n', 'new-channel'],\n 'Sales': ['all-testn8n', 'social'],\n 'Marketing': ['all-testn8n', 'social'],\n 'HR': ['all-testn8n', 'new-channel'],\n 'Design': ['all-testn8n', 'social']\n};\n\nconst dept = $input.first().json.department;\nconst channels = departmentChannelMap[dept] || ['all-testn8n'];\n\nconst SLACK_INVITE_LINK = 'https://join.slack.com/t/testn8n-6i17414/shared_invite/zt-429tad5xx-6dmoOUMbNCJ_TmQpYUrUzA';\n\nreturn [{\n json: {\n ...$input.first().json,\n target_channels: channels,\n slack_invite_link: SLACK_INVITE_LINK\n }\n}];"
},
"typeVersion": 2
},
{
"id": "1f8db531-7af7-4f30-b897-63473ba902ee",
"name": "Send Welcome Email with Slack Invite Link1",
"type": "n8n-nodes-base.gmail",
"position": [
3776,
-4288
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=<h2>Welcome aboard, {{ $json.full_name }}!</h2><p>We're thrilled to have you join us as <strong>{{ $json.role }}</strong> in the <strong>{{ $json.department }}</strong> team, starting <strong>{{ $json.start_date }}</strong>.</p><p>Step 1: Click the link below to join our Slack workspace:</p><p><a href=\"{{ $json.slack_invite_link }}\">{{ $json.slack_invite_link }}</a></p><p>Once you join, you'll automatically be added to your team's channels and our bot will say hi!</p><p>See you soon!</p>",
"options": {},
"subject": "=Welcome to the team, {{ $json.full_name }}! \ud83c\udf89 Join us on Slack"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "48db0793-cf8f-4650-b147-78f6c1d42c0d",
"name": "Notify Manager on Slack1",
"type": "n8n-nodes-base.slack",
"position": [
4000,
-4288
],
"parameters": {
"text": "=:bust_in_silhouette: Heads up! *{{ $('Map Department + Attach Invite Link1').item.json.full_name }}* has been sent a Slack invite link.\n\nDepartment: {{ $('Map Department + Attach Invite Link1').item.json.department }}\nRole: {{ $('Map Department + Attach Invite Link1').item.json.role }}\nStart Date: {{ $('Map Department + Attach Invite Link1').item.json.start_date }}\nManager: {{ $('Map Department + Attach Invite Link1').item.json.manager_email }}\n\nThey'll be auto-added to: {{ $('Map Department + Attach Invite Link1').item.json.target_channels.join(', ') }} once they join the workspace.",
"user": {
"__rl": true,
"mode": "list",
"value": "U0BDTGNCMJQ",
"cachedResultName": "umartkd989"
},
"select": "user",
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "3a8d3a62-a318-41b1-9848-e9d36a12e8a4",
"name": "Update Status: Invite Sent1",
"type": "n8n-nodes-base.googleSheets",
"position": [
4224,
-4288
],
"parameters": {
"columns": {
"value": {
"email": "={{ $('Map Department + Attach Invite Link1').item.json.email }}",
"status": "Invite Sent",
"slack_invited_at": "={{ $now.toISO() }}"
},
"schema": [
{
"id": "email",
"type": "string",
"display": true,
"required": false,
"displayName": "email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_invited_at",
"type": "string",
"display": true,
"required": false,
"displayName": "slack_invited_at",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_user_id",
"type": "string",
"display": true,
"required": false,
"displayName": "slack_user_id",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"email"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1kGaxbKg-6SZTWqWFXL2GZz0WvUaC8PTsOpZ8tySKpLo/edit?usp=drivesdk",
"cachedResultName": "employ"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "a0c74732-1a6e-4545-b561-005d4695d4a6",
"name": "Respond Success1",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
4448,
-4288
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"success\": true, \"message\": \"Onboarding invite sent\", \"employee\": $json.full_name } }}"
},
"typeVersion": 1.2
},
{
"id": "7c8b381d-70ff-4600-a0e3-39182c7d7080",
"name": "Sticky Note \u2014 WF2 Overview1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2112,
-3664
],
"parameters": {
"width": 488,
"height": 680,
"content": "# \ud83d\udd17 Workflow 2 \u2014 Slack Team Join Listener\n\n**What this workflow does:**\nListens for Slack's `team_join` event (fired when anyone joins the workspace). When triggered:\n1. Verifies it's a real event (not URL verification challenge)\n2. Extracts new user's email + Slack user ID\n3. Looks up their record in Google Sheets\n4. Maps department to channels\n5. Adds user to each channel one by one\n6. Sends a welcome DM on Slack\n7. Updates sheet status to \"Joined\"\n\n**Setup Required:**\n- Slack App \u2192 Event Subscriptions \u2192 Enable\n- Request URL: `https://umarimran99999.app.n8n.cloud/webhook/slack-team-join`\n- Subscribe to bot event: `team_join`\n- This workflow must be **Active** (toggle ON)\n\n**Required Slack Scopes:**\n`users:read`, `users:read.email`, `channels:read`, `channels:manage`, `chat:write`"
},
"typeVersion": 1
},
{
"id": "3a20c7ce-fb08-4acb-8c65-721cbec6d538",
"name": "Sticky Note \u2014 Challenge1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2832,
-3840
],
"parameters": {
"color": 6,
"width": 524,
"height": 456,
"content": "## \ud83e\udd1d URL Verification Challenge\n\nWhen you first save the Request URL in Slack's Event Subscriptions, Slack sends a one-time verification request:\n```json\n{ \"type\": \"url_verification\", \"challenge\": \"abc123\" }\n```\n\nThis IF node checks for that.\n\n**TRUE \u2192** Echo back the challenge (Slack marks URL as Verified \u2713)\n**FALSE \u2192** It's a real event, continue processing\n\n\u26a0\ufe0f This workflow must be **Active** and use the production `/webhook/` URL for Slack verification to work."
},
"typeVersion": 1
},
{
"id": "4
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.
gmailOAuth2googleSheetsOAuth2ApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automates HR onboarding by capturing new hires via a webhook, saving them to Google Sheets, emailing a Slack invite via Gmail, and notifying managers in Slack, then listening for Slack team_join events to add new hires to department channels and update onboarding…
Source: https://n8n.io/workflows/16925/ — 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.
Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups,
This workflow receives Stripe payment webhooks, looks up the customer’s order in Google Sheets, generates personalized HTML content with OpenAI, converts it to a PDF using PDFShift, then queues the re
Streamline and standardize your entire client onboarding process with a single end-to-end automation. 🚀📋 This workflow captures detailed client intake data via webhook, automatically creates a fully s
Human Approval AI Response. Uses httpRequest, slack, gmail, googleSheets. Webhook trigger; 20 nodes.
This workflow receives an HR offboarding webhook, validates and enriches the employee record, suspends the user in Google Workspace, deactivates the user in Slack, looks up the matching HubSpot contac