{
  "id": "3bg5VAmWsx3K3JlM",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Zoho CRM - Smart Meeting Scheduler",
  "tags": [
    {
      "id": "MrPLV9qP4N9aNfVu",
      "name": "Submit",
      "createdAt": "2025-11-14T06:55:53.666Z",
      "updatedAt": "2025-11-14T06:55:53.666Z"
    }
  ],
  "nodes": [
    {
      "id": "5f5e5d7b-6d70-4c73-9f05-ffda8eb04dd8",
      "name": "New Lead Trigger",
      "type": "n8n-nodes-base.zohoCrm",
      "position": [
        -800,
        368
      ],
      "parameters": {
        "leadId": "",
        "resource": "lead",
        "operation": "get"
      },
      "credentials": {
        "zohoOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6fdef927-6c46-476c-89e4-3da12a64d3e8",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -496,
        368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "meetingDuration",
              "type": "number",
              "value": 30
            },
            {
              "id": "id-2",
              "name": "bufferTimeBefore",
              "type": "number",
              "value": 15
            },
            {
              "id": "id-3",
              "name": "bufferTimeAfter",
              "type": "number",
              "value": 15
            },
            {
              "id": "id-4",
              "name": "daysToLookAhead",
              "type": "number",
              "value": 7
            },
            {
              "id": "id-5",
              "name": "workingHoursStart",
              "type": "string",
              "value": "09:00"
            },
            {
              "id": "id-6",
              "name": "workingHoursEnd",
              "type": "string",
              "value": "17:00"
            },
            {
              "id": "id-7",
              "name": "meetingLinkService",
              "type": "string",
              "value": "zoom"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "d74b2808-6562-446a-af66-546d93d48d80",
      "name": "Get Sales Rep Details",
      "type": "n8n-nodes-base.zohoCrm",
      "position": [
        -128,
        368
      ],
      "parameters": {
        "accountId": "",
        "operation": "get"
      },
      "credentials": {
        "zohoOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "4bd23adf-0fdf-4361-a6f2-a1947c4690c7",
      "name": "Detect Lead Timezone",
      "type": "n8n-nodes-base.code",
      "position": [
        48,
        368
      ],
      "parameters": {
        "jsCode": "const leadData = $input.first().json;\nconst phone = leadData.Phone || '';\nconst country = leadData.Country || '';\nconst state = leadData.State || '';\n\nlet timezone = 'America/New_York';\n\nif (country === 'United States' || country === 'USA') {\n  const stateTimezones = {\n    'California': 'America/Los_Angeles',\n    'New York': 'America/New_York',\n    'Texas': 'America/Chicago',\n    'Florida': 'America/New_York',\n    'Illinois': 'America/Chicago',\n    'Arizona': 'America/Phoenix'\n  };\n  timezone = stateTimezones[state] || 'America/New_York';\n} else if (country === 'United Kingdom' || country === 'UK') {\n  timezone = 'Europe/London';\n} else if (country === 'Germany') {\n  timezone = 'Europe/Berlin';\n} else if (country === 'Australia') {\n  timezone = 'Australia/Sydney';\n}\n\nreturn {\n  json: {\n    ...leadData,\n    detectedTimezone: timezone\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "596b7c12-344f-4651-8986-42a4df49f61b",
      "name": "Get Rep Calendar Availability",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        224,
        368
      ],
      "parameters": {
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "id",
          "value": ""
        },
        "operation": "getAll"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3,
      "alwaysOutputData": false
    },
    {
      "id": "3b78a1d2-bf0e-4b9b-9786-76cc39a65b25",
      "name": "Find Available Slots with Buffer",
      "type": "n8n-nodes-base.code",
      "position": [
        448,
        368
      ],
      "parameters": {
        "jsCode": "const config = $('Workflow Configuration').first().json;\nconst events = $input.all().map(item => item.json);\nconst meetingDuration = config.meetingDuration;\nconst bufferBefore = config.bufferTimeBefore;\nconst bufferAfter = config.bufferTimeAfter;\nconst workStart = config.workingHoursStart;\nconst workEnd = config.workingHoursEnd;\nconst daysAhead = config.daysToLookAhead;\nconst timezone = $('Detect Lead Timezone').first().json.detectedTimezone;\n\nconst availableSlots = [];\nconst now = new Date();\n\nfor (let day = 0; day < daysAhead; day++) {\n  const currentDay = new Date(now);\n  currentDay.setDate(now.getDate() + day);\n  const dayStart = new Date(currentDay.toDateString() + ' ' + workStart);\n  const dayEnd = new Date(currentDay.toDateString() + ' ' + workEnd);\n  \n  let currentTime = dayStart;\n  \n  while (currentTime < dayEnd) {\n    const slotEnd = new Date(currentTime.getTime() + meetingDuration * 60000);\n    if (slotEnd > dayEnd) break;\n    \n    const slotStartWithBuffer = new Date(currentTime.getTime() - bufferBefore * 60000);\n    const slotEndWithBuffer = new Date(slotEnd.getTime() + bufferAfter * 60000);\n    \n    const hasConflict = events.some(event => {\n      const eventStart = new Date(event.start.dateTime || event.start.date);\n      const eventEnd = new Date(event.end.dateTime || event.end.date);\n      return (slotStartWithBuffer < eventEnd && slotEndWithBuffer > eventStart);\n    });\n    \n    if (!hasConflict && currentTime > now) {\n      availableSlots.push({\n        startTime: currentTime.toISOString(),\n        endTime: slotEnd.toISOString(),\n        timezone: timezone\n      });\n    }\n    \n    currentTime = new Date(currentTime.getTime() + 30 * 60000);\n  }\n}\n\nreturn {\n  json: {\n    availableSlots: availableSlots.slice(0, 5),\n    hasSlots: availableSlots.length > 0\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "3a2ef151-6eca-4757-964f-2da81eba5b48",
      "name": "Check Slots Available",
      "type": "n8n-nodes-base.if",
      "position": [
        720,
        368
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.hasSlots }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "44b47691-07a1-4b94-8712-8253426579cc",
      "name": "Generate Meeting Link",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1040,
        64
      ],
      "parameters": {
        "url": "https://zoom.us/oauth/token",
        "method": "POST",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "grant_type",
              "value": "account_credentials"
            },
            {
              "name": "account_id",
              "value": "UGR7lYDyTLGGuUUxURMMdw"
            }
          ]
        }
      },
      "credentials": {
        "httpBasicAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "c80d5adf-e346-40a9-b841-dce726c188e6",
      "name": "Generate Personalized Invite",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1888,
        304
      ],
      "parameters": {
        "text": "=Lead details: {{ JSON.stringify($('Detect Lead Timezone').first().json) }}\nAvailable slots: {{ JSON.stringify($('Find Available Slots with Buffer').first().json.availableSlots) }}\nMeeting link: {{ $json.join_url }}",
        "options": {
          "systemMessage": "You are a professional meeting scheduler assistant.\n\nYour task is to:\n1. Analyze the lead information and available meeting slots\n2. Generate a warm, personalized email invitation\n3. Present the top 3 available time slots in the lead's timezone\n4. Include the meeting link\n5. Keep the tone professional yet friendly\n6. Highlight the value of the meeting\n\nReturn ONLY the email content with subject line and body in HTML format."
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "74cc79c0-dd30-4414-8af3-66601029ba2d",
      "name": "Send Meeting Invite",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2224,
        304
      ],
      "parameters": {
        "sendTo": "={{ $('Detect Lead Timezone').item.json.Owner.email }}",
        "message": "={{ $json.output }}",
        "options": {},
        "subject": "={{ $json.output.split('Subject:')[1].split('\\n')[0].trim() }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "830014ab-c1fc-43c4-a091-76325c1b0320",
      "name": "Log Meeting in Zoho CRM",
      "type": "n8n-nodes-base.zohoCrm",
      "position": [
        2464,
        304
      ],
      "parameters": {
        "Company": "Meeting Event",
        "lastName": "={{ $('Detect Lead Timezone').item.json.Owner.name }}",
        "resource": "lead",
        "additionalFields": {
          "Description": "={{ 'Meeting Scheduled with ' + $('Detect Lead Timezone').first().json.Full_Name + ' from ' + $('Find Available Slots with Buffer').first().json.availableSlots[0].startTime + ' to ' + $('Find Available Slots with Buffer').first().json.availableSlots[0].endTime }}"
        }
      },
      "credentials": {
        "zohoOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "bcdcb6dd-9585-4369-822c-c9523819fa64",
      "name": "No Slots Available Message",
      "type": "n8n-nodes-base.set",
      "position": [
        1056,
        544
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "subject",
              "type": "string",
              "value": "Unable to Schedule Meeting - Let's Connect"
            },
            {
              "id": "id-2",
              "name": "message",
              "type": "string",
              "value": "=Hi {{ $('Detect Lead Timezone').first().json.Full_Name }},\n\nThank you for your interest! Unfortunately, our sales representative doesn't have any available slots in the next {{ $('Workflow Configuration').first().json.daysToLookAhead }} days.\n\nWe'd still love to connect with you. Please reply to this email with your preferred times, and we'll do our best to accommodate.\n\nBest regards,\nThe Team"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4fc09d7c-4e51-4635-8927-5a938a7f3a7d",
      "name": "Send No Availability Email",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1360,
        544
      ],
      "parameters": {
        "sendTo": "=dg3avt@gmail.com",
        "message": "={{ $json.message }}",
        "options": {},
        "subject": "={{ $json.subject }}"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "326b149a-ef54-44e1-ba7f-73914f74bcca",
      "name": "Zoho CRM Lead Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -1040,
        368
      ],
      "parameters": {
        "path": "zoho-lead-webhook",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "13b1e2c4-3b4f-4cfb-a78c-1b6602928a50",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        1920,
        544
      ],
      "parameters": {
        "options": {}
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "2fe13fe0-5ac7-4b1c-9a74-5801491e4c9a",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "onError": "continueRegularOutput",
      "position": [
        1328,
        64
      ],
      "parameters": {
        "url": "https://api.zoom.us/v2/users/me/meetings",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "topic",
              "value": "A Scheduled Meeting from n8n"
            },
            {
              "name": "type",
              "value": "2"
            },
            {
              "name": "start_time",
              "value": "={{ $('Check Slots Available').item.json.availableSlots[0].startTime }}"
            },
            {
              "name": "duration",
              "value": "30"
            },
            {
              "name": "timezone",
              "value": "={{ $('Check Slots Available').item.json.availableSlots[0].timezone }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "={{ 'Bearer ' + $json.access_token }}"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "5bf907e6-4f69-4e62-ad19-e828e97431ea",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1840,
        -608
      ],
      "parameters": {
        "width": 656,
        "height": 1024,
        "content": "## How It Works\nThis workflow automatically schedules meetings for new Zoho CRM leads. When a lead is created, Zoho triggers a webhook that sends the lead ID to n8n, which then retrieves full lead details, identifies the sales rep, and detects the lead\u2019s timezone. The workflow checks the rep\u2019s Google Calendar availability and generates time slots based on your rules such as working hours, meeting duration, buffer time, and days to search.\n\nIf suitable slots exist, a Zoom meeting is created and Gemini AI generates a personalized email with the top three time options and meeting link, which is then sent to the lead. The workflow also updates Zoho CRM with the meeting details. If no slots are available, a fallback email is sent instead.\n\n## Setup Steps\n\n### 1.Connect Integrations\nAuthenticate Zoho CRM, Google Calendar, Gmail, Zoom, and Gemini in n8n.\n\n### 2.Import Workflow\nGo to n8n \u2192 Workflows \u2192 Import and paste the provided workflow JSON.\n\n### 3.Update Configuration\nIn the Workflow Configuration node, set meeting duration, buffers, working hours, days to search, and meeting provider.\n\n### 4.Adjust Timezone Logic\nIn the Detect Lead Timezone code node, edit or expand country/state \u2192 timezone mappings.\n\n### 5.Verify Google Calendar Access\nEnsure each sales rep has a correct calendar ID in Zoho CRM and events are fetchable.\n\n### 6.Add Zoho Webhook\nCopy the webhook URL from n8n and add it under Zoho CRM \u2192 Setup \u2192 Automation \u2192 Webhooks \u2192 Lead Created.\n\n### 7.Run a Test Lead\nCreate a lead and confirm it detects timezone, finds slots, creates a Zoom meeting, emails the lead, and logs in CRM.\n\n### 8.Activate Workflow\nOnce verified, switch the workflow to Active."
      },
      "typeVersion": 1
    },
    {
      "id": "95c0d447-1545-446e-93b2-47ef3304ae24",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1088,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 480,
        "content": "## Lead Capture & Retrieval (Webhook + Zoho CRM Get Lead)\n### Automatically triggers when a new lead is created in Zoho CRM. The webhook sends the lead ID to n8n, which then fetches full lead details for processing."
      },
      "typeVersion": 1
    },
    {
      "id": "e51df1c6-c11c-4510-9289-85a7c053cfb0",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -592,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 480,
        "content": "## Workflow Configuration\n### Stores all scheduling settings such as meeting duration, buffers, working hours, days to search, and meeting provider for later workflow steps."
      },
      "typeVersion": 1
    },
    {
      "id": "701e6b38-0538-4421-810b-65e9f624cf18",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -192,
        176
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 480,
        "content": "## Sales Rep & Availability Processing\n### Retrieves the assigned sales rep\u2019s details, detects the lead\u2019s timezone, checks the rep\u2019s current calendar events, and generates conflict-free meeting slots using working hours, duration, and buffer rules."
      },
      "typeVersion": 1
    },
    {
      "id": "90d2adf7-7678-4156-a69a-9a76457b82a8",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 576,
        "height": 560,
        "content": "## Zoom Meeting Creation\n### Authenticates with Zoom to obtain an access token, then creates a scheduled Zoom meeting using the earliest available time slot and returns the join details."
      },
      "typeVersion": 1
    },
    {
      "id": "0c15bd75-4297-4c65-9a2b-7daf10df99a4",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 576,
        "height": 464,
        "content": "## Fallback Email Handling\n### Prepares a polite \u201cno availability\u201d message and sends it to the lead via Gmail when no suitable meeting slots are found, prompting them to share preferred times."
      },
      "typeVersion": 1
    },
    {
      "id": "d9fada0c-fa2e-487f-a955-692cdcfba297",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1664,
        80
      ],
      "parameters": {
        "color": 7,
        "width": 1056,
        "height": 624,
        "content": "## AI Email & CRM Logging\n### Generates a personalized HTML invite with meeting details and top time slots, sends it to the lead via Gmail, and logs the scheduled meeting inside Zoho CRM for tracking."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c34da5a0-7fc6-4946-ac12-c8057f007dcd",
  "connections": {
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Generate Personalized Invite",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Lead Trigger": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Meeting Invite": {
      "main": [
        [
          {
            "node": "Log Meeting in Zoho CRM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Lead Timezone": {
      "main": [
        [
          {
            "node": "Get Rep Calendar Availability",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Slots Available": {
      "main": [
        [
          {
            "node": "Generate Meeting Link",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "No Slots Available Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Meeting Link": {
      "main": [
        [
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Sales Rep Details": {
      "main": [
        [
          {
            "node": "Detect Lead Timezone",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Zoho CRM Lead Webhook": {
      "main": [
        [
          {
            "node": "New Lead Trigger",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Get Sales Rep Details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Generate Personalized Invite",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "No Slots Available Message": {
      "main": [
        [
          {
            "node": "Send No Availability Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Personalized Invite": {
      "main": [
        [
          {
            "node": "Send Meeting Invite",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Rep Calendar Availability": {
      "main": [
        [
          {
            "node": "Find Available Slots with Buffer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find Available Slots with Buffer": {
      "main": [
        [
          {
            "node": "Check Slots Available",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}