This workflow corresponds to n8n.io template #10104 — we link there as the canonical source.
This workflow follows the Gmail → Google Calendar 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": "f86tpZtlEF8Fxt6s",
"name": "Automated Booking Confirmation and Meeting Scheduler",
"tags": [],
"nodes": [
{
"id": "3dd27b86-6e03-4595-a9fa-2fe3d1210611",
"name": "Google Forms Webhook1",
"type": "n8n-nodes-base.webhook",
"position": [
176,
208
],
"parameters": {
"path": "google-forms-booking",
"options": {},
"httpMethod": "POST",
"responseMode": "lastNode"
},
"typeVersion": 2.1
},
{
"id": "957b6711-281f-4599-9962-84ebf221691a",
"name": "Merge Form Data1",
"type": "n8n-nodes-base.merge",
"position": [
496,
224
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "3b63fe73-a5e7-4f3e-bf61-e7bd0a9aa63c",
"name": "Workflow Configuration1",
"type": "n8n-nodes-base.set",
"position": [
848,
224
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "id-1",
"name": "calendarId",
"type": "string",
"value": "user@example.com"
},
{
"id": "id-2",
"name": "slackChannel",
"type": "string",
"value": "C09GN4NCTAP"
},
{
"id": "id-3",
"name": "teammateEmail",
"type": "string",
"value": "user@example.com"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "66b2895b-8260-4e40-b4ec-39b100b89f77",
"name": "Extract Booking Details1",
"type": "n8n-nodes-base.set",
"position": [
1168,
224
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "id-1",
"name": "customerName",
"type": "string",
"value": "={{ $json.body.name }}"
},
{
"id": "id-2",
"name": "customerEmail",
"type": "string",
"value": "={{ $json.body.email }}"
},
{
"id": "id-3",
"name": "bookingDate",
"type": "string",
"value": "={{ $json.body.date }}"
},
{
"id": "id-4",
"name": "bookingTime",
"type": "string",
"value": "={{ $json.body.time }}"
},
{
"id": "34865dea-9db2-4f35-b91b-322572680869",
"name": "bookingStartISO",
"type": "string",
"value": "={{ new Date($json.body.date + 'T' + $json.body.time + ':00+09:00').toISOString() }}"
},
{
"id": "941d5f18-54fd-41ad-8f46-c9f9f13fb32f",
"name": "bookingEndISO",
"type": "string",
"value": "={{ new Date(new Date($json.body.date + 'T' + $json.body.time + ':00+09:00').getTime() + 60*60*1000).toISOString() }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "6591a8f7-2400-4de8-9fbe-b35271faf1f8",
"name": "Check Calendar Availability1",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1472,
224
],
"parameters": {
"options": {},
"timeMax": "={{ $json.bookingEndISO }}",
"timeMin": "={{ $json.bookingStartISO }}",
"calendar": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Configuration1').first().json.calendarId }}"
},
"operation": "getAll"
},
"typeVersion": 1.3,
"alwaysOutputData": true
},
{
"id": "d80641b0-9da6-491c-922f-d278c0f030c3",
"name": "Is Time Slot Available?1",
"type": "n8n-nodes-base.if",
"position": [
1824,
224
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "14e9293a-f96c-45f1-b216-2c8aaf2fb3e2",
"operator": {
"type": "object",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "76a27cb5-7196-4564-a89a-85d5d0a41d52",
"name": "Create Calendar Event1",
"type": "n8n-nodes-base.googleCalendar",
"position": [
2144,
208
],
"parameters": {
"end": "={{ $('Extract Booking Details1').first().json.bookingEndISO }}",
"start": "={{ $('Extract Booking Details1').first().json.bookingStartISO }}",
"calendar": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Configuration1').first().json.calendarId }}"
},
"additionalFields": {
"summary": "=Booking with {{ $('Extract Booking Details1').first().json.customerName }}",
"attendees": [
"={{ $('Extract Booking Details1').first().json.customerEmail }}"
],
"description": "=Customer: {{ $('Extract Booking Details1').first().json.customerName }} ({{ $('Extract Booking Details1').first().json.customerEmail }})"
}
},
"typeVersion": 1.3
},
{
"id": "9f4ca36f-8f02-43ee-8630-222958201959",
"name": "Create Zoom Meeting1",
"type": "n8n-nodes-base.zoom",
"position": [
2416,
208
],
"parameters": {
"topic": "=Booking with {{ $('Extract Booking Details1').first().json.customerName }}",
"authentication": "oAuth2",
"additionalFields": {
"duration": 60,
"timeZone": "UTC",
"startTime": "={{ $('Extract Booking Details1').first().json.bookingStartISO }}"
}
},
"typeVersion": 1
},
{
"id": "a31d67fa-38b4-4276-a0ad-56d1069f95dd",
"name": "Send Confirmation Email1",
"type": "n8n-nodes-base.gmail",
"position": [
2720,
208
],
"parameters": {
"sendTo": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
"message": "=Hi {{ $('Extract Booking Details1').first().json.customerName }},\n\nYour booking has been confirmed!\n\nDate & Time: {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}\n\nZoom Meeting Link: {{ $json.join_url }}\n\nLooking forward to meeting you!\n\nBest regards",
"options": {},
"subject": "=Booking Confirmed: {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}"
},
"typeVersion": 2.1
},
{
"id": "b456c4f9-dcca-48a4-b750-f39e95df493f",
"name": "Notify Teammate on Slack1",
"type": "n8n-nodes-base.slack",
"position": [
3040,
208
],
"parameters": {
"text": "=\ud83c\udf89 New booking confirmed!\n\n*Customer:* {{ $('Extract Booking Details1').first().json.customerName }} ({{ $('Extract Booking Details1').first().json.customerEmail }})\n*Date & Time:* {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }}\n*Zoom Link:* {{ $json.join_url }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Configuration1').first().json.slackChannel }}"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"typeVersion": 2.3
},
{
"id": "78d4ae92-b136-4bbe-ae52-a73a60c47a6c",
"name": "Send Unavailable Email1",
"type": "n8n-nodes-base.gmail",
"position": [
2144,
512
],
"parameters": {
"sendTo": "={{ $('Extract Booking Details1').first().json.customerEmail }}",
"message": "=Hi {{ $('Extract Booking Details1').first().json.customerName }},\n\nThank you for your booking request. Unfortunately, the requested time slot on {{ new Date($('Extract Booking Details1').first().json.bookingStartISO).toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' }) }} is not available.\n\nPlease submit a new booking request with an alternative time.",
"options": {},
"subject": "Time Slot Unavailable"
},
"typeVersion": 2.1
},
{
"id": "9f8af7ba-09f1-46bb-9bc6-bb2d0b26d744",
"name": "Sticky: Google Forms Webhook1",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
-400
],
"parameters": {
"color": "white",
"width": 768,
"height": 528,
"content": "Title: Automated Booking \u2192 Calendar + Zoom + Email + Slack\nWhat this workflow does\n\nCaptures booking submissions from a form and parses date/time.\n\nChecks Google Calendar for conflicts.\n\nIf free: creates a Calendar event \u2192 creates a Zoom meeting \u2192 emails the guest \u2192 notifies your team on Slack.\n\nIf busy: emails the guest to pick another time.\n\nFlow\nWebhook \u2192 Merge \u2192 Config \u2192 Extract details \u2192 Check availability \u2192 IF (free/busy) \u2192\n[Free] Create Calendar Event \u2192 Create Zoom \u2192 Email confirmation \u2192 Slack notify\n[Busy] Email unavailability\n\nNotes\n\nKeep all user-editable variables in the Set nodes for easy maintenance.\n\nDate handling assumes Asia/Tokyo input and converts to ISO for API calls.\n\nNo hardcoded credentials inside HTTP nodes; store secrets via Credentials."
},
"typeVersion": 1
},
{
"id": "5eb1dc05-5c0f-44a0-9000-d4abdd74a981",
"name": "Sticky: Merge Form Data1",
"type": "n8n-nodes-base.stickyNote",
"position": [
80,
384
],
"parameters": {
"color": "white",
"width": 256,
"height": 176,
"content": "Purpose: Entry point for bookings. Receives a POST payload from your form (name, email, date, time).\nOutput: Raw form fields under body.* used downstream."
},
"typeVersion": 1
},
{
"id": "967bcc58-fc07-4e4c-8b17-5f2a99f9287f",
"name": "Sticky: Workflow Configuration1",
"type": "n8n-nodes-base.stickyNote",
"position": [
400,
384
],
"parameters": {
"color": "white",
"width": 272,
"height": 176,
"content": "Purpose: Normalizes/forwards webhook data to keep a single item moving through the flow.\nTip: Use this as a \u201cbuffer\u201d if you ever add parallel inputs later."
},
"typeVersion": 1
},
{
"id": "663ecdf9-6f9d-481c-abe6-e7d8b3c34021",
"name": "Sticky: Extract Booking Details1",
"type": "n8n-nodes-base.stickyNote",
"position": [
736,
384
],
"parameters": {
"color": "white",
"width": 288,
"height": 176,
"content": "Purpose: Central place for editable constants (e.g., calendarId, slackChannel, teammateEmail).\nWhy: Makes the template plug-and-play\u2014update values here instead of hunting through nodes."
},
"typeVersion": 1
},
{
"id": "c12bee38-9494-43b7-9961-2e4971a92316",
"name": "Sticky: Check Calendar Availability1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1088,
384
],
"parameters": {
"color": "white",
"width": 272,
"height": 176,
"content": "Purpose: Maps form fields to clean variables: customerName, customerEmail, bookingDate, bookingTime.\nAlso: Builds bookingStartISO and bookingEndISO (60-min duration) using the submitted local time (JST) \u2192 ISO strings."
},
"typeVersion": 1
},
{
"id": "b58f33ab-ad60-4a98-9354-3ed1a1aeab72",
"name": "Sticky: Is Time Slot Available?1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1424,
384
],
"parameters": {
"color": "white",
"width": 256,
"height": 176,
"content": "Purpose: Queries the target calendar for events overlapping bookingStartISO\u2013bookingEndISO.\nBehavior: Returns an empty list when the slot is free; non-empty when it\u2019s taken."
},
"typeVersion": 1
},
{
"id": "b0b7376c-f552-4ce9-bd31-33919ba04618",
"name": "Sticky: Create Calendar Event1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1744,
384
],
"parameters": {
"color": "white",
"width": 256,
"height": 176,
"content": "Purpose: Branches on availability.\nTrue (empty result): Slot is free \u2192 proceed to create the event.\nFalse (has events): Slot is busy \u2192 send \u201cunavailable\u201d email."
},
"typeVersion": 1
},
{
"id": "bb03b52c-ddc4-4896-9016-6d01ab6b68ec",
"name": "Sticky: Create Zoom Meeting1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2000,
16
],
"parameters": {
"color": "white",
"width": 272,
"content": "Purpose: Books the time on Google Calendar with the guest as an attendee.\nFields: Summary includes guest name; Description includes name + email for quick context."
},
"typeVersion": 1
},
{
"id": "73736740-501f-4814-9722-e8576e2dd21f",
"name": "Sticky: Send Confirmation Email1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2336,
16
],
"parameters": {
"color": "white",
"content": "Purpose: Creates a Zoom meeting for the confirmed slot.\nTiming: Uses the booking start time and a 60-minute duration.\nOutput: Provides join_url used by Email/Slack steps."
},
"typeVersion": 1
},
{
"id": "6e9c22c3-0b31-47f9-ab96-4476e501175d",
"name": "Sticky: Notify Teammate on Slack1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2640,
16
],
"parameters": {
"color": "white",
"width": 256,
"content": "Purpose: Sends a confirmation to the guest with local (Japan) date/time and the Zoom link.\nSubject/Body: Human-readable datetime via toLocaleString('ja-JP', { timeZone: 'Asia/Tokyo' })."
},
"typeVersion": 1
},
{
"id": "b9aa000c-63a2-44b1-800a-c041a1582f64",
"name": "Sticky: Send Unavailable Email1",
"type": "n8n-nodes-base.stickyNote",
"position": [
2064,
672
],
"parameters": {
"color": "white",
"width": 256,
"content": "Purpose: Notifies the guest when the requested slot is already taken and asks them to rebook another time."
},
"typeVersion": 1
},
{
"id": "3904238d-39eb-40f0-879f-3f17e1afd303",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
2960,
16
],
"parameters": {
"content": "Purpose: Posts a concise booking summary to your specified Slack channel.\nIncludes: Guest name/email, localized date/time, and Zoom join_url."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "31e08b0e-50a9-485b-b16c-856d2311d0f5",
"connections": {
"Merge Form Data1": {
"main": [
[
{
"node": "Workflow Configuration1",
"type": "main",
"index": 0
}
]
]
},
"Create Zoom Meeting1": {
"main": [
[
{
"node": "Send Confirmation Email1",
"type": "main",
"index": 0
}
]
]
},
"Google Forms Webhook1": {
"main": [
[
{
"node": "Merge Form Data1",
"type": "main",
"index": 0
}
]
]
},
"Create Calendar Event1": {
"main": [
[
{
"node": "Create Zoom Meeting1",
"type": "main",
"index": 0
}
]
]
},
"Workflow Configuration1": {
"main": [
[
{
"node": "Extract Booking Details1",
"type": "main",
"index": 0
}
]
]
},
"Extract Booking Details1": {
"main": [
[
{
"node": "Check Calendar Availability1",
"type": "main",
"index": 0
}
]
]
},
"Is Time Slot Available?1": {
"main": [
[
{
"node": "Create Calendar Event1",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Unavailable Email1",
"type": "main",
"index": 0
}
]
]
},
"Send Confirmation Email1": {
"main": [
[
{
"node": "Notify Teammate on Slack1",
"type": "main",
"index": 0
}
]
]
},
"Check Calendar Availability1": {
"main": [
[
{
"node": "Is Time Slot Available?1",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Who’s it for
Source: https://n8n.io/workflows/10104/ — 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.
Receive booking requests via webhook with automatic validation, duplicate detection, availability checking, confirmation emails, Google Calendar sync, and Slack notifications.
This template is designed for freelancers, small businesses, and finance teams who need automated invoice management with intelligent payment follow-ups. Perfect for service providers, agencies, or an
Automate short-term trading research by generating high-quality trade ideas using MCP (Market Context Protocol) signals and AI-powered analysis. 📈🤖 This workflow evaluates market context, catalysts, m
Automate building visitor management with secure verification, digital entry passes, and real-time security notifications.
This workflow monitors partner API usage in real time and triggers alerts based on usage thresholds. It validates incoming data, calculates usage percentage and routes actions using a Switch node. Sla