This workflow corresponds to n8n.io template #12419 — 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": "VDszM3EhszJTQHuk",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Schedule appointments using Google Calendar and Gmail",
"tags": [],
"nodes": [
{
"id": "29aab469-1f9f-452d-8141-5059af69fffc",
"name": "Receive appointment request",
"type": "n8n-nodes-base.webhook",
"position": [
160,
352
],
"parameters": {
"path": "appointment-request",
"options": {
"rawBody": false,
"ignoreBots": true,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2.1
},
{
"id": "2bf0d6da-e840-4599-b793-8fbf23babcfd",
"name": "Format appointment data",
"type": "n8n-nodes-base.set",
"position": [
384,
352
],
"parameters": {
"include": "selected",
"options": {
"dotNotation": false
},
"assignments": {
"assignments": [
{
"id": "0e263997-2422-4470-a2d8-75e948d9263b",
"name": "name",
"type": "string",
"value": "={{ $json.body.name }}"
},
{
"id": "7ada9c8f-f6bb-43c7-9f85-2a0f0a647dc4",
"name": "company",
"type": "string",
"value": "={{ $json.body.organization }}"
},
{
"id": "ef270c99-ac86-4f4e-b0e0-ab90954081d9",
"name": "email",
"type": "string",
"value": "={{ $json.body.email }}"
},
{
"id": "7dd61002-b455-4e00-997c-8bcdc6fb55c4",
"name": "phone",
"type": "string",
"value": "={{ $json.body.phone }}"
},
{
"id": "5273013e-ad6f-4ae0-ac2e-4a5de27d8bf0",
"name": "appointmentStartDate",
"type": "string",
"value": "={{ $json.body.appointmentDateTime }}"
},
{
"id": "0ee4cc66-e4d5-429a-81f6-fe14371589be",
"name": "appointmentEndDate",
"type": "string",
"value": "={{ DateTime.fromISO($json.body.appointmentDateTime).setZone('Asia/Kolkata').plus(1, 'hours') }}"
},
{
"id": "da4a897b-96f5-4008-a7cc-68f5dfa6d4a5",
"name": "message",
"type": "string",
"value": "={{$json.body.optionalMessage }}"
}
]
},
"includeFields": "body",
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "a0c4e8f2-ed59-466e-b020-13b4c763894d",
"name": "Check Availability",
"type": "n8n-nodes-base.googleCalendar",
"onError": "continueRegularOutput",
"position": [
608,
352
],
"parameters": {
"options": {
"outputFormat": "availability"
},
"timeMax": "={{ $json.appointmentEndDate }}",
"timeMin": "={{ $json.appointmentStartDate }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "Primary"
},
"resource": "calendar"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"notesInFlow": false,
"typeVersion": 1.3,
"alwaysOutputData": true
},
{
"id": "8ae03768-acf8-4748-9d5e-804d2cc7fad3",
"name": "Is approved?",
"type": "n8n-nodes-base.if",
"position": [
1504,
256
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "2b5cc36c-b8b5-4a20-9fa7-499fa8c4a939",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{$json.data.approved }}",
"rightValue": "true"
}
]
}
},
"executeOnce": false,
"typeVersion": 2.2,
"alwaysOutputData": false
},
{
"id": "16e45971-fc70-4478-ac00-c5ce0eb66f48",
"name": "Appointment Failed",
"type": "n8n-nodes-base.gmail",
"position": [
1728,
352
],
"parameters": {
"sendTo": "={{ $('Format appointment data').item.json.body.email}}",
"message": "=Hi,{{ $('Format appointment data').item.json.name }}\n\nThe appointment could not be scheduled for the requested date and time.\n\nReason: The appointment was rejected by the approver.\n\nPlease reschedule your appointment or contact us directly by replying to this email.\n\nApologies for the inconvenience caused.\n\nRegards,\n<insert-your-org-name>\n",
"options": {
"bccList": "info@example.com",
"appendAttribution": false
},
"subject": "=RE: Appointment request with <insert-your-name> at {{ DateTime.fromISO($('Format appointment data').item.json.appointmentStartDate).toFormat('cccc, MMMM dd @ hh:mm a') }}\n\n",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "22a1d4e8-f83a-4e46-a883-7880c5968bbb",
"name": "Book Appointment",
"type": "n8n-nodes-base.googleCalendar",
"position": [
1728,
160
],
"parameters": {
"end": "={{ $('Format appointment data').item.json.appointmentEndDate }}",
"start": "={{ $('Format appointment data').item.json.appointmentStartDate }}",
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "Primary"
},
"additionalFields": {
"color": "11",
"summary": "=Project discovery meet with {{ $('Format appointment data').item.json.body.name }} at {{ DateTime.fromISO($('Format appointment data').item.json.appointmentStartDate).toLocaleString(DateTime.DATETIME_MED) }}",
"attendees": [
"={{ $('Format appointment data').item.json.email }}",
"info@example.com"
],
"description": "=Hi {{$('Format appointment data').item.json.name}}\n\nYour appointment is confirmed, please find the attached event/meeting details.\n\nRegards,\n<insert-your-org-name>",
"sendUpdates": "all",
"conferenceDataUi": {
"conferenceDataValues": {
"conferenceSolution": "hangoutsMeet"
}
},
"guestsCanSeeOtherGuests": true
}
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "a3c0ede0-ee2a-4ef8-a8d4-4badeb6ee97d",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
832,
352
],
"parameters": {
"options": {
"responseCode": 200,
"responseHeaders": {
"entries": [
{
"name": "Content-Type",
"value": "application/json"
}
]
}
},
"respondWith": "json",
"responseBody": "={\n \"success\": \"{{ $json.available }}\",\n \"message\": \"{{ $json.available ? 'Thank you for your interest, Meeting details will be emailed shortly once approved.' : 'We cannot confirm the appointment at this time, Please try again with a different day/time-slot.' }}\"\n}"
},
"typeVersion": 1.4
},
{
"id": "a05231fc-9c65-4732-8e73-ecb5fb51cf19",
"name": "Is Slot Available?",
"type": "n8n-nodes-base.if",
"position": [
1056,
352
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ca33df49-543c-4fc8-b357-47c83348871d",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $('Check Availability').item.json?.available }}",
"rightValue": "true"
}
]
}
},
"typeVersion": 2.2,
"alwaysOutputData": false
},
{
"id": "b7ec4e94-48e8-41d0-ae3f-3cfce5c88388",
"name": "Get Approval (HR) [1 hour wait]",
"type": "n8n-nodes-base.gmail",
"onError": "continueRegularOutput",
"position": [
1280,
256
],
"parameters": {
"sendTo": "info@example.com",
"message": "=Hi <insert-your-name>,\n{{ $('Format appointment data').item.json.body.name }} has requested to schedule an appointment with you at {{ DateTime.fromISO($('Format appointment data').item.json.appointmentStartDate).toFormat('cccc, MMMM dd @ hh:mm a') }}. \nHere are the customer information:\nName: {{ $('Format appointment data').item.json.name }}\nCompany: {{ $('Format appointment data').item.json.company }}\nContact Email: {{ $('Format appointment data').item.json.email }}\nMessage: {{ $('Format appointment data').item.json.message }}\n",
"options": {
"appendAttribution": false
},
"subject": "Approval Required",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double"
}
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"alwaysOutputData": false
},
{
"id": "42b3486c-f2d7-4336-839d-1789f7bae261",
"name": "End - Slot Busy",
"type": "n8n-nodes-base.noOp",
"position": [
1280,
448
],
"parameters": {},
"typeVersion": 1
},
{
"id": "fb697393-26eb-4bd2-8fe9-69566d1eb088",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
-160
],
"parameters": {
"width": 672,
"height": 360,
"content": "## Smart Appointment Scheduler\n\n## How it works\n1. Receives appointment request via Webhook.\n2. Checks Google Calendar availability.\n3. If free, requests HR approval via Gmail.\n4. Sends confirmation or rejection email.\n\n## Setup steps\n1. Configure Google Calendar and Gmail credentials.\n2. Update Timezone in workflow settings.\n3. Send POST request with JSON body."
},
"typeVersion": 1
},
{
"id": "277da4b1-0ee9-49d9-8be6-eabfbc4aec17",
"name": "Sticky Note Group 1",
"type": "n8n-nodes-base.stickyNote",
"position": [
105,
248
],
"parameters": {
"color": 7,
"width": 430,
"height": 264,
"content": "## Step 1: Ingestion\nReceives and formats the request."
},
"typeVersion": 1
},
{
"id": "e9898219-fcaa-4c86-bd80-d28bbc1864a0",
"name": "Sticky Note Group 2",
"type": "n8n-nodes-base.stickyNote",
"position": [
572,
248
],
"parameters": {
"color": 7,
"width": 616,
"height": 264,
"content": "## Step 2: Availability\nChecks calendar availability and returns immediate response."
},
"typeVersion": 1
},
{
"id": "ac7ca2be-1159-4311-bc12-e495d4a5fea3",
"name": "Sticky Note Group 3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1244,
126
],
"parameters": {
"color": 7,
"width": 616,
"height": 482,
"content": "## Step 3: Approval & Booking\nHandles manual approval and booking."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"timezone": "Asia/Kolkata",
"callerPolicy": "workflowsFromSameOwner",
"timeSavedMode": "fixed",
"availableInMCP": false,
"executionOrder": "v1",
"executionTimeout": -1
},
"versionId": "480e31a5-f443-4925-b0ed-70ec7f2c80d8",
"connections": {
"Is approved?": {
"main": [
[
{
"node": "Book Appointment",
"type": "main",
"index": 0
}
],
[
{
"node": "Appointment Failed",
"type": "main",
"index": 0
}
]
]
},
"Check Availability": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Is Slot Available?": {
"main": [
[
{
"node": "Get Approval (HR) [1 hour wait]",
"type": "main",
"index": 0
}
],
[
{
"node": "End - Slot Busy",
"type": "main",
"index": 0
}
]
]
},
"Respond to Webhook": {
"main": [
[
{
"node": "Is Slot Available?",
"type": "main",
"index": 0
}
]
]
},
"Format appointment data": {
"main": [
[
{
"node": "Check Availability",
"type": "main",
"index": 0
}
]
]
},
"Receive appointment request": {
"main": [
[
{
"node": "Format appointment data",
"type": "main",
"index": 0
}
]
]
},
"Get Approval (HR) [1 hour wait]": {
"main": [
[
{
"node": "Is approved?",
"type": "main",
"index": 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.
gmailOAuth2googleCalendarOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Tired of automated booking tools cluttering your calendar with spam or overlapping meetings? SyncPoint is a “Smart Gatekeeper” that checks your availability and asks for your manual approval via email before a single event is booked. Once approved, it schedules the meeting…
Source: https://n8n.io/workflows/12419/ — 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.
Complete Calendly automation that handles confirmations, cancellations and reschedules in a single workflow. WHAT IT DOES:
Automate your GoHighLevel (GHL) client onboarding process from the moment a deal is marked as “Won.” This workflow seamlessly generates client folders in Google Drive, duplicates contract and kickoff
This n8n workflow is designed for businesses, consultants, and service providers who want to automate their meeting scheduling process. The workflow creates a seamless booking system that can handle m
This workflow creates a complete appointment booking system — no external scheduling tools needed. It serves a styled HTML booking form via webhook, checks your Google Calendar for availability, and l
Scheduling. Uses googleDocs, googleCalendar, gmail, mySql. Webhook trigger; 10 nodes.