This workflow corresponds to n8n.io template #15690 β 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": "7KHVOYiGL4lvvi2K",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Autonomous IT Asset Recovery Agent Q \u2014 Google Sheets Edition",
"tags": [],
"nodes": [
{
"id": "1bb904c6-4c13-4c7e-b6be-34d32cb10d8e",
"name": "\ud83d\udccb Trigger \u2014 Watch Employees Sheet",
"type": "n8n-nodes-base.googleSheetsTrigger",
"notes": "Polls the Employees sheet for new/updated rows. Replace YOUR_GOOGLE_SHEET_ID_HERE with your actual Sheet ID from the URL.",
"position": [
-1872,
2752
],
"parameters": {
"event": "rowAdded",
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0/edit?usp=drivesdk",
"cachedResultName": "IT Allocation"
}
},
"credentials": {
"googleSheetsTriggerOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "c1e2abf9-a6ea-4464-ab18-8d74d95b37e5",
"name": "\ud83d\udd0d Filter \u2014 Resigned or Terminated Only",
"type": "n8n-nodes-base.code",
"position": [
-1648,
2752
],
"parameters": {
"jsCode": "// ============================================================\n// FILTER: Only process rows where status = Resigned or Terminated\n// and email_sent = No (avoid re-processing)\n// ============================================================\nconst rows = $input.all();\n\nconst eligible = rows.filter(item => {\n const s = (item.json.status || '').trim();\n const sent = (item.json.email_sent || 'No').trim();\n return (s === 'Resigned' || s === 'Terminated') && sent === 'No';\n});\n\nif (eligible.length === 0) {\n return [{ json: { __skip: true, reason: 'No eligible rows found' } }];\n}\n\nreturn eligible.map(item => ({ json: item.json }));"
},
"typeVersion": 2
},
{
"id": "be2e2a39-76e2-4bc9-8b8e-282ed8a735df",
"name": "\u2753 Has Eligible Rows?",
"type": "n8n-nodes-base.if",
"position": [
-1440,
2752
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-skip",
"operator": {
"type": "boolean",
"operation": "notEquals"
},
"leftValue": "={{ $json.__skip }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "6ad7da48-dc8f-4937-8ac4-a5d87a3e3a27",
"name": "\ud83d\uddc4\ufe0f Google Sheets \u2014 Read Employee Assets",
"type": "n8n-nodes-base.googleSheets",
"notes": "Reads all rows from Assets sheet where employee_id matches and status = Allocated",
"position": [
-1248,
2592
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": 358936068,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0/edit#gid=358936068",
"cachedResultName": "Sheet2"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1fiSPjKE-ELzgTJdNyfE1t8z5_Z7JeE6bBUUTcCjkBH0/edit?usp=drivesdk",
"cachedResultName": "IT Allocation"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "1f48a54b-24c6-42bc-b868-19b5a6252287",
"name": "\ud83d\udd17 Merge Employee Profile & Asset List",
"type": "n8n-nodes-base.code",
"position": [
-1024,
2592
],
"parameters": {
"jsCode": "// ============================================================\n// MERGE: Combine employee row with their assets from Sheets\n// $('Filter: Resigned or Terminated Only') = employee data\n// $input = asset rows just read from Google Sheets\n// ============================================================\n\n// Get the employee data from the filter node (passed through IF)\nconst employeeItem = $('IF: Has Eligible Rows?').item;\nconst employee = employeeItem.json;\n\n// All asset rows returned from Google Sheets for this employee\nconst assetItems = $input.all();\nconst assets = assetItems.map(a => ({\n asset_id: a.json.asset_id || '',\n employee_id: a.json.employee_id || '',\n asset_type: a.json.asset_type || '',\n brand_model: a.json.brand_model || '',\n serial_number: a.json.serial_number || '',\n asset_value_inr: Number(a.json.asset_value_inr) || 0,\n status: a.json.status || 'Allocated',\n row_number: Number(a.json.row_number) || 0\n}));\n\nconst totalValue = assets.reduce((sum, a) => sum + a.asset_value_inr, 0);\n\nreturn [{\n json: {\n // \u2500\u2500 Employee fields (column names must match your Google Sheet header row exactly)\n employee_id: employee.employee_id || '',\n name: employee.name || '',\n email: employee.email || '',\n department: employee.department || '',\n status: employee.status || '',\n notice_period_days: Number(employee.notice_period_days) || 0,\n last_working_day: employee.last_working_day || '',\n manager_email: employee.manager_email || '',\n manager_name: employee.manager_name || '',\n employee_row_number: Number(employee.row_number) || 0,\n // \u2500\u2500 Aggregated assets\n assets,\n total_asset_value_inr: totalValue,\n asset_count: assets.length\n }\n}];"
},
"typeVersion": 2
},
{
"id": "f6aa5fb0-d596-4ac6-a172-f2f5679f3f4a",
"name": "\ud83d\udcdd Google Sheets \u2014 Update Employee Return Status",
"type": "n8n-nodes-base.googleSheets",
"notes": "Writes email_sent=Yes, return_deadline, and urgency back to the Employees sheet row",
"position": [
352,
2352
],
"parameters": {
"columns": {
"value": {
"urgency": "={{ $json.urgency }}",
"email_sent": "Yes",
"row_number": "={{ $json.employee_row_number }}",
"return_deadline": "={{ $json.return_deadline }}"
},
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
]
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Employees"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID_HERE"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "43bb9261-ef74-4041-acd4-353dbf6f2586",
"name": "\u2699\ufe0f Split \u2014 One Item Per Asset",
"type": "n8n-nodes-base.code",
"position": [
576,
2352
],
"parameters": {
"jsCode": "// ============================================================\n// Update each asset row in Google Sheets: status = Return Email Sent\n// Returns one item per asset so the Sheets node loops over them\n// ============================================================\nconst item = $input.item.json;\n\nreturn item.assets.map(asset => ({\n json: {\n ...item,\n current_asset: asset\n }\n}));"
},
"typeVersion": 2
},
{
"id": "9f3299e6-af9d-4951-8744-bdd49148a5cf",
"name": "\u2705 Google Sheets \u2014 Mark Asset Email Sent",
"type": "n8n-nodes-base.googleSheets",
"position": [
816,
2352
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Assets"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID_HERE"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "547178fc-d84c-4ea4-aa55-f6d0e28d5f07",
"name": "\u26a0\ufe0f Split \u2014 Isolate Overdue Assets",
"type": "n8n-nodes-base.code",
"position": [
400,
2640
],
"parameters": {
"jsCode": "// Split overdue assets so we update each row individually\nconst item = $input.item.json;\nreturn item.overdue_assets.map(asset => ({\n json: { ...item, current_asset: asset }\n}));"
},
"typeVersion": 2
},
{
"id": "02793764-89e6-4b7e-af04-1d5e3ed79881",
"name": "\ud83d\udea9 Google Sheets \u2014 Mark Assets as Missing",
"type": "n8n-nodes-base.googleSheets",
"position": [
624,
2640
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Assets"
},
"documentId": {
"__rl": true,
"mode": "id",
"value": "YOUR_GOOGLE_SHEET_ID_HERE"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "bc206071-4a1b-469e-886a-6b97f8264a68",
"name": "\ud83d\udcd2 Log \u2014 No Action Needed",
"type": "n8n-nodes-base.code",
"position": [
400,
2928
],
"parameters": {
"jsCode": "const item = $input.item.json;\nreturn [{\n json: {\n log: `No action needed for ${item.name || 'unknown'}. Reason: ${item.reason || 'Checklist invalid, assets returned, or not overdue.'}`\n }\n}];"
},
"typeVersion": 2
},
{
"id": "ed82f2c1-8535-49d4-ab76-f85a0d9900a0",
"name": "\ud83e\udde0 MCTS \u2014 Plan Asset Return Timeline",
"type": "n8n-nodes-base.code",
"position": [
-800,
2592
],
"parameters": {
"jsCode": "// ============================================================\n// MCTS: Monte Carlo Tree Search \u2014 Return Timeline Planner\n// Plans optimal return strategy based on notice period\n// ============================================================\nconst item = $input.item.json;\n\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\nconst lastDay = new Date(item.last_working_day);\n\nlet return_strategy, return_deadline, reminder_day, urgency;\n\nif (item.status === 'Terminated' || item.notice_period_days === 0) {\n return_strategy = 'IMMEDIATE';\n return_deadline = new Date(today);\n return_deadline.setDate(today.getDate() + 1);\n reminder_day = new Date(today);\n urgency = 'CRITICAL';\n} else if (item.notice_period_days <= 14) {\n return_strategy = 'SHORT_NOTICE';\n return_deadline = new Date(lastDay);\n return_deadline.setDate(lastDay.getDate() - 1);\n reminder_day = new Date(lastDay);\n reminder_day.setDate(lastDay.getDate() - 3);\n urgency = 'HIGH';\n} else {\n // Standard 30-day notice\n return_strategy = 'STANDARD';\n return_deadline = new Date(lastDay);\n return_deadline.setDate(lastDay.getDate() - 2);\n reminder_day = new Date(lastDay);\n reminder_day.setDate(lastDay.getDate() - 5);\n urgency = 'NORMAL';\n}\n\nconst mcts_recovery_score = Math.round(\n item.total_asset_value_inr *\n (urgency === 'CRITICAL' ? 1.0 : urgency === 'HIGH' ? 0.85 : 0.70)\n);\n\nconst fmtDate = d => d.toISOString().split('T')[0];\n\nreturn [{\n json: {\n ...item,\n return_strategy,\n return_deadline: fmtDate(return_deadline),\n reminder_day: fmtDate(reminder_day),\n urgency,\n mcts_recovery_score,\n days_until_deadline: Math.ceil((return_deadline - today) / 86400000)\n }\n}];"
},
"typeVersion": 2
},
{
"id": "d9068823-da33-467f-925c-96f8ec9dc5a8",
"name": "\u2705 Self-Critique \u2014 Validate Return Checklist",
"type": "n8n-nodes-base.code",
"position": [
-592,
2592
],
"parameters": {
"jsCode": "// ============================================================\n// SELF-CRITIQUE: Validates checklist completeness\n// Every asset must have serial_number, asset_value_inr, asset_type\n// ============================================================\nconst item = $input.item.json;\n\nconst critiques = [];\nlet checklist_valid = true;\n\nif (!item.assets || item.assets.length === 0) {\n critiques.push('FAIL: No assets found for this employee in the Assets sheet.');\n checklist_valid = false;\n}\n\n(item.assets || []).forEach((asset, idx) => {\n if (!asset.serial_number || asset.serial_number.trim() === '') {\n critiques.push(`WARN: Asset #${idx + 1} (${asset.asset_type}) missing serial number.`);\n checklist_valid = false;\n }\n if (!asset.asset_value_inr || asset.asset_value_inr <= 0) {\n critiques.push(`WARN: Asset #${idx + 1} (${asset.asset_type}) has no value recorded.`);\n checklist_valid = false;\n }\n if (!asset.asset_type || asset.asset_type.trim() === '') {\n critiques.push(`FAIL: Asset #${idx + 1} missing asset_type.`);\n checklist_valid = false;\n }\n});\n\nif (checklist_valid) {\n critiques.push('PASS: All assets validated. Checklist complete.');\n}\n\nconst checklist_lines = (item.assets || []).map((a, i) =>\n `${i + 1}. ${a.asset_type} \u2014 ${a.brand_model} (S/N: ${a.serial_number}) \u2014 \u20b9${Number(a.asset_value_inr).toLocaleString('en-IN')}`\n).join('\\n');\n\nreturn [{\n json: {\n ...item,\n checklist_valid,\n self_critique_notes: critiques,\n checklist_lines\n }\n}];"
},
"typeVersion": 2
},
{
"id": "c7126429-2398-4e64-a069-6206ffe13da8",
"name": "\u2753 Checklist Valid?",
"type": "n8n-nodes-base.if",
"position": [
-368,
2592
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-valid",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.checklist_valid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "88d476b4-d4de-49f3-b796-4c2af36b4b58",
"name": "\u270d\ufe0f Build Return Instructions Email Body",
"type": "n8n-nodes-base.code",
"position": [
-80,
2352
],
"parameters": {
"jsCode": "// ============================================================\n// Build Gmail Email Body \u2014 personalised per employee\n// ============================================================\nconst item = $input.item.json;\n\nconst firstName = item.name.split(' ')[0];\nconst subject = `[ACTION REQUIRED] IT Asset Return \u2014 ${item.name} | Deadline: ${item.return_deadline}`;\n\nconst body = `Dear ${firstName},\n\nThis is an official communication from the IT Asset Management team at Acme Corp.\n\nAs per HR records, your employment status has been updated to \"${item.status}\" effective ${item.last_working_day}.\n\nPlease arrange to return the following company-issued assets by ${item.return_deadline}:\n\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nITEMISED ASSET RETURN CHECKLIST\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n${item.checklist_lines}\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\nTotal Asset Value: \u20b9${Number(item.total_asset_value_inr).toLocaleString('en-IN')}\n\nRETURN INSTRUCTIONS:\n\u2022 Drop off assets at IT Helpdesk, 3rd Floor, Acme Corp HQ, Hyderabad\n\u2022 Office hours: Mon\u2013Fri, 9 AM \u2013 6 PM\n\u2022 Bring this email as reference\n\u2022 For courier returns, contact user@example.com\n\nDEADLINE: ${item.return_deadline}\nFailure to return assets by this date will result in escalation to the Legal team and deduction from your Full & Final Settlement.\n\nIf you have already returned any items, please reply to this email with confirmation.\n\nRegards,\nIT Asset Management Team\nAcme Corp | user@example.com`;\n\nreturn [{\n json: {\n ...item,\n email_subject: subject,\n email_body: body\n }\n}];"
},
"typeVersion": 2
},
{
"id": "16491ba6-2b21-48b2-ac4a-7142e5595df6",
"name": "\ud83d\udce7 Gmail \u2014 Send Return Instructions to Employee",
"type": "n8n-nodes-base.gmail",
"position": [
144,
2352
],
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "={{ $json.email_body }}",
"options": {
"ccList": "={{ $json.manager_email }}"
},
"subject": "={{ $json.email_subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "4b16c219-6655-4e73-b4d8-9c8848c4dd71",
"name": "\u23f0 Check Asset Return Deadline",
"type": "n8n-nodes-base.code",
"position": [
-144,
2688
],
"parameters": {
"jsCode": "// ============================================================\n// DEADLINE CHECK: Has return_deadline passed today?\n// Also checks for Terminated employees (always immediate)\n// ============================================================\nconst item = $input.item.json;\n\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\nconst deadline = new Date(item.return_deadline);\n\nconst isOverdue = today >= deadline;\n\n// Assets still in 'Return Email Sent' or 'Allocated' state = not yet returned\nconst overdue_assets = item.assets.filter(a =>\n a.status === 'Allocated' || a.status === 'Return Email Sent'\n);\n\nreturn [{\n json: {\n ...item,\n is_overdue: isOverdue,\n overdue_assets,\n missing_count: overdue_assets.length,\n missing_value_inr: overdue_assets.reduce((s, a) => s + a.asset_value_inr, 0)\n }\n}];"
},
"typeVersion": 2
},
{
"id": "cffc11ec-67f5-4f1c-b76f-d89d4f134a2b",
"name": "\u2753 Assets Overdue?",
"type": "n8n-nodes-base.if",
"position": [
80,
2688
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-overdue",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.is_overdue }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "ad1894ad-a6e1-43bf-854a-f88967f8f031",
"name": "\ud83d\udd04 DPO \u2014 Build Escalation Message",
"type": "n8n-nodes-base.code",
"position": [
864,
2640
],
"parameters": {
"jsCode": "// ============================================================\n// DPO: Direct Preference Optimization \u2014 Escalation Builder\n// Scores severity, selects escalation channel and tone\n// ============================================================\nconst item = $input.item.json;\n\nconst missingList = item.overdue_assets.map((a, i) =>\n `\u2022 ${a.asset_type} | ${a.brand_model} | S/N: ${a.serial_number} | \u20b9${Number(a.asset_value_inr).toLocaleString('en-IN')}`\n).join('\\n');\n\nconst totalMissingValue = item.missing_value_inr;\nconst escalate_to_legal = totalMissingValue >= 50000;\n\nconst slackMessage = `:rotating_light: *IT ASSET RECOVERY ESCALATION*\\n\\n*Employee:* ${item.name} (${item.employee_id})\\n*Status:* ${item.status}\\n*Department:* ${item.department}\\n*Last Working Day:* ${item.last_working_day}\\n*Return Deadline Passed:* ${item.return_deadline}\\n\\n*MISSING ASSETS (${item.missing_count} items):*\\n${missingList}\\n\\n*Total At-Risk Value:* \u20b9${Number(totalMissingValue).toLocaleString('en-IN')}\\n*MCTS Recovery Score:* \u20b9${Number(item.mcts_recovery_score).toLocaleString('en-IN')}\\n\\n${escalate_to_legal ? ':scales: *Legal escalation triggered \u2014 Full & Final Settlement hold recommended.*' : ':warning: IT Manager follow-up required.'}\\n\\n*Action Required:* Contact employee immediately or initiate F&F deduction.\\nHR: user@example.com | IT: user@example.com`;\n\nreturn [{\n json: {\n ...item,\n slack_escalation_message: slackMessage,\n escalate_to_legal,\n dpo_preference: escalate_to_legal ? 'LEGAL_ESCALATION' : 'IT_MANAGER_ONLY'\n }\n}];"
},
"typeVersion": 2
},
{
"id": "9088f5bd-f2d6-4741-ae81-5285801d3f80",
"name": "\ud83d\udd14 Slack \u2014 Alert IT Manager",
"type": "n8n-nodes-base.slack",
"notes": "Replace C_IT_ALERTS with your actual Slack channel ID",
"position": [
1120,
2528
],
"parameters": {
"text": "={{ $json.slack_escalation_message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "C_IT_ALERTS"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "27af90dc-2756-46d9-b46c-9dde21020d8e",
"name": "\u2753 Escalate to Legal?",
"type": "n8n-nodes-base.if",
"position": [
1088,
2720
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "cond-legal",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.escalate_to_legal }}",
"rightValue": true
}
]
}
},
"typeVersion": 2
},
{
"id": "01862aa3-9a35-420a-ad16-8bdd8a61cd62",
"name": "\ud83d\udea8 Slack \u2014 Alert Legal Team",
"type": "n8n-nodes-base.slack",
"notes": "Replace C_LEGAL_ESCALATIONS with your actual Slack channel ID",
"position": [
1360,
2656
],
"parameters": {
"text": "={{ $json.slack_escalation_message }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "C_LEGAL_ESCALATIONS"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "37b567ed-a801-4c41-b95f-54904094cc7d",
"name": "Sticky Note \u2014 Phase 1: Offboarding Detection",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1904,
2528
],
"parameters": {
"color": 3,
"width": 490,
"height": 185,
"content": "## \ud83d\udce5 Phase 1: Offboarding Detection\nWatches the Employees Google Sheet for changes.\nFilters rows to only process employees with status **Resigned** or **Terminated**.\n- \u2705 **Eligible rows found** \u2192 proceed to asset lookup\n- \u274c **No eligible rows** \u2192 log no action needed and stop"
},
"typeVersion": 1
},
{
"id": "58abe98d-0809-425e-8427-fbc776eb1830",
"name": "Sticky Note \u2014 Phase 2: Asset Lookup & Merge",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1344,
2896
],
"parameters": {
"color": 5,
"width": 470,
"height": 175,
"content": "## \ud83d\uddc4\ufe0f Phase 2: Asset Lookup & Data Merge\nFetches all assets assigned to the departing employee from the **Assets Google Sheet**.\nMerges the employee profile with their full asset list to create a unified recovery record used throughout the rest of the workflow."
},
"typeVersion": 1
},
{
"id": "192ebe33-1ecd-4966-9388-6e22ba53be96",
"name": "Sticky Note \u2014 Phase 3: MCTS Planning & Checklist Validation",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1328,
2320
],
"parameters": {
"color": 4,
"width": 490,
"height": 227,
"content": "## \ud83e\udde0 Phase 3: MCTS Planning & Self-Critique\n**MCTS** generates an optimised asset return timeline based on the employee's last day, asset count, and location.\n\n**Self-Critique** then validates the return checklist against IT policy:\n- \u2705 **Valid** \u2192 build and send return instructions\n- \u274c **Invalid** \u2192 flag and stop before emailing"
},
"typeVersion": 1
},
{
"id": "69767392-35ae-46fd-bd91-ab85a4a83ef5",
"name": "Sticky Note \u2014 Phase 4: Return Instructions & Sheet Update",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
2240
],
"parameters": {
"color": 6,
"width": 510,
"height": 222,
"content": "## \ud83d\udce7 Phase 4: Send Return Instructions & Update Sheets\nBuilds a personalised return instructions email listing all assets to be returned with deadlines.\n- **Gmail** sends the email directly to the departing employee\n- **Google Sheets** updates the employee row with return status\n- Each asset record is split and individually marked as **Email Sent** in the assets sheet"
},
"typeVersion": 1
},
{
"id": "c000f387-a91b-40e3-9dbd-4b9afa725c50",
"name": "Sticky Note \u2014 Phase 5: Deadline Check & Overdue Handling",
"type": "n8n-nodes-base.stickyNote",
"position": [
32,
2128
],
"parameters": {
"color": 7,
"width": 490,
"height": 175,
"content": "## \u23f0 Phase 5: Deadline Check & Overdue Asset Handling\nChecks whether the return deadline has passed for each asset:\n- \u2705 **On time** \u2192 no further action needed\n- \u26a0\ufe0f **Overdue** \u2192 isolate overdue assets, mark them as **Missing** in Google Sheets, then trigger the escalation pipeline"
},
"typeVersion": 1
},
{
"id": "bb2636bd-8e3c-4dab-8fbe-e4147088e559",
"name": "Sticky Note \u2014 Phase 6: Escalation & Legal Alert",
"type": "n8n-nodes-base.stickyNote",
"position": [
1088,
2256
],
"parameters": {
"color": 2,
"width": 490,
"height": 185,
"content": "## \ud83d\udea8 Phase 6: Escalation & Legal Alert\nFor overdue assets, Agent Q escalates via **DPO-style messaging**:\n- **Slack** alerts the IT Manager with asset and employee details\n- Evaluates whether the case warrants **legal escalation** based on asset value and overdue duration\n- \ud83d\udea8 If legal threshold met \u2192 **Slack** alerts the Legal Team for formal follow-up"
},
"typeVersion": 1
},
{
"id": "4b1f3688-aa26-4427-a9d7-fcbda4fb0c6d",
"name": "Sticky Note \u2014 Phase 7: No Action Path",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
2880
],
"parameters": {
"width": 430,
"height": 150,
"content": "## \ud83d\udcd2 Phase 7: No Action Needed\nIf no eligible offboarding rows are detected during the trigger check, the workflow logs a **No Action Needed** entry and exits cleanly \u2014 preventing any unnecessary processing or notifications."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "c14a0648-e059-4f12-ac1c-b99d32249e96",
"connections": {
"\u2753 Assets Overdue?": {
"main": [
[
{
"node": "\u26a0\ufe0f Split \u2014 Isolate Overdue Assets",
"type": "main",
"index": 0
}
],
[
{
"node": "\ud83d\udcd2 Log \u2014 No Action Needed",
"type": "main",
"index": 0
}
]
]
},
"\u2753 Checklist Valid?": {
"main": [
[
{
"node": "\u270d\ufe0f Build Return Instructions Email Body",
"type": "main",
"index": 0
},
{
"node": "\u23f0 Check Asset Return Deadline",
"type": "main",
"index": 0
}
],
[
{
"node": "\ud83d\udcd2 Log \u2014 No Action Needed",
"type": "main",
"index": 0
}
]
]
},
"\u2753 Escalate to Legal?": {
"main": [
[
{
"node": "\ud83d\udea8 Slack \u2014 Alert Legal Team",
"type": "main",
"index": 0
}
]
]
},
"\u2753 Has Eligible Rows?": {
"main": [
[
{
"node": "\ud83d\uddc4\ufe0f Google Sheets \u2014 Read Employee Assets",
"type": "main",
"index": 0
}
],
[
{
"node": "\ud83d\udcd2 Log \u2014 No Action Needed",
"type": "main",
"index": 0
}
]
]
},
"\u23f0 Check Asset Return Deadline": {
"main": [
[
{
"node": "\u2753 Assets Overdue?",
"type": "main",
"index": 0
}
]
]
},
"\u2699\ufe0f Split \u2014 One Item Per Asset": {
"main": [
[
{
"node": "\u2705 Google Sheets \u2014 Mark Asset Email Sent",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udd04 DPO \u2014 Build Escalation Message": {
"main": [
[
{
"node": "\ud83d\udd14 Slack \u2014 Alert IT Manager",
"type": "main",
"index": 0
},
{
"node": "\u2753 Escalate to Legal?",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udccb Trigger \u2014 Watch Employees Sheet": {
"main": [
[
{
"node": "\ud83d\udd0d Filter \u2014 Resigned or Terminated Only",
"type": "main",
"index": 0
}
]
]
},
"\u26a0\ufe0f Split \u2014 Isolate Overdue Assets": {
"main": [
[
{
"node": "\ud83d\udea9 Google Sheets \u2014 Mark Assets as Missing",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udd17 Merge Employee Profile & Asset List": {
"main": [
[
{
"node": "\ud83e\udde0 MCTS \u2014 Plan Asset Return Timeline",
"type": "main",
"index": 0
}
]
]
},
"\ud83e\udde0 MCTS \u2014 Plan Asset Return Timeline": {
"main": [
[
{
"node": "\u2705 Self-Critique \u2014 Validate Return Checklist",
"type": "main",
"index": 0
}
]
]
},
"\u270d\ufe0f Build Return Instructions Email Body": {
"main": [
[
{
"node": "\ud83d\udce7 Gmail \u2014 Send Return Instructions to Employee",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udd0d Filter \u2014 Resigned or Terminated Only": {
"main": [
[
{
"node": "\u2753 Has Eligible Rows?",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udea9 Google Sheets \u2014 Mark Assets as Missing": {
"main": [
[
{
"node": "\ud83d\udd04 DPO \u2014 Build Escalation Message",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\uddc4\ufe0f Google Sheets \u2014 Read Employee Assets": {
"main": [
[
{
"node": "\ud83d\udd17 Merge Employee Profile & Asset List",
"type": "main",
"index": 0
}
]
]
},
"\u2705 Self-Critique \u2014 Validate Return Checklist": {
"main": [
[
{
"node": "\u2753 Checklist Valid?",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udce7 Gmail \u2014 Send Return Instructions to Employee": {
"main": [
[
{
"node": "\ud83d\udcdd Google Sheets \u2014 Update Employee Return Status",
"type": "main",
"index": 0
}
]
]
},
"\ud83d\udcdd Google Sheets \u2014 Update Employee Return Status": {
"main": [
[
{
"node": "\u2699\ufe0f Split \u2014 One Item Per Asset",
"type": "main",
"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.
gmailOAuth2googleSheetsOAuth2ApigoogleSheetsTriggerOAuth2ApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
π Description Automate the entire IT asset recovery and employee offboarding process with this AI-powered n8n workflow. ππ» This automation monitors Google Sheets for resigned or terminated employees, validates assigned company assets, sends personalized return instructions viaβ¦
Source: https://n8n.io/workflows/15690/ β 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.
Automate end-to-end vendor onboarding workflows with an AI-powered autonomous agent built in n8n π€. This workflow uses advanced MCTS (Monte Carlo Tree Search) reasoning to intelligently map procuremen
Automate your entire supplier negotiation process with this AI-driven workflow that intelligently drafts, refines, and sends negotiation emails π§. Using advanced LLM reasoning and multi-angle strategi
Consultants, agencies, freelancers, and project managers who want to ensure proposals, emails, and tasks are followed up on time.
This workflow automatically monitors a Google Sheet for failed trades, analyzes each failure using AI and updates the sheet with a probable root cause, confidence level and actionable next steps. It a
This n8n workflow automates the transition from raw financial trade data to professional client communication. It monitors a Google Sheet for portfolio changes, uses Gemini AI to draft a personalized,