Vapi + Google Calendar: calls book appointments for you
Your phone rings, you’re mid-task, and the lead goes to voicemail. Later, you call back, play email tag, and still end up with a half-filled calendar event and no notes on what they wanted.
This is where Vapi calendar booking hits hardest for a small business owner trying to juggle everything. A marketing lead running campaigns feels it too. Same with an agency ops manager who’s tired of “Did we ever book them?” turning into a Slack thread.
This workflow turns your inbound calls into booked Google Calendar meetings, plus clean Airtable call logs. You’ll see how the automation works, what you need to run it, and what to tweak so it matches your schedule and your brand voice.
How This Automation Works
Here’s the complete workflow you’ll be setting up:
n8n Workflow Template: Vapi + Google Calendar: calls book appointments for you
flowchart LR
subgraph sg0["Flow 1"]
direction LR
n0@{ icon: "mdi:swap-vertical", form: "rounded", label: "Input Arguments", pos: "b", h: 48 }
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/itemLists.svg' width='40' height='40' /></div><br/>Format response"]
n2["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/itemLists.svg' width='40' height='40' /></div><br/>Sort"]
n3["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Available Start Times & Ranges"]
n4["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Flatten Slots"]
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Enrich Date"]
n6@{ icon: "mdi:swap-vertical", form: "rounded", label: "Build Response Payload", pos: "b", h: 48 }
n16["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Getslot_tool"]
n17@{ icon: "mdi:location-exit", form: "rounded", label: "Check Availability", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Response"]
n19@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Check if time is available o..", pos: "b", h: 48 }
n20@{ icon: "mdi:swap-vertical", form: "rounded", label: "Time available (true) & Call..", pos: "b", h: 48 }
n21@{ icon: "mdi:location-exit", form: "rounded", label: "Get All Calendar Events", pos: "b", h: 48 }
n22@{ icon: "mdi:swap-vertical", form: "rounded", label: "Extract start, end and name", pos: "b", h: 48 }
n23["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Convert into Json format for.."]
n24["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Response to Vapi"]
n2 --> n1
n5 --> n6
n16 --> n0
n4 --> n5
n1 --> n3
n0 --> n17
n17 --> n19
n6 --> n23
n21 --> n22
n22 --> n2
n3 --> n4
n20 --> n18
n19 --> n20
n19 --> n21
n23 --> n24
end
subgraph sg1["Flow 2"]
direction LR
n7@{ icon: "mdi:swap-vertical", form: "rounded", label: "Booking Payload", pos: "b", h: 48 }
n8@{ icon: "mdi:swap-vertical", form: "rounded", label: "Success Response", pos: "b", h: 48 }
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Add Friendly Error"]
n10@{ icon: "mdi:swap-vertical", form: "rounded", label: "Error Response", pos: "b", h: 48 }
n11["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Escape Json"]
n12@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Has all information", pos: "b", h: 48 }
n13["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond with Error"]
n14@{ icon: "mdi:swap-vertical", form: "rounded", label: "Build Error Response Payload", pos: "b", h: 48 }
n25["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>bookslots_tool"]
n26@{ icon: "mdi:swap-vertical", form: "rounded", label: "Input Arguments from booking..", pos: "b", h: 48 }
n27["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>Convert time to CST America .."]
n28@{ icon: "mdi:location-exit", form: "rounded", label: "Create Event", pos: "b", h: 48 }
n29["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond to Vapi"]
n30@{ icon: "mdi:swap-horizontal", form: "rounded", label: "If the booking is confirmed ..", pos: "b", h: 48 }
n31@{ icon: "mdi:swap-vertical", form: "rounded", label: "Information to be Saved in A..", pos: "b", h: 48 }
n32["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Logs the confirmed booking d.."]
n11 --> n27
n28 --> n7
n28 --> n9
n10 --> n29
n25 --> n26
n7 --> n8
n29 --> n30
n8 --> n29
n9 --> n10
n12 --> n11
n12 --> n14
n14 --> n13
n26 --> n12
n31 --> n32
n27 --> n28
n30 --> n31
end
subgraph sg2["Flow 3"]
direction LR
n15@{ icon: "mdi:swap-vertical", form: "rounded", label: "Build Error Response Payload2", pos: "b", h: 48 }
n33["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Updateslots_tool"]
n34@{ icon: "mdi:swap-vertical", form: "rounded", label: "Input Arguments from updates..", pos: "b", h: 48 }
n35@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Checks if required info is p..", pos: "b", h: 48 }
n36["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Finds original appointment"]
n37["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Response with Error"]
n38@{ icon: "mdi:location-exit", form: "rounded", label: "Update Event", pos: "b", h: 48 }
n39["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Updates Airtable record"]
n40@{ icon: "mdi:swap-vertical", form: "rounded", label: "Response & call_id", pos: "b", h: 48 }
n41["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond to Vapi about Updati.."]
n38 --> n39
n38 --> n40
n33 --> n34
n40 --> n41
n39 --> n40
n36 --> n38
n15 --> n37
n35 --> n36
n35 --> n15
n34 --> n35
end
subgraph sg3["Flow 4"]
direction LR
n42["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>CancelSlots_tool"]
n43@{ icon: "mdi:swap-vertical", form: "rounded", label: "Input Arguments from cancels..", pos: "b", h: 48 }
n44@{ icon: "mdi:swap-horizontal", form: "rounded", label: "Checks if required info is p..", pos: "b", h: 48 }
n45["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Finds the appointment record"]
n46@{ icon: "mdi:swap-vertical", form: "rounded", label: "Build Error Response", pos: "b", h: 48 }
n47["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond with Error to Vapi"]
n48@{ icon: "mdi:location-exit", form: "rounded", label: "Delete Event", pos: "b", h: 48 }
n49["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Update Airtable record"]
n50@{ icon: "mdi:swap-vertical", form: "rounded", label: "Call_id & Response", pos: "b", h: 48 }
n51["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Respond to Vapi about cancel.."]
n48 --> n49
n48 --> n50
n42 --> n43
n50 --> n51
n46 --> n47
n49 --> n50
n45 --> n48
n43 --> n44
n44 --> n45
n44 --> n46
end
subgraph sg4["Flow 5"]
direction LR
n52["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>call_results"]
n53@{ icon: "mdi:swap-vertical", form: "rounded", label: "All Input Arguments", pos: "b", h: 48 }
n54["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/airtable.svg' width='40' height='40' /></div><br/>Save all information"]
n52 --> n53
n53 --> n54
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n19,n12,n30,n35,n44 decision
class n32,n36,n39,n45,n49,n54 database
class n16,n18,n24,n13,n25,n29,n33,n37,n41,n42,n47,n51,n52 api
class n3,n4,n5,n23,n9,n11,n27 code
classDef customIcon fill:none,stroke:none
class n1,n2,n3,n4,n5,n16,n18,n23,n24,n9,n11,n13,n25,n27,n29,n32,n33,n36,n37,n39,n41,n42,n45,n47,n49,n51,n52,n54 customIcon
Why This Matters: Missed calls become missed revenue
Calls are still the fastest way for a lead to say “I’m ready.” The problem is that humans are bad at being always-on. When you miss the call, the moment cools off. When you do answer, you’re suddenly a receptionist, a scheduler, and a note-taker while also trying to sound professional. Then the details leak out of your head: the preferred time, the real problem, the budget, the urgency. And if your calendar availability isn’t up to date, you end up double-booking or offering slots you can’t actually take.
It adds up fast. Here’s where it breaks down in real life.
- You miss 2–3 calls in a busy week, and at least one of them never calls back.
- Booking manually takes about 10 minutes once you include confirming the time, creating the event, and sending the follow-up.
- Notes end up scattered in inboxes, sticky notes, and someone’s memory, which is honestly the worst place for lead context.
- Reschedules and cancellations are where mistakes happen, especially when multiple people touch the same calendar.
What You’ll Build: An AI receptionist that books, confirms, and logs
This workflow gives you a voice-based AI receptionist that answers inbound calls through Vapi, checks your Google Calendar for available slots, and books the appointment while the caller is still on the line. If the caller needs a different time, it can update the booking or cancel it based on your rules. Once the call ends, the workflow creates a clean record in Airtable with the call summary and key details, so you’re not relying on memory or hunting through transcripts. You still control the schedule. The automation just handles the back-and-forth and the admin work.
The workflow starts with a Vapi-triggered webhook when a call comes in. From there, n8n routes the request to the right scheduling action (get availability, book, update, or cancel) and confirms the result. Finally, it writes the call outcome and summary into Airtable, so your pipeline and reporting stay tidy.
What You’re Building
| What Gets Automated | What You’ll Achieve |
|---|---|
|
|
Expected Results
Say you get about 20 inbound calls a week that could turn into appointments. Manually, even a “quick” flow (answer, check calendar, propose times, create event, send confirmation) is about 10 minutes each, or roughly 3 hours weekly. Add reschedules and cancellations and it’s easy to hit 5 hours. With this workflow, you spend close to 15 minutes setting rules and reviewing Airtable notes, while Vapi handles the live booking and n8n logs everything automatically.
Before You Start
- n8n instance (try n8n Cloud free)
- Self-hosting option if you prefer (Hostinger works well)
- Vapi to answer calls and hit webhooks
- Google Calendar for availability and booking events
- Airtable to store call summaries and outcomes
- OpenAI API key (get it from the OpenAI API dashboard)
Skill level: Intermediate. You’ll connect credentials, paste webhook URLs into Vapi, and test a few call scenarios.
Want someone to build this for you? Talk to an automation expert (free 15-minute consultation).
Step by Step
An inbound call triggers the receptionist. Vapi answers and sends the call context into n8n using webhooks (different endpoints for checking slots, booking, updating, canceling, and the end-of-call report).
Your availability gets checked before anything is promised. n8n looks at Google Calendar to find open times that match your slot rules. A bit of conditional logic (If/Switch) keeps it from offering times that are too soon, outside business hours, or already taken.
The booking action runs based on what the caller wants. The AI agent guides the conversation, then n8n executes the right Calendar action: create a new event, update an existing one, or cancel it. Fields are cleaned up along the way so the event title, email, and notes stay consistent.
Everything gets logged for follow-up. At the end of the call, an OpenAI Chat Model generates a readable summary, and Airtable stores the transcript details and outcomes. You can also push a notification to Telegram for quick visibility when a hot lead books.
You can easily modify your slot length and booking rules to match how your team sells. See the full implementation guide below for customization options.
Troubleshooting Tips
- Google Calendar credentials can expire or lack the right permissions. If bookings stop showing up, check the Google Calendar credential in n8n and confirm the connected account has access to the target calendar.
- If you’re using external call handling and webhooks, timing can get weird during busy moments. If downstream nodes fail because the payload is incomplete, add a short wait or ensure Vapi is sending the end-of-call report webhook reliably.
- Default AI prompts are bland. Put your business rules and brand tone into the Vapi system prompt and the OpenAI summary prompt early, or you will keep “fixing” notes after every call.
Quick Answers
About 45 minutes if your accounts are ready.
No. You will connect accounts, paste webhook URLs into Vapi, and adjust a few booking rules in n8n.
Yes. n8n has a free self-hosted option and a free trial on n8n Cloud. Cloud plans start at $20/month for higher volume. You’ll also need to factor in OpenAI API costs (usually a few cents per day for light usage) plus your Vapi/Twilio calling costs.
Two options: n8n Cloud (managed, easiest setup) or self-hosting on a VPS. For self-hosting, Hostinger VPS is affordable and handles n8n well. Self-hosting gives you unlimited executions but requires basic server management.
Yes, and you probably should. You can swap the Airtable logging step for Google Sheets, or add Gmail confirmations after booking. Common customizations include changing slot length, adding buffer time between meetings, restricting booking to certain event types, and sending a Telegram alert when a “high intent” call books.
Usually it’s the webhook URL. Make sure the workflow is activated in n8n, then re-copy the live webhook URLs into Vapi for GetSlots, BookSlots, UpdateSlots, CancelSlots, and the end-of-call report. If it still fails, check that your n8n instance is reachable from the public internet (self-hosted firewalls and SSL settings can block requests). Also confirm Vapi is sending the request to the right endpoint for the action being tested.
On a typical n8n Cloud plan, it can handle hundreds to thousands of calls per month depending on your execution limits. If you self-host, there’s no platform execution cap, but your server resources and Vapi/Twilio throughput will be the practical limit. The workflow itself is lightweight per call, so most bottlenecks come from voice/call handling and external API rate limits.
Often, yes. Zapier and Make are fine for simple “form → calendar” flows, but voice-driven scheduling needs branching logic, multiple webhook endpoints, and reliable end-of-call logging. n8n handles that without turning your automation into a maze of paid steps, and you can self-host if volume grows. The tradeoff is setup: you’ll spend a bit more time wiring it once. If you want a quick recommendation for your exact situation, Talk to an automation expert.
Once this is running, your calendar fills itself and your notes stop being a scavenger hunt. Set it up, test it, and let the workflow do the receptionist work for you.
Need Help Setting This Up?
Our automation experts can build and customize this workflow for your specific needs. Free 15-minute consultation—no commitment required.