{
  "id": "FaVKjslhnoxgrLBW",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "M365 Employee Onboarding Orchestrator (Microsoft Agent 365)",
  "tags": [],
  "nodes": [
    {
      "id": "c98b993b-5c74-4150-8f35-291501892e85",
      "name": "README",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2368,
        1120
      ],
      "parameters": {
        "width": 620,
        "height": 386,
        "content": "## M365 Employee Onboarding Orchestrator\n\n### Overview\nThis agent is invoked by HR in Teams or Outlook (via @mention or email) when a new employee\nis added in the HRIS system. It orchestrates the full onboarding stack inside Microsoft 365.\n\n### Production Failsafes Added:\n- **True Parallel Execution:** All 4 major tasks run independently from the parser.\n- **Continue On Fail:** ALL M365 and AI action nodes output error items to downstream Wait nodes.\n- **Dynamic Validation:** The final Adaptive Card pulls live URLs and IDs, showing \u274c for failed branches.\n- **Global Error Trigger:** Catches unhandled workflow crashes.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5f12912b-23d5-4553-a157-86ac6dbc1183",
      "name": "Microsoft Agent 365",
      "type": "@n8n/n8n-nodes-langchain.microsoftAgent365Trigger",
      "position": [
        3104,
        1264
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.1
    },
    {
      "id": "38e642f0-bb95-4437-8f5c-982631de8d8f",
      "name": "Parse New Hire + Config",
      "type": "n8n-nodes-base.code",
      "position": [
        3456,
        1264
      ],
      "parameters": {
        "jsCode": "const payload = $input.first().json;\nconst rawText = payload.text || payload.body?.content || payload.message || '';\n\nconst extract = (label) => {\n  const regex = new RegExp(`${label}[:\\\\s]+([^|\\\\n]+)`, 'i');\n  const match = rawText.match(regex);\n  return match ? match[1].trim() : '';\n};\n\nconst newHire = {\n  fullName:    extract('Name') || extract('Employee') || 'New Employee',\n  role:        extract('Role') || extract('Title') || extract('Position') || 'Team Member',\n  department:  extract('Department') || extract('Team') || 'General',\n  startDate:   extract('StartDate') || extract('Start Date') || extract('Start') ||\n               new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0],\n  managerEmail: extract('Manager') || extract('ReportsTo') || '',\n  location:    extract('Location') || extract('Office') || 'Remote',\n  email:       extract('Email') || extract('WorkEmail') || ''\n};\n\nconst folderName = `${newHire.fullName} - ${newHire.role} - ${newHire.startDate}`\n  .replace(/[<>:\"/\\\\|?*]/g, '-').trim();\n\nconst SHAREPOINT_SITE_ID           = 'REPLACE_WITH_YOUR_SHAREPOINT_SITE_ID';\nconst SHAREPOINT_LIST_ID           = 'REPLACE_WITH_YOUR_ONBOARDING_LIST_ID';\nconst ONEDRIVE_PARENT_FOLDER_PATH  = '/HR/NewHires'; \nconst TEAMS_HR_TEAM_ID             = 'REPLACE_WITH_YOUR_HR_TEAM_ID';\nconst TEAMS_ONBOARDING_CHANNEL_ID  = 'REPLACE_WITH_YOUR_ONBOARDING_CHANNEL_ID';\nconst OUTLOOK_HR_MAILBOX           = 'user@example.com';\n\nreturn [{\n  json: {\n    ...newHire,\n    folderName,\n    SHAREPOINT_SITE_ID,\n    SHAREPOINT_LIST_ID,\n    ONEDRIVE_PARENT_FOLDER_PATH,\n    TEAMS_HR_TEAM_ID,\n    TEAMS_ONBOARDING_CHANNEL_ID,\n    OUTLOOK_HR_MAILBOX,\n    rawText,\n    triggeredAt: new Date().toISOString()\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "f2dd72b9-1c1f-431b-b03f-3326b9eca332",
      "name": "SharePoint: Create Onboarding Entry",
      "type": "n8n-nodes-base.microsoftSharePoint",
      "onError": "continueErrorOutput",
      "position": [
        4288,
        1008
      ],
      "parameters": {
        "site": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "requestOptions": {}
      },
      "typeVersion": 1
    },
    {
      "id": "babf6b34-77b7-47d2-9568-308fe4958ffd",
      "name": "OneDrive: Create Employee Folder",
      "type": "n8n-nodes-base.microsoftOneDrive",
      "onError": "continueErrorOutput",
      "position": [
        3904,
        1248
      ],
      "parameters": {
        "operation": "createFolder"
      },
      "typeVersion": 1
    },
    {
      "id": "c5a20a87-4005-44e9-94fc-ad4c2a134a9d",
      "name": "Build SubFolder Paths",
      "type": "n8n-nodes-base.code",
      "position": [
        4144,
        1232
      ],
      "parameters": {
        "jsCode": "const basePath = $('Parse New Hire + Config').first().json.ONEDRIVE_PARENT_FOLDER_PATH\n  + '/' + $('Parse New Hire + Config').first().json.folderName;\n\nconst subFolders = ['01 - Contracts', '02 - Equipment', '03 - Training', '04 - Benefits', '05 - Personal Documents'];\n\nreturn subFolders.map(folder => ({\n  json: { folderPath: `${basePath}/${folder}`, newHireData: $('Parse New Hire + Config').first().json }\n}));"
      },
      "typeVersion": 2
    },
    {
      "id": "2ee7a1ea-c107-44e0-a2b5-077c67038df7",
      "name": "OneDrive: Create SubFolders",
      "type": "n8n-nodes-base.microsoftOneDrive",
      "onError": "continueErrorOutput",
      "position": [
        4336,
        1232
      ],
      "parameters": {
        "operation": "createFolder"
      },
      "typeVersion": 1
    },
    {
      "id": "40e66bce-ac04-43fb-816c-42ad184cf84f",
      "name": "Limit SubFolders Array",
      "type": "n8n-nodes-base.itemLists",
      "position": [
        4624,
        1216
      ],
      "parameters": {
        "operation": "limit"
      },
      "typeVersion": 3
    },
    {
      "id": "d914428a-263f-438e-9665-28798dc905a1",
      "name": "Wait: SP & OneDrive",
      "type": "n8n-nodes-base.merge",
      "position": [
        5024,
        1008
      ],
      "parameters": {
        "mode": "wait",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "a355dbfc-77bd-41fd-9fa5-5f97438a4983",
      "name": "Teams: Create Onboarding Channel",
      "type": "n8n-nodes-base.microsoftTeams",
      "onError": "continueErrorOutput",
      "position": [
        3968,
        1584
      ],
      "parameters": {
        "teamId": "={{ $('Parse New Hire + Config').first().json.TEAMS_HR_TEAM_ID }}",
        "options": {}
      },
      "typeVersion": 2
    },
    {
      "id": "d2e392dc-ae6e-44cf-a7c4-8aacd5a0b602",
      "name": "AI: Generate Welcome Email",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "onError": "continueErrorOutput",
      "position": [
        3936,
        1776
      ],
      "parameters": {
        "text": "={{ 'Write a warm, personalised welcome email for a new employee with these details:\\n\\nName: ' + $('Parse New Hire + Config').first().json.fullName + '\\nRole: ' + $('Parse New Hire + Config').first().json.role + '\\nDepartment: ' + $('Parse New Hire + Config').first().json.department + '\\nStart Date: ' + $('Parse New Hire + Config').first().json.startDate + '\\nLocation: ' + $('Parse New Hire + Config').first().json.location }}",
        "options": {
          "systemMessage": "You are the company's People Operations team writing a welcome email to a new employee.\nWrite a warm, professional, and concise welcome email. Tone: friendly but not over-the-top.\nDo NOT use em dashes. Use short paragraphs.\nInclude:\n- Genuine welcome using their first name\n- One sentence acknowledging their role and what the team is excited about\n- What happens on day 1 (they will receive a calendar invite from their manager)\n- One sentence about culture / what makes working here special\n- Closing with excitement about them joining\nSign off as: The People Operations Team\nReturn ONLY the email body text, no subject line, no preamble, no JSON."
        },
        "promptType": "define"
      },
      "typeVersion": 1.7
    },
    {
      "id": "0a8bc319-53b6-40b0-9c18-00a8c511bb76",
      "name": "Claude Sonnet 4",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        3936,
        1936
      ],
      "parameters": {
        "model": "claude-sonnet-4-20250514",
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "5ecb5688-be82-4988-81c4-918237f86e2a",
      "name": "Outlook: Send Welcome Email",
      "type": "n8n-nodes-base.microsoftOutlook",
      "onError": "continueErrorOutput",
      "position": [
        4368,
        1760
      ],
      "parameters": {
        "subject": "={{ 'Welcome to the team, ' + $('Parse New Hire + Config').first().json.fullName.split(' ')[0] + '!' }}",
        "toRecipients": "={{ $('Parse New Hire + Config').first().json.email }}",
        "additionalFields": {}
      },
      "typeVersion": 2
    },
    {
      "id": "18b266d0-10b9-41ab-859e-539d90c322db",
      "name": "Wait: Teams & Email",
      "type": "n8n-nodes-base.merge",
      "position": [
        4704,
        1744
      ],
      "parameters": {
        "mode": "wait",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "68b7123b-9df1-4979-a8cc-8d8ceae50fe5",
      "name": "Wait: All Branches",
      "type": "n8n-nodes-base.merge",
      "position": [
        5264,
        1088
      ],
      "parameters": {
        "mode": "wait",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "83073cc0-44ea-4749-8f0c-b509a8f9ef1f",
      "name": "Build HR Summary Card",
      "type": "n8n-nodes-base.code",
      "position": [
        5536,
        1088
      ],
      "parameters": {
        "jsCode": "const hire = $('Parse New Hire + Config').first().json;\n\n// Dynamically pull execution results from the true parallel branches\nconst spItem = $('SharePoint: Create Onboarding Entry').first().json || {};\nconst odFolder = $('OneDrive: Create Employee Folder').first().json || {};\nconst teamsChannel = $('Teams: Create Onboarding Channel').first().json || {};\nconst emailRes = $('Outlook: Send Welcome Email').first().json || {};\n\nconst spSuccess = spItem.id ? `\u2705 SharePoint List Item ID: ${spItem.id}` : '\u274c SharePoint List Update Failed';\nconst odSuccess = odFolder.webUrl ? `\u2705 [OneDrive Folder Provisioned](${odFolder.webUrl})` : '\u274c OneDrive Provisioning Failed';\nconst teamsSuccess = teamsChannel.webUrl ? `\u2705 [Teams Channel Created](${teamsChannel.webUrl})` : '\u274c Teams Channel Creation Failed';\nconst emailSuccess = emailRes.id ? `\u2705 Welcome email sent to ${hire.email}` : '\u274c AI Generation or Email Failed';\n\nconst adaptiveCard = {\n  type: 'AdaptiveCard',\n  '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json',\n  version: '1.5',\n  body: [\n    {\n      type: 'TextBlock',\n      text: `\ud83c\udf89 New Team Member Onboarded: ${hire.fullName}`,\n      weight: 'Bolder',\n      size: 'Medium',\n      color: 'Good',\n      wrap: true\n    },\n    {\n      type: 'FactSet',\n      facts: [\n        { title: 'Role',        value: hire.role },\n        { title: 'Department',  value: hire.department },\n        { title: 'Start Date',  value: hire.startDate },\n        { title: 'Location',    value: hire.location },\n        { title: 'Manager',     value: hire.managerEmail || 'TBD' }\n      ]\n    },\n    {\n      type: 'TextBlock',\n      text: '**Onboarding Task Status:**',\n      weight: 'Bolder',\n      spacing: 'Medium'\n    },\n    {\n      type: 'TextBlock',\n      text: `${spSuccess}\\n${odSuccess}\\n${teamsSuccess}\\n${emailSuccess}`,\n      wrap: true,\n      spacing: 'None'\n    }\n  ]\n};\n\nreturn [{\n  json: {\n    adaptiveCard: JSON.stringify(adaptiveCard),\n    teamId:     hire.TEAMS_HR_TEAM_ID,\n    channelId:  hire.TEAMS_ONBOARDING_CHANNEL_ID\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "e76850bd-b19e-4b00-bbcc-ca3e8b35ac8b",
      "name": "Teams: Post HR Summary Card",
      "type": "n8n-nodes-base.microsoftTeams",
      "position": [
        5808,
        1088
      ],
      "parameters": {
        "operation": "post"
      },
      "typeVersion": 2
    },
    {
      "id": "2fee7dca-1f41-4c26-86b9-f33e54834c65",
      "name": "Error Trigger",
      "type": "n8n-nodes-base.errorTrigger",
      "position": [
        3104,
        1904
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "9dbef3e4-4802-4982-b603-45637cdaf587",
      "name": "Build Error Alert Card",
      "type": "n8n-nodes-base.code",
      "position": [
        3328,
        1904
      ],
      "parameters": {
        "jsCode": "const errorData = $input.first().json;\n\nconst adaptiveCard = {\n  type: 'AdaptiveCard',\n  '$schema': 'http://adaptivecards.io/schemas/adaptive-card.json',\n  version: '1.5',\n  body: [\n    {\n      type: 'TextBlock',\n      text: `\ud83d\udea8 Onboarding Workflow Critical Failure`,\n      weight: 'Bolder',\n      size: 'Medium',\n      color: 'Attention',\n      wrap: true\n    },\n    {\n      type: 'FactSet',\n      facts: [\n        { title: 'Failed Node',  value: errorData.execution.lastNodeExecuted },\n        { title: 'Error Message', value: errorData.execution.error.message },\n        { title: 'Workflow ID',  value: errorData.workflow.id }\n      ]\n    }\n  ]\n};\n\nreturn [{\n  json: {\n    adaptiveCard: JSON.stringify(adaptiveCard),\n    teamId: 'REPLACE_WITH_YOUR_HR_TEAM_ID',\n    channelId: 'REPLACE_WITH_YOUR_ONBOARDING_CHANNEL_ID'\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "0a87e049-f953-4c1b-a35d-8285285aae99",
      "name": "Teams: Post Error Alert",
      "type": "n8n-nodes-base.microsoftTeams",
      "position": [
        3552,
        1904
      ],
      "parameters": {
        "operation": "post"
      },
      "typeVersion": 2
    },
    {
      "id": "a5907727-c132-4f5d-8cf1-c78d583cef2b",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3040,
        1792
      ],
      "parameters": {
        "color": 7,
        "width": 736,
        "height": 268,
        "content": "### Global Error Failsafe\nCatches severe, unhandled workflow crashes (e.g., node timeout, Anthropic API drop, out-of-memory) and alerts the IT/HR channel immediately."
      },
      "typeVersion": 1
    },
    {
      "id": "10f9ded5-d23f-40c8-9fd7-ca8a6b0bbf1e",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3072,
        1152
      ],
      "parameters": {
        "color": 7,
        "width": 560,
        "height": 300,
        "content": "### Ingestion & Payload Parsing\nListens for the Agent 365 trigger and extracts the employee data using regex. Sets up core tenant IDs for downstream nodes"
      },
      "typeVersion": 1
    },
    {
      "id": "28fd8c28-9e47-4181-af64-f62d19c8b904",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3824,
        912
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 508,
        "content": "### Ingestion & Payload Parsing\nCreates the employee's SharePoint entry and provisions their personal OneDrive space. Handles the array mapping to generate the 5 required templated sub-folders."
      },
      "typeVersion": 1
    },
    {
      "id": "c15dd002-af34-4bb9-b278-1481fdcd0f54",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3824,
        1472
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 588,
        "content": "### Communications Pipeline\nProvisions the private cohort channel in Teams and leverages Claude to write a highly contextual, personalized welcome email sent via Outlook."
      },
      "typeVersion": 1
    },
    {
      "id": "b476f704-2f3a-4ba3-8873-3b4cf3aa1072",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4960,
        912
      ],
      "parameters": {
        "color": 7,
        "width": 1088,
        "height": 508,
        "content": "### Parallel Sync & Summary\nWaits for all parallel branches to resolve (whether they succeed or pass an error item via 'Continue on Fail'). Dynamically validates the outputs and posts a final markdown summary card to HR."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "77157b6c-e1e3-4270-976d-1246ae5e75fd",
  "connections": {
    "Error Trigger": {
      "main": [
        [
          {
            "node": "Build Error Alert Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet 4": {
      "ai_languageModel": [
        [
          {
            "node": "AI: Generate Welcome Email",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Wait: All Branches": {
      "main": [
        [
          {
            "node": "Build HR Summary Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Microsoft Agent 365": {
      "main": [
        [
          {
            "node": "Parse New Hire + Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait: SP & OneDrive": {
      "main": [
        [
          {
            "node": "Wait: All Branches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait: Teams & Email": {
      "main": [
        [
          {
            "node": "Wait: All Branches",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Build HR Summary Card": {
      "main": [
        [
          {
            "node": "Teams: Post HR Summary Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build SubFolder Paths": {
      "main": [
        [
          {
            "node": "OneDrive: Create SubFolders",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Error Alert Card": {
      "main": [
        [
          {
            "node": "Teams: Post Error Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit SubFolders Array": {
      "main": [
        [
          {
            "node": "Wait: SP & OneDrive",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Parse New Hire + Config": {
      "main": [
        [
          {
            "node": "SharePoint: Create Onboarding Entry",
            "type": "main",
            "index": 0
          },
          {
            "node": "OneDrive: Create Employee Folder",
            "type": "main",
            "index": 0
          },
          {
            "node": "Teams: Create Onboarding Channel",
            "type": "main",
            "index": 0
          },
          {
            "node": "AI: Generate Welcome Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI: Generate Welcome Email": {
      "main": [
        [
          {
            "node": "Outlook: Send Welcome Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OneDrive: Create SubFolders": {
      "main": [
        [
          {
            "node": "Limit SubFolders Array",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Outlook: Send Welcome Email": {
      "main": [
        [
          {
            "node": "Wait: Teams & Email",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "OneDrive: Create Employee Folder": {
      "main": [
        [
          {
            "node": "Build SubFolder Paths",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Teams: Create Onboarding Channel": {
      "main": [
        [
          {
            "node": "Wait: Teams & Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SharePoint: Create Onboarding Entry": {
      "main": [
        [
          {
            "node": "Wait: SP & OneDrive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}