AutomationFlowsGeneral › Book Calendar Appointments with Availability Checks in Google Calendar

Book Calendar Appointments with Availability Checks in Google Calendar

ByMD Faizan Uzzaman @buildwithfaizan on n8n.io

This workflow is triggered by another n8n workflow to verify a requested appointment slot and, if available, books a 30‑minute event in Google Calendar, returning a booked/unbooked response with formatted date/time details. Receives appointment details (name, phone, service…

Event trigger★★★★☆ complexity17 nodesExecute Workflow TriggerGoogle Calendar
General Trigger: Event Nodes: 17 Complexity: ★★★★☆ Added:
Book Calendar Appointments with Availability Checks in Google Calendar — n8n workflow card showing Execute Workflow Trigger, Google Calendar integration

This workflow corresponds to n8n.io template #16820 — we link there as the canonical source.

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 →

Download .json
{
  "id": "W2i8H6M2VChQVAOJ",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Book Appointment open-source-01",
  "tags": [
    {
      "id": "oufe6ROEtWIl02g4",
      "name": "open-source-01",
      "createdAt": "2026-06-25T18:55:08.441Z",
      "updatedAt": "2026-06-25T18:55:08.441Z"
    }
  ],
  "nodes": [
    {
      "id": "65ab2398-c878-450c-85a4-99d64db98ed6",
      "name": "When Executed by Another Workflow",
      "type": "n8n-nodes-base.executeWorkflowTrigger",
      "position": [
        1904,
        1648
      ],
      "parameters": {
        "workflowInputs": {
          "values": [
            {
              "name": "name"
            },
            {
              "name": "service_type"
            },
            {
              "name": "preferred_date"
            },
            {
              "name": "preferred_time"
            },
            {
              "name": "phone"
            }
          ]
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "8059396b-5183-48e5-a8b2-1f55de956ac8",
      "name": "Sticky Note9",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2528,
        1280
      ],
      "parameters": {
        "color": 7,
        "width": 336,
        "height": 272,
        "content": "## Create calendar event\n\nBuilds the appointment start and end values, then creates the booking in Google Calendar when the slot is available."
      },
      "typeVersion": 1
    },
    {
      "id": "c5be18b9-8a75-47c4-a00d-46126e7e0947",
      "name": "Sticky Note10",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3184,
        1104
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 336,
        "content": "## Success and background tasks\n\nTop-right output cluster that starts a background workflow after booking and prepares the successful booked response with appointment details."
      },
      "typeVersion": 1
    },
    {
      "id": "82bec1ca-a37d-49ee-bd1a-971ae08fe0a1",
      "name": "Sticky Note11",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3200,
        1712
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 384,
        "content": "## Booking error handling\n\nRight-side error cluster that invokes an error workflow and prepares an error response if event creation fails or needs exception handling."
      },
      "typeVersion": 1
    },
    {
      "id": "84a212e6-5108-4f0d-ac29-857a4197f415",
      "name": "Sticky Note12",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        1216
      ],
      "parameters": {
        "color": 4,
        "width": 832,
        "height": 816,
        "content": "## Book Appointment \n\n### How it works\n\nThis workflow is called by another workflow to book an appointment. It checks whether the requested slot is available, returns an unavailable response if not, and otherwise creates the Google Calendar event. After event creation, it emits success details, can start a background workflow, and routes errors to dedicated error responses or an error workflow.\n\n### Setup steps\n\n- Configure the Execute Workflow Trigger so the parent workflow sends the required appointment fields, such as name, service type, preferred date, and slot details.\n- Set up the referenced sub-workflows: \"Check Slot Availability\", \"Background Workflow\", and \"Error Workflow\".\n- Connect Google Calendar credentials in the \"Create an event\" node and select the target calendar.\n- Verify the Set nodes map the expected output fields for booked status, appointment metadata, and error messages.\n\n### Customization\n\nAdjust the slot start/end calculation, calendar event fields, and returned success or error payloads to match your booking rules and client-facing response format."
      },
      "typeVersion": 1
    },
    {
      "id": "ae9342d4-7fa2-4f09-96d3-3344774389f0",
      "name": "Sticky Note13",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1792,
        1392
      ],
      "parameters": {
        "color": 7,
        "width": 688,
        "height": 240,
        "content": "## Receive and check slot\n\nEntry cluster that receives execution from another workflow, calls the slot-availability sub-workflow, and evaluates the availability result."
      },
      "typeVersion": 1
    },
    {
      "id": "3abcb585-d5bb-4a0d-b16b-1bf76707e486",
      "name": "Sticky Note14",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2640,
        1920
      ],
      "parameters": {
        "color": 7,
        "width": 336,
        "height": 272,
        "content": "## Unavailable slot response\n\nReturns a booked=false style response with an error when the requested appointment slot is not available."
      },
      "typeVersion": 1
    },
    {
      "id": "2378d322-0ab3-447f-8612-321dc1b07476",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3600,
        1216
      ],
      "parameters": {
        "width": 944,
        "height": 880,
        "content": "## See it in action\n\nThis workflow powers appointment booking inside Aria, a live AI \nvoice receptionist that books, reschedules, and cancels real \nappointments by phone. Watch the full call below.\n\n@[youtube](OF-5d0pQ7Zo)\n\nNote: this is one of 5 sub-workflows in the Aria system \u2014 \nbooking, canceling, rescheduling, checking availability, and \nfinding alternate slots each run as a separate workflow, called \nvia MCP tools. Build each one to match your own calendar/CRM \nsetup \u2014 or watch the video to see the full pattern working end \nto end."
      },
      "typeVersion": 1
    },
    {
      "id": "5b7e0160-2625-448d-8b11-ed2e39fb0819",
      "name": "Check Slot Availability",
      "type": "n8n-nodes-base.executeWorkflow",
      "position": [
        2128,
        1648
      ],
      "parameters": {
        "options": {},
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "AQhWv6s3ouxoTLPI",
          "cachedResultUrl": "/workflow/AQhWv6s3ouxoTLPI",
          "cachedResultName": "Check Slot Availability"
        },
        "workflowInputs": {
          "value": {
            "name": "={{ $json.name }}",
            "service_type": "={{ $json.service_type }}",
            "preferred_date": "={{ $json.preferred_date }}",
            "preferred_time": "={{ $json.preferred_time }}"
          },
          "schema": [
            {
              "id": "name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "service_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "service_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "76cdb1d4-ba60-4de1-9149-e1433fbcacc9",
      "name": "Run Background Workflow",
      "type": "n8n-nodes-base.executeWorkflow",
      "disabled": true,
      "position": [
        3024,
        1264
      ],
      "parameters": {
        "options": {
          "waitForSubWorkflow": false
        },
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "hEOycKblp9Yg7ath",
          "cachedResultUrl": "/workflow/hEOycKblp9Yg7ath",
          "cachedResultName": "Background Workflow"
        },
        "workflowInputs": {
          "value": {
            "name": "={{ $('When Executed by Another Workflow').item.json.name }}",
            "phone": "={{ $('When Executed by Another Workflow').item.json.phone }}",
            "event_id": "={{ $json.id }}",
            "action_type": "Book",
            "service_type": "={{ $('When Executed by Another Workflow').item.json.service_type }}",
            "preferred_date": "={{ $('When Executed by Another Workflow').item.json.preferred_date }}",
            "preferred_time": "={{ $('When Executed by Another Workflow').item.json.preferred_time }}"
          },
          "schema": [
            {
              "id": "name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "service_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "service_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "event_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "event_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "action_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "action_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "81cda2b4-bde5-43a1-bb77-c22b14d54e84",
      "name": "Execute Error Workflow",
      "type": "n8n-nodes-base.executeWorkflow",
      "disabled": true,
      "position": [
        3024,
        1648
      ],
      "parameters": {
        "options": {
          "waitForSubWorkflow": false
        },
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "bQdno8qQgpKWbiDE",
          "cachedResultUrl": "/workflow/bQdno8qQgpKWbiDE",
          "cachedResultName": "Error Workflow"
        },
        "workflowInputs": {
          "value": {
            "resolved": "No",
            "node_name": "={{ $json.error }}",
            "timestamp": "={{ $now.toISO() }}",
            "error_type": "={{ $json.error }}",
            "execution_id": "={{ $execution.id }}",
            "patient_name": "={{ $('When Executed by Another Workflow').item.json.name }}",
            "service_type": "={{ $('When Executed by Another Workflow').item.json.service_type }}",
            "patient_phone": "={{ $('When Executed by Another Workflow').item.json.phone }}",
            "workflow_name": "={{ $workflow.name }}",
            "preferred_date": "={{ $('When Executed by Another Workflow').item.json.preferred_date }}",
            "preferred_time": "={{ $('When Executed by Another Workflow').item.json.preferred_time }}"
          },
          "schema": [
            {
              "id": "workflow_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "workflow_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "node_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "node_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "error_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "error_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patient_name",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "patient_name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "patient_phone",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "patient_phone",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "service_type",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "service_type",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_date",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "preferred_time",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "preferred_time",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "execution_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "execution_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "resolved",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "resolved",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": true
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e71209b7-ae6a-49ea-9ecd-531b81fc101f",
      "name": "Check Slot Availability Status",
      "type": "n8n-nodes-base.if",
      "position": [
        2352,
        1648
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "7c9e95fb-6367-444f-8c8b-6a0acd096dff",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.available === true }}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "d1eefcfb-acc0-4cab-b451-d06db5cf6a61",
      "name": "Set Slot Start and End",
      "type": "n8n-nodes-base.set",
      "position": [
        2576,
        1552
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "fd936412-e8ed-45b2-9842-9fccc73da593",
              "name": "start",
              "type": "string",
              "value": "={{ $('When Executed by Another Workflow').item.json.preferred_date }}T{{ $('When Executed by Another Workflow').item.json.preferred_time }}"
            },
            {
              "id": "3cda2a1b-6a47-452e-9840-93fffbda80f3",
              "name": "end",
              "type": "string",
              "value": "={{ $('When Executed by Another Workflow').item.json.preferred_date }}T{{\nDateTime\n  .fromFormat(\n    $('When Executed by Another Workflow').first().json.preferred_time,\n    'HH:mm'\n  )\n  .plus({ minutes: 30 })\n  .toFormat('HH:mm')\n}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "ab5e9c27-765e-4259-99d4-5ed4cdd57c85",
      "name": "Set Availability Error",
      "type": "n8n-nodes-base.set",
      "position": [
        2576,
        1744
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a978fa3a-1de7-4149-8740-736df1b7f1a6",
              "name": "booked",
              "type": "boolean",
              "value": false
            },
            {
              "id": "0916d5f0-3c63-411a-953b-ac888d3c316a",
              "name": "error",
              "type": "string",
              "value": "slot_unavailable"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "df6033a0-ee17-480e-a3ff-362c1f4a10d3",
      "name": "Create Google Calendar Event",
      "type": "n8n-nodes-base.googleCalendar",
      "onError": "continueErrorOutput",
      "position": [
        2800,
        1552
      ],
      "parameters": {
        "end": "={{ $json.end }}",
        "start": "={{ $json.start }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "user@example.com",
          "cachedResultName": "user@example.com"
        },
        "additionalFields": {
          "summary": "={{ $('When Executed by Another Workflow').item.json.service_type }} - {{ $('When Executed by Another Workflow').item.json.name }}",
          "attendees": [],
          "description": "={{ $('When Executed by Another Workflow').item.json.phone }}"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "retryOnFail": true,
      "typeVersion": 1.3,
      "waitBetweenTries": 1000
    },
    {
      "id": "a4120312-e7a5-49bf-a2cc-d02df82c4d60",
      "name": "Set Booking Details",
      "type": "n8n-nodes-base.set",
      "position": [
        3024,
        1456
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "320ac51e-c6c0-491e-af7c-690ca9e9ebad",
              "name": "booked",
              "type": "boolean",
              "value": true
            },
            {
              "id": "be46c811-6817-49ec-b91d-9595cc592c8f",
              "name": "name",
              "type": "string",
              "value": "={{ $('When Executed by Another Workflow').item.json.name }}"
            },
            {
              "id": "67c137ed-cda6-468a-b072-65b032c3214e",
              "name": "service_type",
              "type": "string",
              "value": "={{ $('When Executed by Another Workflow').item.json.service_type }}"
            },
            {
              "id": "3a7717f0-f49f-477d-a331-015c08c0c4b3",
              "name": "preferred_date",
              "type": "string",
              "value": "={{\nDateTime\n  .fromISO($('When Executed by Another Workflow').item.json.preferred_date)\n  .toFormat('dd LLL yyyy')\n}}"
            },
            {
              "id": "d7fc5978-8bd3-4941-9bf2-2e4d5508c08c",
              "name": "preferred_time",
              "type": "string",
              "value": "={{ DateTime   .fromFormat($('When Executed by Another Workflow').item.json.preferred_time, 'HH:mm')   .toFormat('hh:mm a') }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "2029ef6b-d15a-414e-98f5-ba6dc92f7d69",
      "name": "Set Error Details",
      "type": "n8n-nodes-base.set",
      "position": [
        3024,
        1840
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a978fa3a-1de7-4149-8740-736df1b7f1a6",
              "name": "booked",
              "type": "boolean",
              "value": false
            },
            {
              "id": "0916d5f0-3c63-411a-953b-ac888d3c316a",
              "name": "error",
              "type": "string",
              "value": "calendar_unavailable"
            }
          ]
        }
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "timezone": "America/Chicago",
    "binaryMode": "separate",
    "callerPolicy": "workflowsFromSameOwner",
    "errorWorkflow": "bQdno8qQgpKWbiDE",
    "timeSavedMode": "fixed",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "8b16fb2f-13a9-46c5-b82c-637af760ffda",
  "connections": {
    "Set Slot Start and End": {
      "main": [
        [
          {
            "node": "Create Google Calendar Event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Slot Availability": {
      "main": [
        [
          {
            "node": "Check Slot Availability Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Google Calendar Event": {
      "main": [
        [
          {
            "node": "Set Booking Details",
            "type": "main",
            "index": 0
          },
          {
            "node": "Run Background Workflow",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Error Details",
            "type": "main",
            "index": 0
          },
          {
            "node": "Execute Error Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Slot Availability Status": {
      "main": [
        [
          {
            "node": "Set Slot Start and End",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Availability Error",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "When Executed by Another Workflow": {
      "main": [
        [
          {
            "node": "Check Slot Availability",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow is triggered by another n8n workflow to verify a requested appointment slot and, if available, books a 30‑minute event in Google Calendar, returning a booked/unbooked response with formatted date/time details. Receives appointment details (name, phone, service…

Source: https://n8n.io/workflows/16820/ — original creator credit. Request a take-down →

More General workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

General

Reagendamiento. Uses executeWorkflowTrigger, redis, n8n-nodes-evolution-api, dataTable. Event-driven trigger; 73 nodes.

Execute Workflow Trigger, Redis, N8N Nodes Evolution Api +2
General

Agendamiento. Uses n8n-nodes-evolution-api, redis, dataTable, executeWorkflowTrigger. Event-driven trigger; 60 nodes.

N8N Nodes Evolution Api, Redis, Data Table +2
General

Cancelacion. Uses executeWorkflowTrigger, redis, n8n-nodes-evolution-api, dataTable. Event-driven trigger; 36 nodes.

Execute Workflow Trigger, Redis, N8N Nodes Evolution Api +2
General

chatbot Sub-Workflow 1. Uses googleCalendar, executeWorkflowTrigger. Event-driven trigger; 5 nodes.

Google Calendar, Execute Workflow Trigger
General

This n8n template implements an MCP (Model Context Protocol)-compliant module for managing Google Calendar events in a context-aware, conflict-free manner.

Mcp Trigger, Execute Workflow Trigger, Tool Workflow +2