Cal.com booking chatbot for n8n
An n8n chatbot that answers questions, picks the right Cal.com event type, offers real availability and books the slot the visitor confirms.
Prerequisites
- An n8n instance, cloud or self-hosted
- A Cal.com account with API access, your Cal.com username, and an API key
- Two event types already created in Cal.com: one for new enquiries, one for support calls
- An OpenAI API key (or another chat model credential)
- SMTP credentials in n8n for the booking notification email
- Your FAQ or services copy as plain text
A chat widget that answers visitor questions, works out whether they want a sales call or a support call, and books them into the right Cal.com event type without sending them to a separate booking page.
What you'll build
A visitor lands on your site, asks a question or two, and at some point the conversation turns to wanting time on your calendar. The bot works out whether that is a new-project enquiry or an existing-customer support call, checks real availability for the right event type, offers a few times and books the one the visitor confirms. It writes the booking into Cal.com and emails you a heads-up.
Two things set this apart from embedding a Cal.com widget:
- It routes, not just books. The bot picks the event type from what the visitor said, so someone saying "I'm looking to get started" and someone saying "I'm an existing customer and need help" end up in different calendars without picking anything.
- It answers first. If it can answer a question from your
knowledgetext it does that before steering toward booking. Booking only comes up when the conversation points there.
How it works
- A webhook receives each widget message and checks a shared secret.
- An AI agent has two tools. check_availability reads open slots and can be called freely because it commits to nothing. book_slot writes the booking.
- Each tool is a separate workflow that calls the Cal.com API.
Note: The confirmation gate is a rule in the system prompt, not code. There is no mechanical way for n8n to verify that a visitor really agreed to one specific time, so the agent is instructed never to book until they have clearly confirmed it. That is a different guarantee from the consent gate in the CRM recipes, which is ordinary n8n branching. If you edit the prompt, keep the confirmation wording intact or the bot may book on a vague yes.
What it costs
The workflow is free to download and use. Your AI provider charges per conversation, and your n8n hosting and the plan for the service you connect apply as normal. For N8N Chat UI plans, see pricing. Cal.com's own plan limits apply.
Set it up
- Create your two event types in Cal.com. One for new-project enquiries and one for support calls. Note each one's slug, the part of its booking URL after
/your-username/. - Get an API key. In Cal.com go to Settings → Developer → API Keys and create one. Copy it now.
- Create the credential. In n8n, create an HTTP Header Auth credential with Name
Authorizationand ValueBearer YOUR_CAL_API_KEY. The word Bearer and the space are required, or Cal.com returns a 401. - Import the workflow. Download the file with the button at the top of this page and import it with Workflows → Import from File. It holds the main chatbot and its tool workflows on one canvas, each in a labelled section.
- Move each tool into its own workflow. n8n tools call a separate workflow, so for each tool section below the main flow: select its nodes, copy them, create a new empty workflow and paste. Save it, then open the matching tool node under the agent and select that workflow. Attach the credential to Call Cal.com slots API in the check availability workflow, and to Call Cal.com bookings API and Re-check availability in the book slot workflow. Attach your SMTP credential to Notify by email.
- Fill in Chatbot settings. Set
company_name,event_type_new_projectandevent_type_support(the slugs from step 1),timezone(an IANA name such asEurope/London),knowledgeand a randomwebhook_secret. If you only run one kind of call, use the same slug for both event types. - Fill in each tool's settings. In check availability, open Tool settings and set
cal_username,timezoneanddays_ahead(7 is sensible). In book slot, open Tool settings (book slot) and set the same three plushandoff_email, where booking notifications go. Each workflow carries its own copy so it can be tested alone. Leavecal_api_versionalone: slots and bookings use different Cal.com API versions, and one value must not be copied into both. - Add your AI credential. Open GPT-4.1 mini model and add your OpenAI credential. Swap the node for another chat model if you prefer.
Test it
Send a test message before you connect a widget. n8n's built-in chat panel needs a Chat Trigger, so it will not open for this workflow. Instead, click Test workflow, then send a POST request to the Test URL shown on the Chat webhook node:
curl -X POST 'YOUR_TEST_URL' \
-H 'Content-Type: application/json' \
-d '{"chatInput":"Hello","sessionId":"test-1","metadata":{"webhook_secret":"YOUR_SECRET"}}'The test URL listens for one request each time you click Test workflow. For a longer conversation, activate the workflow and send requests to the production URL, then read each run under Executions. Reuse the same sessionId to continue a conversation, because memory is kept per session.
Things to try:
- Ask a question covered by
knowledge. It should answer without mentioning booking. - Say you would like to book a call with no other context. The bot should ask which kind before offering times.
- Ask for availability. The times offered should match what is open in your calendar.
- Confirm one specific slot. The booking appears in your calendar and your notification email arrives.
- Ask a vague question, then say yes. The bot should not book anything, because nothing specific was confirmed. This is the check people skip, and a bot that books on a vague yes is worse than one that asks once more.
- Try to book a slot you have just taken manually. The bot should recover with alternatives instead of erroring.
Add it to your site
Activate the workflow and use its production webhook URL as your widget's chat endpoint. Send the same secret in the widget metadata, for example metadata: { page_url: window.location.href, webhook_secret: 'YOUR_SECRET' }. The metadata docs explain how metadata reaches n8n.
Any chat front end that can POST chatInput, sessionId and metadata to a webhook and read { "output": "..." } back will work. N8N Chat UI is built for exactly this.
What happens when a slot goes stale
Someone else can book a time in the gap between the bot offering it and the visitor confirming. If the booking call comes back with an error, the tool does not show a raw error. It checks availability again and hands the agent a fresh set of options, which the agent presents as: that time is not available, here is what is open.
Any error is treated as a reason to recover, and the message is deliberately non-committal: not available right now rather than just taken. That is because the calendar API can reject a slot that was not really taken, so the recipe does not claim more certainty than it has. The visitor sees a normal recovery, not a broken bot.
Troubleshooting
The bot offers times I do not actually have
Check timezone and days_ahead in the check availability Tool settings. Those are the copies used for the API call. The main settings only hold timezone for how times are phrased back to the visitor.
Bookings are not appearing in Cal.com
The book_slot tool is not linked to its workflow, or the Authorization credential is not attached to the HTTP nodes inside the book slot workflow.
The bot booked without a clear confirmation
You probably edited the agent's system message and trimmed the confirmation-gate wording. It is part of the prompt, not sourced from settings.
I get a 401 from Cal.com
The credential value must be exactly Bearer YOUR_API_KEY, including the word Bearer and the space.
Does it also write a contact to my CRM?
Not in this version. Booking and CRM capture are kept separate. The natural place to add a CRM write is the successful path of book slot, calling a lead capture tool from the HubSpot or ActiveCampaign recipes.
My conversations reset when n8n restarts
Memory is an in-memory buffer so the template works as soon as you import it. A restart or redeploy drops conversations in progress. Before a busy launch, swap Conversation memory for Postgres Chat Memory. Nothing else changes.
I get a 401 as soon as I test
The Request from your widget? check compares metadata.webhook_secret in the request with webhook_secret in Chatbot settings. If they differ, or the request has no metadata, the workflow returns a 401 before the agent runs.
Take it further
The chat side is identical for any scheduler. To use a different one, swap the HTTP Request nodes in both tool workflows and keep the agent, the routing and the confirmation gate as they are. A Calendly version is available.