{
  "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
          }
        ]
      ]
    }
  }
}