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 →
{
"name": "Scheduling Assistant - 04 Conflict Scan",
"nodes": [
{
"parameters": {},
"id": "workflow-trigger",
"name": "When called by another workflow",
"type": "n8n-nodes-base.executeWorkflowTrigger",
"typeVersion": 1,
"position": [
250,
300
]
},
{
"parameters": {
"authentication": "oAuth2",
"resource": "calendar",
"operation": "getAll",
"calendarId": "primary",
"options": {
"timeMin": "={{$json.validatedData.normalized.startTime}}",
"timeMax": "={{$json.validatedData.normalized.endTime}}"
}
},
"id": "google-calendar-check",
"name": "Check Google Calendar",
"type": "n8n-nodes-base.googleCalendar",
"typeVersion": 3,
"position": [
450,
150
],
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"mode": "appendItems"
},
"id": "merge-calendar-data",
"name": "Merge Calendar Data",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
650,
300
],
"notes": "Input 0: original validated data (always 1 item, from trigger). Input 1: calendar events (0 or more items). appendItems guarantees Analyze Conflicts runs even when the calendar returns 0 results (no conflicts = happy path)."
},
{
"parameters": {
"jsCode": "// Analyze calendar conflicts\n//\n// Input structure after Merge (appendItems mode):\n// items[0] = original validated scheduling data (from trigger, guaranteed 1 item)\n// items[1..n] = calendar events in the requested time window (0 or more items)\n//\n// The Merge node ensures this code always runs, including when the calendar returns\n// 0 events (no conflicts), which is the happy path and the most common case.\n// Without the Merge, a 0-item getAll result would silently stop execution here.\n\nconst originalData = items[0].json.validatedData || items[0].json;\nconst requestedStart = new Date(originalData.normalized.startTime);\nconst requestedEnd = new Date(originalData.normalized.endTime);\n\n// Calendar events begin at index 1. Index 0 is the original scheduling data.\nconst calendarEvents = items.slice(1).map(item => item.json);\n\nconst conflicts = [];\n\n// Check each calendar event for time overlap with the requested window\nfor (const event of calendarEvents) {\n const eventStart = new Date(event.start?.dateTime || event.start?.date);\n const eventEnd = new Date(event.end?.dateTime || event.end?.date);\n\n if (requestedStart < eventEnd && requestedEnd > eventStart) {\n conflicts.push({\n title: event.summary,\n start: eventStart.toISOString(),\n end: eventEnd.toISOString(),\n attendees: event.attendees?.map(a => a.email) || [],\n location: event.location || 'Not specified'\n });\n }\n}\n\n// Generate up to 3 alternative time slots when conflicts are detected\nconst alternatives = [];\nif (conflicts.length > 0) {\n const duration = originalData.normalized.duration;\n\n const alt1Start = new Date(requestedStart);\n alt1Start.setHours(alt1Start.getHours() - 1);\n alternatives.push({\n startTime: alt1Start.toISOString(),\n endTime: new Date(alt1Start.getTime() + duration * 60000).toISOString(),\n reason: 'Earlier slot on same day'\n });\n\n const alt2Start = new Date(requestedEnd);\n alt2Start.setHours(alt2Start.getHours() + 1);\n alternatives.push({\n startTime: alt2Start.toISOString(),\n endTime: new Date(alt2Start.getTime() + duration * 60000).toISOString(),\n reason: 'Later slot on same day'\n });\n\n const alt3Start = new Date(requestedStart);\n alt3Start.setDate(alt3Start.getDate() + 1);\n alternatives.push({\n startTime: alt3Start.toISOString(),\n endTime: new Date(alt3Start.getTime() + duration * 60000).toISOString(),\n reason: 'Same time next day'\n });\n}\n\nreturn [{\n json: {\n ...originalData,\n conflictScan: {\n hasConflicts: conflicts.length > 0,\n conflictCount: conflicts.length,\n conflicts,\n alternatives,\n scannedAt: new Date().toISOString(),\n calendarSource: 'google_calendar'\n },\n stage: 'conflict_scanned',\n processedAt: new Date().toISOString()\n }\n}];"
},
"id": "code-analyze-conflicts",
"name": "Analyze Conflicts",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
850,
300
]
},
{
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.conflictScan.hasConflicts}}",
"value2": false
}
]
}
},
"id": "if-no-conflicts",
"name": "No Conflicts?",
"type": "n8n-nodes-base.if",
"typeVersion": 1,
"position": [
1050,
300
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "clear-data",
"name": "clearData",
"value": "={{$json}}",
"type": "object"
},
{
"id": "next-workflow-export",
"name": "nextWorkflow",
"value": "05_route_export",
"type": "string"
}
]
},
"options": {}
},
"id": "set-clear-output",
"name": "Set Clear Output",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
1250,
200
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "conflict-data",
"name": "conflictData",
"value": "={{$json}}",
"type": "object"
},
{
"id": "next-workflow-notify",
"name": "nextWorkflow",
"value": "06_notify",
"type": "string"
},
{
"id": "notification-type-conflict",
"name": "notificationType",
"value": "conflict_detected",
"type": "string"
}
]
},
"options": {}
},
"id": "set-conflict-output",
"name": "Set Conflict Output",
"type": "n8n-nodes-base.set",
"typeVersion": 3.2,
"position": [
1250,
400
]
},
{
"parameters": {
"workflowId": "={{$env.WORKFLOW_ID_ROUTE_EXPORT}}",
"options": {
"waitForSubWorkflow": false
}
},
"id": "execute-route-export",
"name": "Trigger Route & Export",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1,
"position": [
1450,
200
]
},
{
"parameters": {
"workflowId": "={{$env.WORKFLOW_ID_NOTIFY}}",
"options": {
"waitForSubWorkflow": false
}
},
"id": "execute-notify-conflict",
"name": "Notify Conflicts",
"type": "n8n-nodes-base.executeWorkflow",
"typeVersion": 1,
"position": [
1450,
400
]
}
],
"connections": {
"When called by another workflow": {
"main": [
[
{
"node": "Check Google Calendar",
"type": "main",
"index": 0
},
{
"node": "Merge Calendar Data",
"type": "main",
"index": 0
}
]
]
},
"Check Google Calendar": {
"main": [
[
{
"node": "Merge Calendar Data",
"type": "main",
"index": 1
}
]
]
},
"Merge Calendar Data": {
"main": [
[
{
"node": "Analyze Conflicts",
"type": "main",
"index": 0
}
]
]
},
"Analyze Conflicts": {
"main": [
[
{
"node": "No Conflicts?",
"type": "main",
"index": 0
}
]
]
},
"No Conflicts?": {
"main": [
[
{
"node": "Set Clear Output",
"type": "main",
"index": 0
}
],
[
{
"node": "Set Conflict Output",
"type": "main",
"index": 0
}
]
]
},
"Set Clear Output": {
"main": [
[
{
"node": "Trigger Route & Export",
"type": "main",
"index": 0
}
]
]
},
"Set Conflict Output": {
"main": [
[
{
"node": "Notify Conflicts",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveExecutionProgress": true,
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all"
},
"staticData": null,
"tags": [
{
"name": "scheduling-assistant",
"id": "scheduling-tag-001"
},
{
"name": "conflict-detection",
"id": "conflict-tag-001"
}
],
"triggerCount": 0,
"updatedAt": "2026-01-19T20:15:00.000Z",
"versionId": "v1.1.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.
googleCalendarOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Scheduling Assistant - 04 Conflict Scan. Uses executeWorkflowTrigger, googleCalendar. Event-driven trigger; 9 nodes.
Source: https://github.com/jasonv2610/multi-agent-orchestration-architecture/blob/c7a386faeebf67f7e7c9ee10be3b32fdc4ac63ef/examples/scheduling-assistant/workflows/04_conflict_scan.json — 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.
Gmail-Calendar. Uses executeWorkflowTrigger, postgres, googleCalendar, httpRequest. Event-driven trigger; 12 nodes.
Who is this for? Agencies, consultants, and service providers who conduct discovery calls and need to quickly turn conversations into professional proposals.
2582. Uses gmail, googleCalendar, lmChatOpenAi, informationExtractor. Event-driven trigger; 61 nodes.
Actioning Your Meeting Next Steps Using Transcripts And Ai. Uses lmChatOpenAi, httpRequest, googleDrive, manualTrigger. Event-driven trigger; 28 nodes.
Splitout Googlecalendar. Uses lmChatOpenAi, httpRequest, googleDrive, manualTrigger. Event-driven trigger; 28 nodes.