Bot WA AI untuk Appointment Booking
Cara membuat bot AI WhatsApp untuk booking appointment otomatis. Jadwal, konfirmasi, reminder. Tutorial lengkap!
AI booking assistant = 24/7 reservation!
Bot AI bisa handle booking appointment secara natural - tanya kebutuhan, cek availability, konfirmasi jadwal, dan kirim reminder otomatis.
Use Cases
📅 COCOK UNTUK:
HEALTHCARE:
- Klinik & dokter
- Dental
- Spa & wellness
BEAUTY:
- Salon
- Barbershop
- Nail art
PROFESSIONAL:
- Konsultasi
- Coaching
- Legal
SERVICES:
- Auto service
- Home repair
- PhotographyBooking Flow
📋 FLOW IDEAL:
1. GREETING
"Hai! Mau booking untuk layanan apa?"
2. SERVICE SELECTION
"Pilih layanan: A, B, atau C"
3. DATE PREFERENCE
"Mau booking tanggal berapa?"
4. TIME SELECTION
"Jam berapa yang nyaman?"
5. AVAILABILITY CHECK
"Slot tersedia! / Coba waktu lain?"
6. CONFIRMATION
"Konfirmasi: [detail]. Benar?"
7. BOOKING SUCCESS
"Done! Akan kirim reminder H-1"System Prompt
javascript
const BOOKING_PROMPT = `Kamu adalah AI booking assistant untuk [SALON NAME].
TENTANG SALON:
- Salon kecantikan wanita
- Alamat: [ALAMAT]
- Jam buka: 09:00-21:00 (Senin-Sabtu)
- Minggu tutup
LAYANAN & HARGA:
1. Potong Rambut - Rp 75.000 (45 menit)
2. Hair Coloring - Rp 350.000 (2 jam)
3. Creambath - Rp 150.000 (1 jam)
4. Hair Treatment - Rp 250.000 (1.5 jam)
5. Manicure Pedicure - Rp 200.000 (1.5 jam)
6. Facial - Rp 300.000 (1.5 jam)
STYLISTS:
- Kak Rina (Senior) - Tersedia Senin-Jumat
- Kak Dewi (Senior) - Tersedia Selasa-Sabtu
- Kak Maya (Junior) - Tersedia setiap hari
TUGAS KAMU:
1. Sapa dengan ramah
2. Tanya layanan yang diinginkan
3. Tanya tanggal & waktu preferensi
4. Cek availability (panggil function)
5. Tawarkan alternatif jika tidak tersedia
6. Konfirmasi detail booking
7. Selesaikan booking (panggil function)
ATURAN:
- Hanya bisa booking H+1 sampai H+14
- Tidak bisa booking hari Minggu
- Maksimal 2 layanan per booking
- Minta nama & nomor WA untuk booking
RESPONSE STYLE:
- Bahasa Indonesia casual dengan "Kak"
- Ramah dan helpful
- Gunakan emoji 😊💇♀️💅`;Function Calling Implementation
javascript
const bookingTools = [
{
type: 'function',
function: {
name: 'check_availability',
description: 'Cek ketersediaan slot booking',
parameters: {
type: 'object',
properties: {
service: {
type: 'string',
description: 'Nama layanan'
},
date: {
type: 'string',
description: 'Tanggal (YYYY-MM-DD)'
},
preferred_time: {
type: 'string',
description: 'Waktu preferensi (HH:MM)'
},
stylist: {
type: 'string',
description: 'Nama stylist (optional)'
}
},
required: ['service', 'date']
}
}
},
{
type: 'function',
function: {
name: 'create_booking',
description: 'Buat booking baru',
parameters: {
type: 'object',
properties: {
customer_name: { type: 'string' },
customer_phone: { type: 'string' },
service: { type: 'string' },
date: { type: 'string' },
time: { type: 'string' },
stylist: { type: 'string' }
},
required: ['customer_name', 'customer_phone', 'service', 'date', 'time']
}
}
},
{
type: 'function',
function: {
name: 'cancel_booking',
description: 'Batalkan booking',
parameters: {
type: 'object',
properties: {
booking_id: { type: 'string' }
},
required: ['booking_id']
}
}
}
];
async function handleBookingChat(userId, userMessage, conversationHistory) {
const response = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: BOOKING_PROMPT },
...conversationHistory,
{ role: 'user', content: userMessage }
],
tools: bookingTools,
tool_choice: 'auto'
});
const message = response.choices[0].message;
// Check if function called
if (message.tool_calls) {
const results = [];
for (const toolCall of message.tool_calls) {
const args = JSON.parse(toolCall.function.arguments);
let result;
switch (toolCall.function.name) {
case 'check_availability':
result = await checkAvailability(args);
break;
case 'create_booking':
result = await createBooking(args);
break;
case 'cancel_booking':
result = await cancelBooking(args);
break;
}
results.push({
tool_call_id: toolCall.id,
role: 'tool',
content: JSON.stringify(result)
});
}
// Continue conversation with function results
const finalResponse = await openai.chat.completions.create({
model: 'gpt-4o',
messages: [
{ role: 'system', content: BOOKING_PROMPT },
...conversationHistory,
{ role: 'user', content: userMessage },
message,
...results
]
});
return finalResponse.choices[0].message.content;
}
return message.content;
}Backend Functions
javascript
// Check availability
async function checkAvailability({ service, date, preferred_time, stylist }) {
const serviceInfo = services[service];
if (!serviceInfo) {
return { available: false, error: 'Layanan tidak ditemukan' };
}
const duration = serviceInfo.duration;
const bookingDate = new Date(date);
// Check if Sunday
if (bookingDate.getDay() === 0) {
return { available: false, reason: 'Hari Minggu tutup' };
}
// Check if within booking window (H+1 to H+14)
const today = new Date();
const maxDate = new Date();
maxDate.setDate(maxDate.getDate() + 14);
if (bookingDate <= today || bookingDate > maxDate) {
return {
available: false,
reason: 'Hanya bisa booking H+1 sampai H+14'
};
}
// Get existing bookings
const existingBookings = await db.bookings.find({
date: date,
status: { $ne: 'cancelled' }
}).toArray();
// Find available slots
const allSlots = generateTimeSlots('09:00', '21:00', 30);
const availableSlots = allSlots.filter(slot => {
return !hasConflict(slot, duration, existingBookings, stylist);
});
if (preferred_time) {
const isPreferredAvailable = availableSlots.includes(preferred_time);
if (isPreferredAvailable) {
return {
available: true,
slot: preferred_time,
service,
date,
price: serviceInfo.price
};
} else {
// Suggest alternatives
const alternatives = findClosestSlots(preferred_time, availableSlots, 3);
return {
available: false,
reason: `Slot ${preferred_time} tidak tersedia`,
alternatives: alternatives,
date
};
}
}
return {
available: true,
availableSlots: availableSlots.slice(0, 10),
date,
service
};
}
// Create booking
async function createBooking({ customer_name, customer_phone, service, date, time, stylist }) {
const bookingId = generateBookingId();
const booking = {
bookingId,
customerName: customer_name,
customerPhone: customer_phone,
service,
date,
time,
stylist: stylist || 'Any',
status: 'confirmed',
createdAt: new Date()
};
await db.bookings.insertOne(booking);
// Schedule reminders
await scheduleReminder(booking, 'H-1');
await scheduleReminder(booking, 'H-day');
return {
success: true,
bookingId,
details: {
service,
date,
time,
stylist: booking.stylist
},
message: 'Booking berhasil!'
};
}Natural Conversation Example
👤: Hai mau booking
🤖: Hai Kak! Selamat datang di [Salon] 💇♀️
Mau booking untuk layanan apa nih?
1️⃣ Potong Rambut - Rp 75k
2️⃣ Hair Coloring - Rp 350k
3️⃣ Creambath - Rp 150k
4️⃣ Hair Treatment - Rp 250k
5️⃣ Manicure Pedicure - Rp 200k
6️⃣ Facial - Rp 300k
---
👤: Mau creambath, hari sabtu bisa?
🤖: Creambath ya kak! ✨
Sabtu ini tanggal 22 Februari ya?
Jam berapa yang nyaman kak?
Slot tersedia:
- 09:00, 10:00, 11:00
- 13:00, 14:00, 15:00
- 17:00, 18:00, 19:00
---
👤: Jam 2 siang aja
🤖: Oke kak, aku cek dulu ya...
[check_availability called]
✅ Slot tersedia!
📋 Konfirmasi booking:
━━━━━━━━━━━━━━━━━━━━
💇 Layanan: Creambath
📅 Tanggal: Sabtu, 22 Feb 2026
⏰ Jam: 14:00 (1 jam)
💰 Harga: Rp 150.000
━━━━━━━━━━━━━━━━━━━━
Boleh tau nama lengkapnya kak?
---
👤: Dina Pratiwi
🤖: Baik Kak Dina! 😊
Nomor WA ini yang akan dihubungi ya?
(untuk reminder H-1)
---
👤: Iya bener
🤖: [create_booking called]
✅ BOOKING BERHASIL!
📋 Detail Booking:
━━━━━━━━━━━━━━━━━━━━
🎫 Kode: #BK-20260222-001
👤 Nama: Dina Pratiwi
💇 Layanan: Creambath
📅 Sabtu, 22 Feb 2026
⏰ 14:00 WIB
📍 [Alamat Salon]
━━━━━━━━━━━━━━━━━━━━
💡 Info:
- Datang 10 menit lebih awal ya
- Reminder akan dikirim H-1
- Reschedule? Reply UBAH
Sampai jumpa Kak Dina! 💕Reminder System
javascript
async function sendReminder(booking, type) {
const templates = {
'H-1': `⏰ REMINDER BESOK!
Hai Kak ${booking.customerName}!
Jangan lupa appointment besok ya:
📅 ${formatDate(booking.date)}
⏰ ${booking.time}
💇 ${booking.service}
📍 [Alamat]
Reply OK untuk konfirmasi!
Reply UBAH untuk reschedule.`,
'H-day': `🌅 HARI INI!
Hai Kak ${booking.customerName}!
Appointment kamu HARI INI:
⏰ ${booking.time}
📍 [Alamat]
Sampai jumpa! 😊`
};
await sendWhatsApp(booking.customerPhone, templates[type]);
}Best Practices
DO ✅
- Konfirmasi setiap detail
- Kirim reminder H-1 dan H-day
- Sediakan opsi reschedule mudah
- Handle edge cases (full, closed)
- Store booking dengan proper IDDON'T ❌
- Book tanpa konfirmasi
- No reminder
- Complicated reschedule
- Ignore availability check
- Manual booking IDFAQ
Bisa handle reschedule?
Ya! Tambahkan function reschedule_booking dan handle keyword "ubah jadwal".
Kalau slot penuh semua?
Tawarkan hari lain atau masukkan ke waiting list.
Kesimpulan
AI Booking = 24/7 reservation!
| Manual Booking | AI Booking |
|---|---|
| Limited hours | 24/7 |
| Phone calls | WhatsApp chat |
| Human error | Consistent |
| No reminder | Auto reminder |