{
  "id": "EEEbK1ShcUtrG40I",
  "name": "Employee Offboarding Compliance & Access Revocation",
  "tags": [
    {
      "id": "2V3HXFbv2wqNGm6s",
      "name": "Dev",
      "createdAt": "2025-06-17T05:42:41.949Z",
      "updatedAt": "2025-06-17T05:42:41.949Z"
    }
  ],
  "nodes": [
    {
      "id": "68b22055-f143-48fd-8757-66c84b9069b7",
      "name": "Overview Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        208,
        320
      ],
      "parameters": {
        "width": 496,
        "height": 896,
        "content": "## Employee Offboarding Compliance & Access Revocation\n\nThis workflow automates the full employee offboarding process from start to finish. When an HR system sends an offboarding webhook, the workflow validates the request, revokes access across key tools, notifies relevant teams, logs every action to a compliance sheet, and sends a final summary alert. It ensures no offboarding step is missed, reducing security risk and compliance gaps.\n\n### How it Works\n\n\t- Receives an offboarding trigger from an HR webhook when an employee is marked as departed\n\t- Validates and parses the employee payload to extract name, email, department, and manager\n\t- Checks if the offboarding date is valid and the record is complete\n\t- Enriches the record with risk metadata and sets revocation deadlines\n\t- Suspends the departing employee account in Google Workspace via Admin API\n\t- Disables the user in Slack and posts a heads-up to the IT channel\n\t- Removes the user from all active Notion workspaces and HubSpot\n\t- Logs every revocation action to a Google Sheet compliance tracker\n\t- Sends a final offboarding summary email to the manager and HR via Gmail\n\t- Posts a Slack digest to the IT ops channel confirming all steps completed\n\n### Setup Steps\n\n\t1. Create a webhook trigger URL in n8n and configure your HR system to POST to it on employee departure\n\t2. Add your Google Workspace Admin API credentials (service account with user management scope)\n\t3. Connect your Slack API credential with users:write and chat:write scopes\n\t4. Add HubSpot App Token credential with contacts write access\n\t5. Connect Notion API credential and set your workspace ID\n\t6. Create a Google Sheet named Offboarding Log with columns: Date, Name, Email, Department, Manager, Actions Taken, Status\n\t7. Add Gmail credential for sending summary emails\n\t8. Set the IT Slack channel ID in the Slack notification nodes"
      },
      "typeVersion": 1
    },
    {
      "id": "99cd5e0c-5beb-4f38-b9e5-aae0a5d51fc6",
      "name": "Section Note 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        720,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 656,
        "height": 896,
        "content": "## Step 1: Receive & Validate Offboarding Request\n\nThis section handles the incoming webhook from the HR system and validates the payload. The parser extracts all key employee fields and the IF node ensures only complete, valid records proceed. Invalid or incomplete payloads are dropped before any action is taken, preventing accidental revocations."
      },
      "typeVersion": 1
    },
    {
      "id": "2081eb31-bc65-425f-8d45-6d91ec69743d",
      "name": "Section Note 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1392,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 896,
        "height": 896,
        "content": "## Step 2: Enrich Record & Revoke Access\n\nOnce validated, the record is enriched with risk level, revocation deadlines, and a unique offboarding ID. The workflow then fires revocations in parallel across Google Workspace (account suspension), Slack (user deactivation), HubSpot (contact status update), and Notion (workspace removal). Each revocation feeds back into a merge node before logging."
      },
      "typeVersion": 1
    },
    {
      "id": "f392a29f-89d6-4231-9894-18abec2c012e",
      "name": "Section Note 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2304,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 768,
        "height": 896,
        "content": "## Step 3: Log, Notify & Close Out\n\nAfter all revocations are confirmed, the workflow logs the full offboarding record to a Google Sheet compliance tracker. A summary email is dispatched to the employee manager and HR, and a final Slack digest is posted to the IT ops channel confirming that all access has been revoked and the offboarding is complete."
      },
      "typeVersion": 1
    },
    {
      "id": "173d51a3-83ee-40b0-8f54-e954c2b11d70",
      "name": "HR Offboarding Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        800,
        880
      ],
      "parameters": {
        "path": "hr/employee-offboarding",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "6e6bd86e-40a3-4beb-b776-9287ea0bd268",
      "name": "Parse Employee Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        992,
        880
      ],
      "parameters": {
        "jsCode": "const body = $input.first().json;\n\nconst email = (body.email || body.work_email || '').toLowerCase().trim();\nconst firstName = body.first_name || body.firstName || '';\nconst lastName = body.last_name || body.lastName || '';\nconst name = body.name || body.full_name || [firstName, lastName].filter(Boolean).join(' ') || 'Unknown';\nconst employeeId = body.employee_id || body.id || '';\nconst department = body.department || body.team || 'Unknown';\nconst managerEmail = (body.manager_email || body.manager || '').toLowerCase().trim();\nconst offboardingDate = body.offboarding_date || body.last_day || new Date().toISOString().split('T')[0];\nconst role = body.role || body.job_title || 'Unknown';\nconst hrEmail = body.hr_email || 'hr@company.com';\n\nif (!email || !name || name === 'Unknown') {\n  return [{ json: { _invalid: true, reason: 'Missing email or name', raw: body } }];\n}\n\nreturn [{\n  json: {\n    _invalid: false,\n    email,\n    name,\n    firstName,\n    lastName,\n    employeeId,\n    department,\n    managerEmail,\n    offboardingDate,\n    role,\n    hrEmail,\n    parsedAt: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "19e9433c-7d0c-43b5-9d4f-640c4374a045",
      "name": "Valid Offboarding Record",
      "type": "n8n-nodes-base.if",
      "position": [
        1216,
        880
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "check-invalid",
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json._invalid }}",
              "rightValue": true
            },
            {
              "id": "check-email",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.email }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "3b36a61e-240a-4300-a288-e409c92a8435",
      "name": "Enrich Offboarding Record",
      "type": "n8n-nodes-base.set",
      "position": [
        1440,
        768
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "enrich-id",
              "name": "offboardingId",
              "type": "string",
              "value": "=OB-{{ $now.toFormat('yyyyMMdd') }}-{{ $json.employeeId || Math.random().toString(36).substring(2,8).toUpperCase() }}"
            },
            {
              "id": "enrich-risk",
              "name": "riskLevel",
              "type": "string",
              "value": "={{ ['Engineering','Finance','Legal','Executive'].includes($json.department) ? 'HIGH' : 'STANDARD' }}"
            },
            {
              "id": "enrich-deadline",
              "name": "revocationDeadline",
              "type": "string",
              "value": "={{ $now.toISO() }}"
            },
            {
              "id": "enrich-log-date",
              "name": "logDate",
              "type": "string",
              "value": "={{ $now.toFormat('yyyy-MM-dd HH:mm:ss') }}"
            },
            {
              "id": "enrich-summary",
              "name": "actionsSummary",
              "type": "string",
              "value": "Google Workspace suspended, Slack deactivated, HubSpot updated, Notion removed"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "d0b6c43c-b4a0-4013-83b5-e9e2834938e4",
      "name": "Suspend Google Workspace Account",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1664,
        688
      ],
      "parameters": {
        "url": "=https://admin.googleapis.com/admin/directory/v1/users/{{ $json.email }}",
        "method": "PUT",
        "options": {},
        "jsonBody": "={ \"suspended\": true }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_GOOGLE_WORKSPACE_ACCESS_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "ccf359d5-3e53-4b69-9384-691a315298a3",
      "name": "Deactivate Slack User",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1664,
        880
      ],
      "parameters": {
        "url": "https://slack.com/api/users.admin.setInactive",
        "method": "POST",
        "options": {},
        "jsonBody": "={ \"email\": \"{{ $('Enrich Offboarding Record').item.json.email }}\" }",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_SLACK_ADMIN_TOKEN"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e3bdb00d-3f19-484e-9794-bc44a06d74de",
      "name": "Find HubSpot Contact",
      "type": "n8n-nodes-base.hubspot",
      "position": [
        1872,
        688
      ],
      "parameters": {
        "limit": 1,
        "operation": "search",
        "authentication": "appToken",
        "filterGroupsUi": {
          "filterGroupsValues": [
            {
              "filtersUi": {
                "filterValues": [
                  {
                    "value": "={{ $('Enrich Offboarding Record').item.json.email }}",
                    "propertyName": "email|string"
                  }
                ]
              }
            }
          ]
        },
        "additionalFields": {
          "properties": [
            "email",
            "firstname",
            "lastname",
            "lifecyclestage"
          ]
        }
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "13e3cd7c-2317-4a17-8afe-5d2ba5738e0e",
      "name": "Log to Notion Offboarding DB",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1872,
        880
      ],
      "parameters": {
        "url": "https://api.notion.com/v1/pages",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"parent\": { \"database_id\": \"YOUR_NOTION_DATABASE_ID\" },\n  \"properties\": {\n    \"Name\": { \"title\": [{ \"text\": { \"content\": \"Offboarding: {{ $('Enrich Offboarding Record').item.json.name }}\" } }] },\n    \"Email\": { \"email\": \"{{ $('Enrich Offboarding Record').item.json.email }}\" },\n    \"Status\": { \"select\": { \"name\": \"Access Revoked\" } },\n    \"Date\": { \"date\": { \"start\": \"{{ $('Enrich Offboarding Record').item.json.offboardingDate }}\" } }\n  }\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_NOTION_API_KEY"
            },
            {
              "name": "Notion-Version",
              "value": "2022-06-28"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "87dbddbc-fd44-43e2-aea1-c693480d29d2",
      "name": "Merge Revocation Results",
      "type": "n8n-nodes-base.merge",
      "position": [
        2144,
        784
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "7192f5b0-1a92-4bca-ad43-d463fa01b926",
      "name": "Log to Compliance Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2416,
        784
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $('Enrich Offboarding Record').item.json.logDate }}",
            "Name": "={{ $('Enrich Offboarding Record').item.json.name }}",
            "Role": "={{ $('Enrich Offboarding Record').item.json.role }}",
            "Email": "={{ $('Enrich Offboarding Record').item.json.email }}",
            "Status": "COMPLETED",
            "Manager": "={{ $('Enrich Offboarding Record').item.json.managerEmail }}",
            "Department": "={{ $('Enrich Offboarding Record').item.json.department }}",
            "Risk Level": "={{ $('Enrich Offboarding Record').item.json.riskLevel }}",
            "Actions Taken": "={{ $('Enrich Offboarding Record').item.json.actionsSummary }}",
            "Offboarding ID": "={{ $('Enrich Offboarding Record').item.json.offboardingId }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Offboarding Log"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "db5b92e6-b767-43e8-9d66-cc32765c906c",
      "name": "Send Offboarding Summary Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2640,
        784
      ],
      "parameters": {
        "sendTo": "={{ $('Enrich Offboarding Record').item.json.managerEmail }},={{ $('Enrich Offboarding Record').item.json.hrEmail }}",
        "message": "=<h2>Employee Offboarding Completed</h2><p>This is an automated confirmation that the offboarding process for the following employee has been completed successfully.</p><table border='1' cellpadding='8' cellspacing='0'><tr><td><strong>Name</strong></td><td>{{ $('Enrich Offboarding Record').item.json.name }}</td></tr><tr><td><strong>Email</strong></td><td>{{ $('Enrich Offboarding Record').item.json.email }}</td></tr><tr><td><strong>Department</strong></td><td>{{ $('Enrich Offboarding Record').item.json.department }}</td></tr><tr><td><strong>Role</strong></td><td>{{ $('Enrich Offboarding Record').item.json.role }}</td></tr><tr><td><strong>Last Day</strong></td><td>{{ $('Enrich Offboarding Record').item.json.offboardingDate }}</td></tr><tr><td><strong>Risk Level</strong></td><td>{{ $('Enrich Offboarding Record').item.json.riskLevel }}</td></tr><tr><td><strong>Offboarding ID</strong></td><td>{{ $('Enrich Offboarding Record').item.json.offboardingId }}</td></tr></table><h3>Actions Completed</h3><ul><li>Google Workspace account suspended</li><li>Slack user deactivated</li><li>HubSpot contact updated</li><li>Notion offboarding record created</li><li>Compliance log entry added</li></ul><p><em>This is an automated message generated by n8n. Please do not reply to this email.</em></p>",
        "options": {},
        "subject": "=Offboarding Complete: {{ $('Enrich Offboarding Record').item.json.name }} ({{ $('Enrich Offboarding Record').item.json.offboardingId }})"
      },
      "typeVersion": 2.1
    },
    {
      "id": "8043d6a6-e407-40d5-b68e-879b2811eddc",
      "name": "Slack IT Ops Digest",
      "type": "n8n-nodes-base.slack",
      "position": [
        2848,
        784
      ],
      "parameters": {
        "text": "=:white_check_mark: *Offboarding Complete* | {{ $('Enrich Offboarding Record').item.json.offboardingId }}\n\n*Employee:* {{ $('Enrich Offboarding Record').item.json.name }}\n*Email:* {{ $('Enrich Offboarding Record').item.json.email }}\n*Department:* {{ $('Enrich Offboarding Record').item.json.department }}\n*Role:* {{ $('Enrich Offboarding Record').item.json.role }}\n*Last Day:* {{ $('Enrich Offboarding Record').item.json.offboardingDate }}\n*Risk Level:* {{ $('Enrich Offboarding Record').item.json.riskLevel }}\n\n*Revocations Confirmed:*\n- :google: Google Workspace - Suspended\n- :slack: Slack - Deactivated\n- :hubspot: HubSpot - Updated\n- :notion: Notion - Record Created\n- :bar_chart: Compliance Sheet - Logged\n\n_All access has been revoked. Offboarding summary emailed to manager and HR._",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_IT_SLACK_CHANNEL_ID"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "3618462c-a476-4562-aeb8-64cc946d0b9b",
      "name": "Alert Invalid Record",
      "type": "n8n-nodes-base.slack",
      "position": [
        1440,
        976
      ],
      "parameters": {
        "text": "=:warning: *Invalid Offboarding Record Received* - payload was missing required fields (email or name). Manual review required.\n\n*Reason:* {{ $json.reason }}\n*Received at:* {{ $now.toISO() }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_IT_SLACK_CHANNEL_ID"
        },
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "typeVersion": 2.2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "b5577069-0e37-44c6-9afa-7ab51797e0ef",
  "connections": {
    "Find HubSpot Contact": {
      "main": [
        [
          {
            "node": "Merge Revocation Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Deactivate Slack User": {
      "main": [
        [
          {
            "node": "Log to Notion Offboarding DB",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HR Offboarding Webhook": {
      "main": [
        [
          {
            "node": "Parse Employee Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Employee Payload": {
      "main": [
        [
          {
            "node": "Valid Offboarding Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Compliance Sheet": {
      "main": [
        [
          {
            "node": "Send Offboarding Summary Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Revocation Results": {
      "main": [
        [
          {
            "node": "Log to Compliance Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Valid Offboarding Record": {
      "main": [
        [
          {
            "node": "Enrich Offboarding Record",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Alert Invalid Record",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Enrich Offboarding Record": {
      "main": [
        [
          {
            "node": "Suspend Google Workspace Account",
            "type": "main",
            "index": 0
          },
          {
            "node": "Deactivate Slack User",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Notion Offboarding DB": {
      "main": [
        [
          {
            "node": "Merge Revocation Results",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Send Offboarding Summary Email": {
      "main": [
        [
          {
            "node": "Slack IT Ops Digest",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Suspend Google Workspace Account": {
      "main": [
        [
          {
            "node": "Find HubSpot Contact",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}