Build an AI Booking Assistant
Automate appointment scheduling with an AI agent, Telegram, and Google Calendar.
Introduction
30 Second Summary
Think about calling an auto shop to book an appointment. You wait on hold, repeat your details to a receptionist, and hope they write everything down correctly.
In this project, you will build an AI-powered booking assistant that takes natural language requests from customers on Telegram and automatically schedules appointments on Google Calendar. The bot uses GPT-5 to understand requests, check availability, and send confirmation emails.
What You'll Build
A Telegram bot powered by an n8n AI Agent workflow that uses GPT-5, Google Calendar, and Gmail to handle end-to-end appointment scheduling for an auto service business.
By the end of this project, you'll have:
- A working Telegram bot connected to an AI Agent that understands natural language booking requests and holds multi-turn conversations.
- Google Calendar integration for real-time availability checking and automatic event creation.
- Gmail automation that sends professional booking confirmation emails to customers with a unique booking reference.
- Secret Mission: Add rescheduling support so customers can modify existing appointments through the same bot.
Are there any prerequisites?
This project assumes you already have a working n8n instance, an OpenAI API key with credits, a Google Cloud project with Calendar and Gmail APIs enabled, and a Telegram account. You will create a new Telegram bot token during Step 1.
Before We Start
Before We Start...
Create Your Telegram Bot and Configure Credentials
Before you can build the booking workflow, your n8n instance needs a way to receive messages from customers and talk to Google's services.
In this step, you will create a brand new Telegram bot and wire up all the credentials your workflow needs. By the end, n8n will be able to receive Telegram messages, read your Google Calendar, and send emails through Gmail.
In this step, get ready to:
- Create a Telegram bot using BotFather and save your bot token.
- Add a Telegram API credential in n8n.
- Verify your Google OAuth2 credentials for Calendar and Gmail.
Create a new Telegram bot with BotFather
Every Telegram bot needs a unique token that acts as its password. You get this token from BotFather, Telegram's official bot for creating and managing other bots.
- Open Telegram on your phone or desktop.
- In the search bar at the top, search for @BotFather and open the chat.
- Send the message /newbot to start the bot creation process.
- BotFather will ask you for a display name. Type a friendly name like QuickFix Auto Booking and send it.
- Next, BotFather asks for a username. This must end in bot and be globally unique. Try something like quickfix_auto_booking_bot (add numbers if your first choice is taken).
- BotFather responds with a message containing your bot token. It looks like a long string of numbers and letters separated by a colon.
- Copy this token and save it somewhere safe. You will paste it into n8n in the next substep.
What is a bot token?
The bot token is a secret key that lets your n8n workflow send and receive messages as your bot. Anyone with this token can control your bot, so treat it like a password.
Username already taken?
Telegram bot usernames must be globally unique. Try adding your initials or random numbers to the end (e.g. quickfix_auto_jd42_bot). The username must end in bot or Bot.
Why can't I create my Telegram bot?
Add your Telegram credential in n8n
Now that you have a bot token, n8n needs it stored as a credential so your workflow nodes can authenticate with Telegram.
- Open your n8n instance in your browser.
- Click the menu icon in the top-left corner, then select Credentials.
- Click Add Credential in the top-right corner.
- Search for Telegram and select Telegram API.
- Paste your bot token into the Access Token field.
- Click Save. n8n will test the connection automatically.
You should see a green success banner confirming the credential is working.
Your n8n instance must be publicly accessible
Telegram sends messages to your n8n instance via webhooks. This means your n8n instance needs a public URL (not just localhost). If you are running n8n locally without a tunnel, the Telegram Trigger will not receive messages.
If your instance is already hosted (n8n Cloud, a VPS, or behind a tunnel like ngrok), you are good to go.
Credential test failed?
Double-check that you copied the entire token from BotFather, including the numbers before the colon. A common mistake is missing the first few digits or including a trailing space.
Why is my Telegram credential failing in n8n?
Verify your Google Calendar and Gmail credentials
Your workflow will check calendar availability and send confirmation emails. Both actions require a Google OAuth2 credential with the right scopes.
What are OAuth2 scopes?
Scopes define what your n8n credential is allowed to do with your Google account. For this project, you need the Calendar scope (to read and create events) and the Gmail scope (to send emails). Without both scopes, parts of your workflow will fail silently.
If you already have a Google OAuth2 credential in n8n, verify it is working. If not, create one now.
✔️ I already have a Google credential in n8n
- Go back to your n8n canvas and click the + button to add a node.
- Search for Google Calendar and add the node.
- In the node settings, select your existing Google credential from the Credential to connect with dropdown.
- Set the Resource to Calendar and the Operation to Availability.
- Click Test step to run the node.
If the test succeeds and you see availability data (or an empty result if your calendar is free), your credential is working. Delete this test node afterwards since you will build the real workflow in the next step.
ⓧ I need to set up Google credentials
You need to create a Google OAuth2 credential in n8n that has access to both Google Calendar and Gmail.
- In n8n, go to Credentials and click Add Credential.
- Search for Google Calendar and select Google Calendar OAuth2 API.
- Follow the setup instructions. You will need your Client ID and Client Secret from your Google Cloud Console OAuth2 credentials.
- Click Sign in with Google and authorize access to your Google Calendar.
- Click Save.
- Repeat the same process for Gmail. Add a new credential, search for Gmail OAuth2 API, and authorize access.
Which Google APIs need to be enabled?
In your Google Cloud Console, make sure these APIs are enabled: calendar-json.googleapis.com for Google Calendar and gmail.googleapis.com for Gmail. Without these, the OAuth flow will fail even if your credentials are correct.
To verify everything works, add a temporary Google Calendar node to your canvas, select your new credential, set the operation to Availability, and click Test step. You should see a result without errors.
Google Calendar test returning an error?
Make sure your Google Cloud project has the Calendar API enabled. Also check that your OAuth consent screen is configured and your n8n redirect URI matches what is set in Google Cloud.
Help me fix my Google OAuth2 credential in n8n.
One Telegram trigger per bot
Telegram only allows one active webhook per bot token at a time. If you have another n8n workflow using the same bot, deactivate it before building this project.
Your credentials are locked in. n8n can now talk to Telegram, Google Calendar, and Gmail on your behalf. Next up, you will build the AI Agent core that receives customer messages and starts intelligent booking conversations.
Build the AI Agent Core
Your Telegram bot exists, but it can't do anything yet. It needs a brain.
In this step, you'll wire up the core of your booking assistant inside n8n. You'll connect a Telegram Trigger (so the bot listens for messages), an AI Agent node (so it can reason and act), an OpenAI Chat Model (the language model powering its responses), and a Simple Memory node (so it remembers each customer's conversation).
In this step, get ready to:
- Create a new workflow with a Telegram Trigger node that fires on incoming messages.
- Add an AI Agent node and configure its prompt to pass the customer's message text.
- Attach an OpenAI Chat Model and Simple Memory sub-node to give the agent intelligence and conversation context.
Create a new workflow and add the Telegram Trigger
Every n8n automation starts with a trigger node. The Telegram Trigger listens for messages sent to your bot and kicks off the workflow each time a customer types something.
- In your n8n instance, click the Create Workflow button from the Overview page.
- On the empty canvas, click Add first step to open the nodes panel.
- Search for Telegram and select Telegram Trigger (look for the bolt icon indicating it is a trigger).
- In the node settings, find the Trigger On dropdown and select Message.
- In the Credential for Telegram API dropdown, select the Telegram API credential you created in Step 1.
- Close the node panel to return to the canvas.
What is a Telegram Trigger?
When this workflow is published, n8n registers a webhook with Telegram. Every time someone sends a message to your bot, Telegram forwards that message to n8n, which starts this workflow automatically.
You should see the Telegram Trigger node on your canvas with a green checkmark indicating a valid credential.
Don't see your credential in the dropdown?
Make sure you created the Telegram API credential in Step 1 and that it is saved. If it still doesn't appear, click Create new credential and paste your bot token again.
Help me troubleshoot my Telegram Trigger credential in n8n.
Add the AI Agent node and configure its prompt
The AI Agent node is the brain of your workflow. It receives the customer's message, reasons about what to do, and decides which tools to call. You need to tell it where to find the user's message text.
- On the canvas, click the + connector on the right side of the Telegram Trigger node.
- Search for AI Agent and select it to add it to the canvas. n8n automatically connects it after the Telegram Trigger.
- Double-click the AI Agent node to open its settings.
- Find the Prompt parameter and set it to Define below.
- In the Text field that appears, click the expression editor (the = icon) and enter this expression:
{{ $json.message.text }}
Why Define below instead of Connected Chat Trigger Node?
Since you are using a Telegram Trigger (not n8n's built-in Chat Trigger), the AI Agent won't automatically know where the user's text lives. Setting the prompt to "Define below" lets you manually point it to the correct field in the Telegram message payload.
The expression {{ $json.message.text }} grabs the text content of the incoming Telegram message and passes it as the prompt to the AI Agent.
- Leave the AI Agent node open for the next substep. You will connect sub-nodes to it next.
Seeing a "No prompt specified" error?
This happens when the Prompt parameter is still set to "Connected Chat Trigger Node" instead of "Define below". Open the AI Agent node, change the Prompt dropdown to Define below, and add the expression {{ $json.message.text }} in the Text field.
Help me fix the No prompt specified error in my AI Agent node.
Connect the OpenAI Chat Model and Simple Memory sub-nodes
An AI Agent needs two things to function: a language model to generate responses and memory to track the conversation. You'll attach both as sub-nodes.
- With the AI Agent node open, find the Chat Model connector along the bottom of the node and click the + button.
- In the search dialog, select OpenAI Chat Model.
- In the OpenAI Chat Model settings, find the Model dropdown and select gpt-5.
- In the Credential for OpenAI API dropdown, select your OpenAI credential (it should appear automatically if you added one earlier).
- Close the OpenAI Chat Model sub-node to return to the AI Agent.
What is a sub-node?
Sub-nodes attach to root nodes (like the AI Agent) to extend their capabilities. The OpenAI Chat Model sub-node gives the agent its language model. You'll see it appear as a small connected node below the AI Agent on the canvas.
- Back on the AI Agent node, find the Memory connector along the bottom and click the + button.
- Select Simple Memory from the list.
- Set the Context Window Length to 10.
- Find the Session Key field, click the expression editor (= icon), and enter this expression:
{{ $json.message.chat.id }}
Why use the chat ID as the session key?
Each Telegram user has a unique chat ID. By using it as the session key, the Simple Memory node stores a separate conversation history for each customer. This means two customers can message your bot at the same time without their conversations mixing.
A Context Window Length of 10 means the agent remembers the last 10 exchanges. A typical booking conversation takes 3 to 5 messages, so 10 gives plenty of room.
- Close the Simple Memory sub-node to return to the canvas.
- Save your workflow by pressing Ctrl+S (Windows) or Cmd+S (macOS).
Your canvas should now show: Telegram Trigger connected to AI Agent, with OpenAI Chat Model and Simple Memory appearing as sub-nodes below the AI Agent.
Seeing "A Chat Model sub-node must be connected" error?
This means the OpenAI Chat Model did not attach properly. Open the AI Agent node, click the + Chat Model button at the bottom of the node panel, and select OpenAI Chat Model again. Make sure you select a model and credential before closing.
Help me connect the OpenAI Chat Model to my AI Agent node.
Running n8n in queue mode?
The Simple Memory node does not work in queue mode because n8n cannot guarantee every request goes to the same worker. If your instance uses queue mode, use Postgres Chat Memory or Redis Chat Memory instead.
Your AI Agent has a brain and a memory. Next up, you'll give it intelligence with a system prompt that defines its personality and connect Google Calendar so it can actually check availability and book appointments.
Add Intelligence with System Prompt, Structured Output, and Calendar Tool
In the previous step, you built the core of your AI Agent with a chat model and conversation memory. Right now, though, the agent has no idea it's supposed to be a booking assistant.
In this step, you'll give the agent its personality, teach it what data to collect, and connect it to Google Calendar so it can check real-time availability. These three pieces turn a generic chatbot into a purpose-built booking assistant.
In this step, get ready to:
- Add a system prompt that defines the bot's personality, services, and conversational instructions.
- Connect a Structured Output Parser so the agent outputs clean, structured booking data.
- Add a Google Calendar tool so the agent can check appointment availability on demand.
Generate and add the system prompt with Claude Code
A system prompt tells the AI Agent who it is, what rules to follow, and how to behave. Without one, GPT-5 would respond as a generic assistant with no knowledge of your auto service business.
You'll use Claude Code to generate a well-crafted system prompt, then paste it into your AI Agent node.
- Open your terminal and run Claude Code by typing:
claude
- Ask Claude Code to generate your system prompt by entering the following message:
Generate a system prompt for an n8n AI Agent that acts as a booking assistant for "QuickFix Auto Service". The prompt should:
- Define available services: Oil Change ($49.99, ~30 min), Tire Rotation ($39.99, ~45 min), Brake Inspection ($29.99, ~30 min), Full Service ($149.99, ~2 hours)
- Set business hours: Monday to Friday 8:00 AM to 5:00 PM, Saturday 9:00 AM to 2:00 PM, closed Sunday
- Require collecting: service type, preferred date/time, customer name, and customer email before booking
- Instruct the agent to check calendar availability before confirming
- Tell it to suggest alternatives if a slot is taken
- Use a friendly but professional tone
- Keep the prompt concise and actionable
Return only the system prompt text, no code blocks or extra formatting.
Why use Claude Code here?
Crafting an effective system prompt is a skill. Claude Code helps you generate a well-structured prompt quickly. You can always refine the output to match your exact needs.
- Copy the system prompt that Claude Code generates.
- Back in n8n, double-click your AI Agent node to open it.
- Scroll down to the options section at the bottom of the node panel.
- Click Add Option and select System Message.
- Paste your generated system prompt into the System Message field.
Your system prompt should define the services, business hours, required information, and conversational behavior. Here is the reference version to compare against:
✔️ Awesome, I've got everything!
Great. Make sure your system prompt covers the four services with prices, business hours, the five required fields, and instructions for handling unavailable slots.
ⓧ I'd like to double check the full code
Here is the complete reference system prompt. Your version from Claude Code may differ slightly in wording, but should contain the same key information:
You are a friendly and professional booking assistant for QuickFix Auto Service. Your job is to help customers schedule service appointments.
Available services:
- Oil Change ($49.99, ~30 min)
- Tire Rotation ($39.99, ~45 min)
- Brake Inspection ($29.99, ~30 min)
- Full Service ($149.99, ~2 hours)
Business hours: Monday to Friday, 8:00 AM to 5:00 PM. Saturday 9:00 AM to 2:00 PM. Closed Sunday.
To complete a booking, you need:
1. Service type
2. Preferred date and time
3. Customer name
4. Customer email
Instructions:
- Greet the customer warmly and ask how you can help.
- If they request a service, collect all required information conversationally.
- Before booking, use the calendar availability tool to check if the requested time slot is free.
- If the slot is available, confirm all details with the customer before creating the event.
- If the slot is not available, suggest the next available time on the same day or the following day.
- Always be concise and helpful. Use a friendly but professional tone.
- When the booking is confirmed, let the customer know they will receive a confirmation email.
- Format dates clearly (e.g., "Monday, May 12th at 2:00 PM").
Don't see the System Message option?
Make sure you click Add Option at the bottom of the AI Agent node panel. The System Message field is not visible by default. It only appears after you add it as an option.
Help me find the System Message option in my AI Agent node.
Enable structured output and connect the parser
Right now, the agent would respond with free-form text. For booking to work automatically, downstream nodes need structured data with exact field names like customer_email and date. A Structured Output Parser forces the agent's final output into a predictable JSON shape.
- In your AI Agent node settings, find the Require Specific Output Format toggle and turn it on.
- A new output parser connector appears at the bottom of the node. Click the Output Parser + connector.
- Select Structured Output Parser from the list.
Now you need to define the JSON schema that tells the parser what fields to extract. Use Claude Code to generate it.
- Switch back to your terminal where Claude Code is running and enter this prompt:
Generate a JSON Schema for an n8n Structured Output Parser that extracts booking data. The schema should have these required fields:
- service_type (string): The type of auto service requested
- date (string): Booking date in ISO 8601 format YYYY-MM-DD
- time (string): Booking time in 24-hour format HH:MM
- customer_name (string): Full name of the customer
- customer_email (string): Email address of the customer
- booking_confirmed (boolean): Whether the booking has been confirmed by the customer
All fields are required. Include descriptions for each field. Return only the JSON schema object, no extra text.
- Copy the JSON schema that Claude Code generates.
- Back in n8n, double-click the Structured Output Parser node to open it.
- Set Schema Type to Define using JSON Schema.
- Paste your JSON schema into the JSON Schema field.
What does booking_confirmed do?
The booking_confirmed boolean is the signal that triggers downstream nodes. During the conversation, the agent chats freely as natural text. Only when all details are collected and the customer confirms does the agent output structured JSON with booking_confirmed: true.
Compare your schema against the reference version to make sure all fields and types match.
✔️ Awesome, I've got everything!
Make sure you have all six fields with the correct types and that all are listed as required.
ⓧ I'd like to double check the full code
Here is the complete JSON schema. Your version should match these field names, types, and descriptions:
{
"type": "object",
"properties": {
"service_type": {
"type": "string",
"description": "The type of auto service requested"
},
"date": {
"type": "string",
"description": "The booking date in ISO 8601 format (YYYY-MM-DD)"
},
"time": {
"type": "string",
"description": "The booking time in 24-hour format (HH:MM)"
},
"customer_name": {
"type": "string",
"description": "The full name of the customer"
},
"customer_email": {
"type": "string",
"description": "The email address of the customer"
},
"booking_confirmed": {
"type": "boolean",
"description": "Whether the booking has been confirmed by the customer"
}
},
"required": ["service_type", "date", "time", "customer_name", "customer_email", "booking_confirmed"]
}
Seeing a 'JSON Output contains invalid JSON' error?
This means your schema has a syntax issue. Check for missing commas between properties, mismatched braces, or trailing commas after the last property. Use a JSON validator to verify your schema is valid before pasting it in.
Help me fix my Structured Output Parser JSON schema.
Connect Google Calendar as a tool for availability checking
The agent needs to verify that a requested time slot is actually free before confirming a booking. By connecting Google Calendar as a tool to the AI Agent, the agent can autonomously call the calendar whenever it needs to check availability.
- Close the Structured Output Parser node and look at your AI Agent node on the canvas.
- Click the Tool + connector on the AI Agent node.
- Search for and select Google Calendar.
- In the Google Calendar node settings, set Resource to Calendar.
- Set Operation to Availability.
- Select your Google Calendar credential from the Credential dropdown.
Now you need to let the AI Agent dynamically fill in the start and end times. The $fromAI() function tells n8n to let the AI model provide parameter values based on the conversation context.
- Find the Start Time field. Click the small AI button (or expression toggle) on the right side of the field.
- Click the X to revert to user-defined values, then switch to expression mode and enter:
{{ $fromAI('startTime', 'The start time to check availability for in ISO 8601 format', 'string') }}
- Find the End Time field. Switch to expression mode and enter:
{{ $fromAI('endTime', 'The end time to check availability for in ISO 8601 format', 'string') }}
What does $fromAI() do?
The $fromAI() function is only available for tools connected to the AI Agent node. It tells the agent to dynamically fill in that parameter using context from the conversation.
When a customer says "next Monday at 10am," the agent converts that into an ISO 8601 datetime and passes it to the Google Calendar tool automatically.
- Close the Google Calendar node.
Your canvas should now show the AI Agent node with four sub-node connections: OpenAI Chat Model, Simple Memory, Structured Output Parser, and Google Calendar (Availability).
Google Calendar not appearing as a tool option?
Make sure you are clicking the Tool + connector on the AI Agent node, not the general node panel. Only nodes connected via the tool connector get the $fromAI() capability. Also verify your Google Calendar OAuth2 credential is working by testing it in the credential settings.
Help me connect Google Calendar as a tool to my AI Agent.
Your AI Agent now has brains, structure, and real-world awareness. Next up, you'll wire up the booking actions so the agent can actually create calendar events, send confirmation emails, and reply to the customer.
Add Booking Actions with Calendar, Gmail, and Telegram Reply
Your AI Agent can now understand booking requests, hold a conversation to collect details, and check calendar availability. The missing piece is the action chain that executes after a customer confirms their booking.
When the agent outputs structured data with booking_confirmed: true, downstream nodes need to take that data and do three things: create the calendar event, email the customer, and reply in Telegram. In this step, you will build each of those nodes and connect them into a complete booking pipeline.
In this step, get ready to:
- Add a Code node that generates booking references and formats data for Calendar, Gmail, and Telegram.
- Add a Google Calendar node that creates the appointment event.
- Add Gmail and Telegram nodes that send confirmation messages to the customer.
Add the Code node for booking reference generation
Before the workflow can create a calendar event or send emails, it needs to transform the raw structured output into properly formatted fields. A Code node lets you write custom JavaScript that runs as a step in your workflow.
- In the n8n canvas, click the + button on the right side of the AI Agent node's main output connector.
- Search for Code and select the Code node.
- In the Code node settings, set Language to JavaScript.
- Set Mode to Run Once for All Items.
- Open Claude Code in your terminal and ask it to generate booking reference code with this prompt:
Generate JavaScript for an n8n Code node that:
1. Gets the first input item's json (fields: service_type, date, time, customer_name, customer_email)
2. Generates a booking reference in format QFA-YYYYMMDD-XXXX (XXXX = random 4-char alphanumeric uppercase)
3. Parses date and time into a startDateTime string (format: YYYY-MM-DDTHH:MM:00)
4. Calculates endDateTime based on service duration (Oil Change: 30min, Tire Rotation: 45min, Brake Inspection: 30min, Full Service: 120min, default: 60min)
5. Formats an HTML email body with a table showing booking reference, service, date, time, and duration
6. Formats a Telegram confirmation message with emojis
7. Returns a single item with json containing: bookingReference, service_type, customer_name, customer_email, startDateTime, endDateTime, durationMinutes, emailSubject, emailBody, telegramMessage, calendarSummary, calendarDescription
The return format must be [{json: {...}}] as required by n8n.
Claude Code will generate the JavaScript. Compare its output against the reference code below, then paste the final version into the Code node's code editor. Replace any existing placeholder code.
- Paste the following JavaScript into the Code field (replacing any existing code):
// Generate booking reference and format data for Calendar and Gmail
const items = $input.all();
const item = items[0].json;
// Generate booking reference: QFA-YYYYMMDD-XXXX
const now = new Date();
const dateStr = now.toISOString().slice(0, 10).replace(/-/g, '');
const randomPart = Math.random().toString(36).substring(2, 6).toUpperCase();
const bookingReference = `QFA-${dateStr}-${randomPart}`;
// Parse the booking date and time
const bookingDate = item.date;
const bookingTime = item.time;
const startDateTime = `${bookingDate}T${bookingTime}:00`;
// Calculate end time based on service duration
const serviceDurations = {
'Oil Change': 30,
'Tire Rotation': 45,
'Brake Inspection': 30,
'Full Service': 120
};
const durationMinutes = serviceDurations[item.service_type] || 60;
const startDate = new Date(startDateTime);
const endDate = new Date(startDate.getTime() + durationMinutes * 60000);
const endDateTime = endDate.toISOString();
// Format email body
const emailBody = `
<h2>Booking Confirmation - QuickFix Auto Service</h2>
<p>Hi ${item.customer_name},</p>
<p>Your appointment has been confirmed! Here are your booking details:</p>
<table style="border-collapse: collapse; width: 100%;">
<tr><td style="padding: 8px; border: 1px solid #ddd;"><strong>Booking Reference</strong></td><td style="padding: 8px; border: 1px solid #ddd;">${bookingReference}</td></tr>
<tr><td style="padding: 8px; border: 1px solid #ddd;"><strong>Service</strong></td><td style="padding: 8px; border: 1px solid #ddd;">${item.service_type}</td></tr>
<tr><td style="padding: 8px; border: 1px solid #ddd;"><strong>Date</strong></td><td style="padding: 8px; border: 1px solid #ddd;">${bookingDate}</td></tr>
<tr><td style="padding: 8px; border: 1px solid #ddd;"><strong>Time</strong></td><td style="padding: 8px; border: 1px solid #ddd;">${bookingTime}</td></tr>
<tr><td style="padding: 8px; border: 1px solid #ddd;"><strong>Duration</strong></td><td style="padding: 8px; border: 1px solid #ddd;">${durationMinutes} minutes</td></tr>
</table>
<p>Please arrive 5 minutes before your appointment time.</p>
<p>If you need to reschedule or cancel, simply message us on Telegram.</p>
<p>Thank you for choosing QuickFix Auto Service!</p>
`;
// Format Telegram confirmation message
const telegramMessage = `\u2705 Booking Confirmed!\n\n\ud83d\udccb Reference: ${bookingReference}\n\ud83d\udd27 Service: ${item.service_type}\n\ud83d\udcc5 Date: ${bookingDate}\n\u23f0 Time: ${bookingTime}\n\u23f1 Duration: ${durationMinutes} min\n\nYou'll receive a confirmation email at ${item.customer_email}. See you soon!`;
return [{
json: {
bookingReference,
service_type: item.service_type,
customer_name: item.customer_name,
customer_email: item.customer_email,
startDateTime,
endDateTime,
durationMinutes,
emailSubject: `Booking Confirmed: ${item.service_type} - ${bookingReference}`,
emailBody,
telegramMessage,
calendarSummary: `${item.service_type} - ${item.customer_name}`,
calendarDescription: `Booking Reference: ${bookingReference}\nCustomer: ${item.customer_name}\nEmail: ${item.customer_email}\nService: ${item.service_type}`
}
}];
What does this code do?
This script takes the structured booking data from the AI Agent and prepares everything the downstream nodes need.
- Generates a unique booking reference in the format QFA-YYYYMMDD-XXXX using today's date and a random 4-character alphanumeric string.
- Calculates the event end time by adding the service duration (30, 45, or 120 minutes depending on service type) to the start time.
- Formats an HTML email body with a professional table layout showing all booking details.
- Builds a Telegram reply message with emojis for a friendly confirmation.
- Returns everything in the [{json: {...}}] format that n8n requires for passing data between nodes.
- Close the Code node panel.
- Click Execute step on the Code node to test it. You should see output fields like bookingReference, startDateTime, and emailBody in the output panel.
Seeing an error about items not being returned?
The n8n Code node requires output in the format [{json: {...}}]. Make sure you copied the full return statement at the bottom of the code. If you see Error: Always an Array of items has to be returned! it means the return statement is missing or malformed.
help me fix my Code node error in n8n
Add the Google Calendar Create Event node
With the formatted data flowing out of the Code node, the next step is creating the actual calendar event. The Google Calendar node's Create Event operation takes a start time, end time, summary, and description to create an appointment on your calendar.
- Click the + button on the right side of the Code node's output connector.
- Search for Google Calendar and select it.
- Set Credential to connect with to your existing Google Calendar OAuth2 credential.
- Set Resource to Event.
- Set Operation to Create.
- Set Calendar to your primary calendar (select From list and choose it from the dropdown).
- Set Start Time to the expression {{ $json.startDateTime }}.
- Set End Time to the expression {{ $json.endDateTime }}.
- Expand the Options section at the bottom.
- Click Add Option and select Summary. Set it to the expression {{ $json.calendarSummary }}.
- Click Add Option and select Description. Set it to the expression {{ $json.calendarDescription }}.
- Click Add Option and select Attendees. Set it to the expression {{ $json.customer_email }}.
What do these fields map to?
- Summary becomes the event title on Google Calendar (e.g., "Oil Change - John Smith").
- Description holds the booking reference and customer details, visible when you click into the event.
- Attendees sends a Google Calendar invitation to the customer's email address.
- Close the Google Calendar node panel.
Calendar node showing a credential error?
Make sure you selected the same Google OAuth2 credential you verified in Step 1. If the credential expired, click into Credentials in the left sidebar, find your Google Calendar credential, and click Sign in with Google again to re-authenticate.
help me fix my Google Calendar credential in n8n
Add Gmail and Telegram confirmation nodes
The last two nodes complete the customer experience. A Gmail node sends a professional HTML confirmation email, and a Telegram node replies directly in the customer's chat.
- Click the + button on the right side of the Google Calendar node's output connector.
- Search for Gmail and select it.
- Set Credential to connect with to your Google OAuth2 credential (the same one with Gmail scope).
- Set Resource to Message.
- Set Operation to Send.
- Set To to the expression {{ $json.customer_email }}.
- Set Subject to the expression {{ $json.emailSubject }}.
- Set Email Type to HTML.
- Set Message to the expression {{ $json.emailBody }}.
- Close the Gmail node panel.
Now add the final node to reply in Telegram.
- Click the + button on the right side of the Gmail node's output connector.
- Search for Telegram and select the Telegram node (not the Trigger).
- Set Credential to connect with to your existing Telegram API credential.
- Set Resource to Message.
- Set Operation to Send Message.
- Set Chat ID to the expression {{ $('Telegram Trigger').item.json.message.chat.id }}. This sends the reply back to the same user who started the conversation.
- Set Text to the expression {{ $json.telegramMessage }}.
- Close the Telegram node panel.
Why reference the Telegram Trigger for Chat ID?
The Chat ID identifies which Telegram conversation to reply to. By the time the workflow reaches this node, the current $json contains Code node output (booking data), not the original Telegram message. The expression $('Telegram Trigger').item.json.message.chat.id reaches back to the Trigger node to get the original sender's chat ID.
- Press Ctrl+S (Windows) or Cmd+S (macOS) to save your workflow.
- Verify the full node chain on the canvas reads: Telegram Trigger, AI Agent, Code, Google Calendar, Gmail, Telegram (Send Message). Each node should be connected by a line from left to right.
Nodes not connected in a chain?
If any node appears disconnected, drag from the small circle on the right edge of one node to the left edge of the next. The connection line should snap into place. Your final chain must be: Telegram Trigger, AI Agent, Code, Google Calendar, Gmail, Telegram.
help me connect my n8n nodes in the correct order
Your workflow is fully wired. The AI Agent handles the conversation, and these four nodes handle the actions. Next up, you will activate the workflow and test the complete booking flow end-to-end.
Test Your Complete Booking Flow
Your workflow is fully built, but a single broken connection or misconfigured expression can silently break the entire chain. Until you send a real message and watch every node fire in sequence, you can't be sure it actually works.
In this step, you'll activate your workflow, send real booking requests to your Telegram bot, and verify that the AI agent correctly creates calendar events, sends emails, and replies with confirmation messages.
In this step, get ready to:
- Activate your n8n workflow so it listens for incoming Telegram messages.
- Send a complete booking request and verify all outputs (calendar, email, reply).
- Test edge cases like busy time slots and multi-turn conversations.
Activate your workflow and send a test booking request
An n8n workflow only processes incoming messages when it's set to Active. While inactive, the Telegram Trigger node doesn't register its webhook, so your bot ignores all messages.
- In your n8n workflow editor, find the Active toggle in the top-right corner of the canvas.
- Click the toggle to switch it on. It turns green when active.
What does activating do?
When you activate the workflow, n8n registers a webhook with Telegram's servers. From this point forward, any message sent to your bot gets forwarded to your n8n instance in real time.
Your n8n instance must be publicly accessible (not running on localhost without a tunnel) for the Telegram webhook to reach it.
Now send your first test message to the bot.
- Open Telegram and find your bot (search for the username you chose when creating it with BotFather).
- Send this message to your bot:
Hi, I'd like to book an oil change for next Monday at 10am. My name is John and my email is john@example.com
Why this specific message?
This message includes all the required booking fields in one shot: service type (oil change), date (next Monday), time (10am), customer name (John), and email (john@example.com). It gives the AI agent everything it needs to complete a booking without follow-up questions.
- Wait 10-30 seconds for the agent to process. You should see the bot reply in Telegram with a confirmation message or a follow-up question asking you to confirm the booking details.
- If the bot asks you to confirm, reply with "Yes" or "Confirm" to proceed.
Bot not replying at all?
Check that the workflow toggle is green (active). If it is, open the Executions tab in n8n to see if the workflow was triggered. If no execution appears, your n8n instance may not be publicly accessible for Telegram webhooks.
Also confirm you're messaging the correct bot. Search for your bot's exact username in Telegram (the one BotFather gave you, not the display name).
help me debug why my Telegram bot isn't receiving messages in n8n
Verify the full booking chain
A successful booking means four things happened: the AI understood your request, a calendar event was created, an email was sent, and you got a Telegram reply with a booking reference.
- Check your Telegram chat. You should see a reply containing a booking reference in the format QFA-YYYYMMDD-XXXX along with the service type, date, time, and duration.
- Open Google Calendar in your browser. Look for a new event on the date you requested. The event summary should show the service type and customer name (e.g. "Oil Change - John").
- Check the email inbox for john@example.com (or whatever email you used). You should see a confirmation email with the subject "Booking Confirmed: Oil Change" followed by the booking reference.
- In n8n, click the Executions tab in the left sidebar. Open the most recent execution to see how data flowed through each node.
Use your own email for testing
Replace john@example.com with your actual email address in the test message so you can verify the confirmation email arrives in your inbox.
What should I see in the execution?
Each node in the execution view shows a green checkmark if it ran successfully. Click on any node to inspect its input and output data. The Code node output should show all your formatted fields (bookingReference, emailBody, telegramMessage, etc.).
If a node shows a red X, click it to see the error message. Common issues include expired OAuth tokens (re-authenticate in Credentials) or missing field mappings.
Calendar event not appearing?
Open the execution in n8n and check the Google Calendar node output. If it shows an authentication error, go to Credentials, find your Google OAuth2 credential, and click Reconnect.
Also check that the calendar selected in the Google Calendar node matches the calendar you're viewing in the browser. The event may have been created on a different calendar.
help me debug why my Google Calendar event isn't being created
Test edge cases
A booking system that only works with perfect input isn't production-ready. Real customers will forget details, request unavailable times, and provide information across multiple messages.
Run these three tests to confirm your agent handles imperfect conversations gracefully.
Test 1: Booking a taken time slot
- In Google Calendar, manually create an event at a specific time (e.g. next Tuesday at 2pm).
- Send a message to your bot requesting that exact time slot:
I need a tire rotation next Tuesday at 2pm. Name is Sarah, email sarah@example.com
- The bot should detect the conflict using the Calendar Availability tool and suggest an alternative time on the same day or the following day.
Test 2: Incomplete information
- Send a message with missing details:
I want to book a brake inspection for Friday
- The bot should ask follow-up questions for the missing fields: time, name, and email. This confirms your Simple Memory node is working correctly, because the bot remembers the earlier context when you provide the missing details in subsequent messages.
Test 3: Multi-turn conversation
- Start a new conversation by sending a simple greeting:
Hi, I need to get my car serviced
- The bot should greet you and ask what service you need. Provide details one at a time across 3-4 messages.
- Verify that the bot collects all required information across the conversation and still produces a successful booking at the end.
What if the bot behaves unexpectedly?
AI agents are non-deterministic. The bot might phrase things differently each time or occasionally ask for details you already provided. This is normal LLM behavior.
If the bot consistently fails to remember context, check your Simple Memory node. Make sure the Session Key is set to {{ $json.message.chat.id }} and the Context Window Length is 10.
Bot keeps asking for the same information?
This usually means the memory isn't persisting between messages. Open your Simple Memory node and confirm the Session Key expression is {{ $json.message.chat.id }} (not a hardcoded string).
If you're running n8n in queue mode, Simple Memory does not work. Switch to Postgres Chat Memory or Redis Chat Memory instead.
help me fix conversation memory in my n8n AI Agent
Your AI booking assistant is now live and handling real conversations. You've proven it works end-to-end with both perfect and imperfect inputs. Next up, the Secret Mission challenges you to add rescheduling support so customers can move existing appointments.
Secret mission
Add Rescheduling Support
Your booking assistant can create appointments, but what happens when a customer needs to move theirs? Real businesses need rescheduling support. Extend your AI agent to find existing bookings and move them to new time slots, all through natural conversation.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. This project uses your OpenAI API credits each time someone messages your Telegram bot, so leaving the workflow active will consume credits with every conversation.
Cost warning
Your n8n workflow triggers on every Telegram message sent to your bot. Each booking conversation costs less than $0.01 in OpenAI credits, but if you leave the workflow active and your bot receives unexpected messages, credits will be consumed.
If you are done testing, deactivate your workflow to prevent any unintended API usage.
Resources you used:
- n8n workflow (AI Booking Assistant).
- Telegram bot (created via BotFather).
- OpenAI API key with credits.
- Google Calendar OAuth2 credential in n8n.
- Gmail OAuth2 credential in n8n.
- Google Cloud project (Calendar and Gmail APIs enabled).
Keep everything running
No action needed. Choose this if you are still actively building or testing your booking assistant.
- Your n8n workflow stays active and will respond to Telegram messages.
- OpenAI credits will be consumed each time someone messages your bot.
- Google Calendar events created during testing will remain on your calendar.
Pause - I'll come back to this later
Deactivate your workflow to stop API usage while keeping everything configured for later.
- In n8n, open your AI Booking Assistant workflow and click the toggle in the top right to deactivate it.
- Your Telegram bot will still exist but will stop responding to messages.
- All credentials and node configurations are preserved. Reactivate the workflow when you are ready to resume.
- Clean up any test events from your Google Calendar by deleting bookings with the "QFA-" prefix.
Delete - I don't want to use this again
Remove all project resources and start fresh.
- In n8n, open the workflow and click the three-dot menu, then select Delete.
- In n8n, go to Credentials and delete the Telegram API credential you created for this project.
- In Telegram, message @BotFather and send /deletebot to remove your bot.
- Delete any test events from your Google Calendar that were created during this project.
- If you no longer need Google Calendar or Gmail integrations, remove those credentials from n8n as well.
- Your OpenAI API key and Google Cloud project can remain if you plan to use them for other projects.
Nice Work!
Nice Work!
You just built a production-ready AI booking assistant from scratch! Customers can now message your Telegram bot in plain English, and your AI Agent handles everything from understanding the request to confirming the appointment.
You've learned how to:
- Build a Telegram bot powered by GPT-5 that understands natural language booking requests and collects customer details through multi-turn conversations.
- Configure an n8n AI Agent with conversation memory and a Structured Output Parser to extract booking details into a reliable JSON format.
- Integrate Google Calendar for real-time availability checking and event creation, plus Gmail for automated booking confirmation emails.
- Added rescheduling support with multi-tool AI agent orchestration so customers can move existing appointments through natural conversation.
Ready to quiz yourself?