AutomationFlowsAI & RAG › AI Calendar Booking with Google Calendar

AI Calendar Booking with Google Calendar

Original n8n title: Vapi Calendar

Vapi Calendar. Uses agent, googleCalendarTool, toolCalculator, respondToWebhook. Webhook trigger; 11 nodes.

Webhook trigger★★★☆☆ complexityAI-powered11 nodesAgentGoogle Calendar ToolTool CalculatorOpenAI Chat
AI & RAG Trigger: Webhook Nodes: 11 Complexity: ★★★☆☆ AI nodes: yes Added:

This workflow follows the Agent → Google Calendar Tool 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 →

Download .json
{
  "name": "Vapi Calendar",
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "=details: {{ $json.output }}",
        "options": {
          "systemMessage": "=# \ud83c\udfaf Your Role\n\nYou are a smart and reliable calendar assistant. Your job is to manage the user's calendar by **booking**, **checking**, **updating**, and **canceling** appointments. You must follow the correct logic based on the `category` value in the request.\n\n---\n\n## \ud83d\udee0\ufe0f Available Tools\n\n* **Book Appointment**: Use **only** when the category is `new_booking` and the time is confirmed to be available.\n* **Get Appointments**: Use when the category is `check_availability`, or when checking availability before any other action.\n* **Cancel Appointment**: Use **only** when the category is `cancel_appointment` and after retrieving the appointment ID using **Get Appointments**.\n* **Update Appointment**: Use **only** when the category is `update_appointment` and after retrieving the appointment ID using **Get Appointments**.\n\n---\n\n## \u2705 Rules to Follow\n\n* Always turn the user's request into an actionable command.\n\n* Only act based on the `category` value:\n\n  * If `category` is `check_availability`: **Use only Get Appointments. Do not book.**\n  * If `category` is `new_booking`: **Use Get Appointments to check**, then proceed with **Book Appointment** only if time is available.\n  * If `category` is `cancel_appointment`: **Use Get Appointments**, then use **Cancel Appointment** with the correct ID.\n  * If `category` is `update_appointment`: **Use Get Appointments**, then use **Update Appointment** with the correct ID.\n\n* There can only be one appointment per one-hour time slot.\n\n* If the requested time is already booked, respond with: `\"Not Available\"` and suggest **only 2 alternative one-hour time slots** on the same day. Do not book until the client confirms.\n\n* Use the summary: `\"Consultation Appointment\"` for every booking.\n\n* Appointments always involve one participant.\n\n* If no duration is provided, assume the appointment lasts exactly **one hour**.\n\n* Never assume availability \u2014 always confirm it first using **Get Appointments**.\n\n---\n\n* Convert vague time frames like \"tomorrow at 4 PM\" into precise ISO 8601 timestamps using `{{ $now }}` as reference.\n\n---\n\n## \ud83d\udd01 Example Flow Summary\n\n1. Receive a request, e.g., *\"Book me an appointment tomorrow at 4 PM\"*\n2. Check the `category` field:\n\n   * If `category` is `check_availability`: Use **Get Appointments** with the provided day and time. Do not proceed with booking.\n   * If `category` is `new_booking`: Use **Get Appointments** to verify availability.\n\n     * If the time is available: Proceed with **Book Appointment**.\n     * If the time is not available: Respond with \"Not Available\" and suggest 2 alternative time slots.\n     * Wait for confirmation before proceeding with the booking.\n   * If `category` is `cancel_appointment`: Use **Get Appointments** to retrieve the appointment ID, then call **Cancel Appointment**.\n   * If `category` is `update_appointment`: Use **Get Appointments** to retrieve the appointment ID, then call **Update Appointment** with the new time and date.\n\n---\n\n### \ud83e\ude9c Keep It Clean\n\n* Never guess or make assumptions.\n* Follow tool logic strictly by category.\n* Do not skip required steps or bypass availability checks.\n* Do not return any links or url\n\n---\n\n## \ud83d\udd52 Date & Time Context\n\n* Treat the following as the **current date and time: `{{ $now }}`**\n* One appointment per hour only.\n"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.8,
      "position": [
        -20,
        100
      ],
      "id": "0f6fe2b8-0fc1-4520-b94e-5092fa99b1d2",
      "name": "Calendar Agent"
    },
    {
      "parameters": {
        "calendar": {
          "__rl": true,
          "value": "e65463fc466fd521dc1ecc1964b4d6dbac77710e2a00f0a73b597f41477d9def@group.calendar.google.com",
          "mode": "list",
          "cachedResultName": "AI Agent"
        },
        "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', ``, 'string') }}",
        "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', ``, 'string') }}",
        "additionalFields": {
          "attendees": [
            "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Attendees', ``, 'string') }}"
          ],
          "summary": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Summary', ``, 'string') }}"
        }
      },
      "type": "n8n-nodes-base.googleCalendarTool",
      "typeVersion": 1.3,
      "position": [
        20,
        320
      ],
      "id": "da016177-45dd-4c95-98a4-4578a1e08b40",
      "name": "Book Appointment",
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "calendar": {
          "__rl": true,
          "value": "e65463fc466fd521dc1ecc1964b4d6dbac77710e2a00f0a73b597f41477d9def@group.calendar.google.com",
          "mode": "list",
          "cachedResultName": "AI Agent"
        },
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
        "updateFields": {
          "end": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('End', ``, 'string') }}",
          "start": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Start', ``, 'string') }}"
        }
      },
      "type": "n8n-nodes-base.googleCalendarTool",
      "typeVersion": 1.3,
      "position": [
        200,
        320
      ],
      "id": "bd5549bf-c1ce-454a-9643-43d1af20e782",
      "name": "Update Appointment",
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "getAll",
        "calendar": {
          "__rl": true,
          "value": "e65463fc466fd521dc1ecc1964b4d6dbac77710e2a00f0a73b597f41477d9def@group.calendar.google.com",
          "mode": "list",
          "cachedResultName": "AI Agent"
        },
        "returnAll": true,
        "timeMax": "={{ $now.plus({ week: 24 }) }}",
        "options": {
          "fields": "items(id,summary,start,end,attendees)"
        }
      },
      "type": "n8n-nodes-base.googleCalendarTool",
      "typeVersion": 1.3,
      "position": [
        -140,
        320
      ],
      "id": "3e1adcad-39ae-41da-b52b-f9a8e52715ee",
      "name": "Get Appointments",
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "delete",
        "calendar": {
          "__rl": true,
          "value": "e65463fc466fd521dc1ecc1964b4d6dbac77710e2a00f0a73b597f41477d9def@group.calendar.google.com",
          "mode": "list",
          "cachedResultName": "AI Agent"
        },
        "eventId": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('Event_ID', ``, 'string') }}",
        "options": {}
      },
      "type": "n8n-nodes-base.googleCalendarTool",
      "typeVersion": 1.3,
      "position": [
        380,
        320
      ],
      "id": "3aaae3af-4c21-4775-94c4-59a2a5594b44",
      "name": "Cancel Appointment",
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "smartpulse-agency-receptionist",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -700,
        100
      ],
      "id": "c22ac278-00cb-472b-9103-d658dd3b2754",
      "name": "Webhook"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=details: {{ JSON.stringify($json.body.message.toolCalls[0].function.arguments) }}",
        "options": {
          "systemMessage": "=You are a data-cleaning assistant for an AI scheduling agent.\n\nYour task is to process incoming JSON objects and return a cleaned version with the following:\n\n### \u2705 Requirements\n\n1. **Correct the email**:\n   - Replace words like \"at\" with \"@\", and \"dot\" with \".\"\n   - Remove any extra spaces\n   - Lowercase the entire email\n   - Example: \"J C CatCliff at Gmail dot com\" \u2192 \"jccatliff@gmail.com\"\n\n2. **Convert day and time to ISO 8601 dateTime**:\n   - Combine the natural language day and time fields into a full ISO 8601 datetime string\n   - Output should use **local time in Europe/Berlin** (-04:00), not UTC\n   - Format: YYYY-MM-DDTHH:MM:SS-04:00\n   - Use the current date/time: {{ $now }} and the **Calculator Tool** to compute the correct date and time\n   - Interpret common expressions like \"today\", \"tomorrow\", \"Monday\", etc.\n   - Convert time expressions like \"4 PM\", \"2:30pm\", \"noon\", etc. to 24-hour format\n\n3. **Output the cleaned object**:\n   - Include: category, name, cleaned email, and combined dateTime\n   - Preserve other fields unless they are explicitly replaced\n\n---\n\n### Example Input\n\n{\n  \"category\": \"new_booking\",\n  \"name\": \"Jono Catliff\",\n  \"email\": \"J C CatCliff at Gmail dot com\",\n  \"day\": \"Tomorrow\",\n  \"time\": \"4 PM\"\n}\n\n\n### Example Output\n{\n  \"category\": \"new_booking\",\n  \"name\": \"Jono Catliff\",\n  \"email\": \"jccatliff@gmail.com\",\n  \"dateTime\": \"2024-05-10T16:00:00Z\"\n}\n\n\n## Final Notes\n- Here is the current date/time: {{ $now }}\n\n- Only output the required results in a json, No intros or outros. Nothing extra\n\n"
        }
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.8,
      "position": [
        -480,
        100
      ],
      "id": "013f5271-0692-416d-beb9-541155cd20cb",
      "name": "Helper Agent"
    },
    {
      "parameters": {},
      "type": "@n8n/n8n-nodes-langchain.toolCalculator",
      "typeVersion": 1,
      "position": [
        -320,
        320
      ],
      "id": "751eb038-4956-4be7-b687-7d5e0d9e8171",
      "name": "Calculator"
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={\n  \"results\": [\n    {\n      \"toolCallId\": \"{{ $('Webhook').item.json.body.message.toolCalls[0].id }}\",\n      \"result\": \"Invoice has been successfully sent\"\n    }\n  ]\n}\n ",
        "options": {}
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        340,
        100
      ],
      "id": "2c51303c-9a13-41b1-abe8-e1d9be0061a2",
      "name": "Respond to Webhook"
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        -460,
        320
      ],
      "id": "b300b325-ac47-42d5-b971-aa77ed2c7c29",
      "name": "OpenAI Chat Model",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "typeVersion": 1.2,
      "position": [
        560,
        320
      ],
      "id": "af6f234b-881f-4cd1-89a7-655d38f355d0",
      "name": "OpenAI Chat Model1",
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Book Appointment": {
      "ai_tool": [
        [
          {
            "node": "Calendar Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update Appointment": {
      "ai_tool": [
        [
          {
            "node": "Calendar Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Get Appointments": {
      "ai_tool": [
        [
          {
            "node": "Calendar Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Cancel Appointment": {
      "ai_tool": [
        [
          {
            "node": "Calendar Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Helper Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Helper Agent": {
      "main": [
        [
          {
            "node": "Calendar Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculator": {
      "ai_tool": [
        [
          {
            "node": "Helper Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Calendar Agent": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Helper Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Calendar Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "c99f31fc-5cb7-4e75-b7a6-aa7bed2c77e9",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "KyP9QHaLiXBSRmMg",
  "tags": []
}

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

Vapi Calendar. Uses agent, googleCalendarTool, toolCalculator, respondToWebhook. Webhook trigger; 11 nodes.

Source: https://github.com/Zie619/n8n-workflows — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Flux. Uses lmChatOpenAi, agent, googleGemini, httpRequest. Webhook trigger; 67 nodes.

OpenAI Chat, Agent, Google Gemini +8
AI & RAG

This workflow automates automotive regulatory compliance evaluation by intelligently routing assessments through parallel evaluation paths based on component type. Designed for automotive compliance o

Agent, OpenAI Chat, Output Parser Structured +3
AI & RAG

📝 Description

HTTP Request, OpenAI, Google Docs Tool +6
AI & RAG

✨ Intro This workflow shows how to go beyond a “plain” AI chatbot by:

Telegram, OpenAI, OpenAI Chat +13
AI & RAG

My workflow 15. Uses redis, agent, n8n-nodes-evolution-api, lmChatOpenAi. Webhook trigger; 19 nodes.

Redis, Agent, N8N Nodes Evolution Api +4