Create a Google Calendar event the moment a customer books on WhatsApp, and send automatic appointment reminders before the slot. No more manual diary entries or missed follow-ups.
Before following this guide, read the External API Request step foundation guide. It covers every field in the step interface so this guide can focus on Calendar-specific values.
Use case 1 (WA.Expert calls Google): customer books on WhatsApp, automation creates a Calendar event. Use case 2 (Google calls WA.Expert): upcoming event triggers a WhatsApp reminder. Both are covered in this guide.
Creating or reading Calendar events via the Google Calendar API requires an OAuth access token, not a plain API key. The simplest path for both use cases is Apps Script, which runs as your own Google account and has calendar access without any token exchange in WA.Expert.
CalendarApp.function doPost(e) {{
var data = JSON.parse(e.postData.contents);
var cal = CalendarApp.getDefaultCalendar();
// Parse start time from ISO string, e.g. '2026-06-25T10:00:00'
var start = new Date(data.start_datetime);
var end = new Date(data.end_datetime);
var options = {{
description: data.description || '',
guests: data.customer_email || '',
sendInvites: true
}};
var event = cal.createEvent(
data.title,
start,
end,
options
);
return ContentService
.createTextOutput(JSON.stringify({{
status: 'ok',
event_id: event.getId(),
link: event.getEventSeriesId()
}}))
.setMimeType(ContentService.MimeType.JSON);
}}Body:
{{
"title": "Consultation: Priya Sharma",
"start_datetime": "2026-06-25T10:00:00",
"end_datetime": "2026-06-25T10:30:00",
"description": "WhatsApp booking — product demo request",
"customer_email": "priya@example.com"
}}
Response:
{{"status": "ok", "event_id": "abc123_2026062510@google.com"}}
"The event appears in your Google Calendar immediately.
The customer receives a Google Calendar invite if customer_email is provided.Pass dates as ISO 8601 strings: 2026-06-25T10:00:00. The script parses them with new Date(). Collect the slot from the customer in WhatsApp as a variable, or build the string from separate date and time variables: {{slot_date}}T{{slot_time}}:00.
Set up a daily Apps Script trigger that reads tomorrow's events and posts each one to WA.Expert with the customer's phone number, so WA.Expert sends a WhatsApp reminder.
var WA_WEBHOOK = 'YOUR_WA_EXPERT_WEBHOOK_URL';
function sendReminders() {{
var cal = CalendarApp.getDefaultCalendar();
var tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
var events = cal.getEventsForDay(tomorrow);
events.forEach(function(event) {{
var desc = event.getDescription();
// Extract phone from description (e.g. 'phone:+919820000001')
var match = desc.match(/phone:([\+0-9]+)/);
if (!match) return;
var payload = {{
phone: match[1],
title: event.getTitle(),
startTime: event.getStartTime().toLocaleString('en-IN'),
location: event.getLocation() || 'your scheduled session'
}};
UrlFetchApp.fetch(WA_WEBHOOK, {{
method: 'post',
contentType: 'application/json',
payload: JSON.stringify(payload)
}});
}});
}}
// Add a time-driven trigger: Triggers -> Add Trigger
// sendReminders -> Time-driven -> Day timer -> 8am-9amWhen creating the event (Use case 1), include the customer's WhatsApp number in the event description using a parseable format like phone:+919820000001. The reminder script then extracts it with a regex and sends the reminder to the right number.
If you prefer the direct API, here is the create-event endpoint. You need a valid OAuth access token from a service account.
POST https://www.googleapis.com/calendar/v3/calendars/primary/events
?sendUpdates=all
Authorization: Bearer YOUR_OAUTH_ACCESS_TOKEN
Content-Type: application/json
Body:
{{
"summary": "Consultation: Priya Sharma",
"description": "WhatsApp booking",
"start": {{"dateTime": "2026-06-25T10:00:00+05:30",
"timeZone": "Asia/Kolkata"}},
"end": {{"dateTime": "2026-06-25T10:30:00+05:30",
"timeZone": "Asia/Kolkata"}},
"attendees": [{{"email": "priya@example.com"}}]
}}
Response (HTTP 200):
{{
"kind": "calendar#event",
"id": "abc123",
"htmlLink":"https://calendar.google.com/calendar/event?eid=...",
"status": "confirmed"
}}
Map: id -> event_id, htmlLink -> calendar_link| Field | Value | Notes |
|---|---|---|
| calendarId | primary | 'primary' for your main calendar. |
| summary | Event title | What appears in the calendar. |
| start.dateTime | RFC 3339 datetime | e.g. 2026-06-25T10:00:00+05:30 |
| start.timeZone | IANA timezone | e.g. Asia/Kolkata |
| attendees[].email | Customer email | Sends a calendar invite if sendUpdates=all. |
| sendUpdates query param | all / externalOnly / none | all sends invites to all attendees. |
Customer: 'I want to book a consultation'
Bot collects:
{{customer_name}} = Priya Sharma
{{customer_email}} = priya@example.com
{{slot_date}} = 2026-06-25
{{slot_time}} = 10:00
External API Request step:
POST https://script.google.com/macros/s/AKfy.../exec
Body:
title: 'Consultation: Priya Sharma'
start_datetime: '2026-06-25T10:00:00'
end_datetime: '2026-06-25T10:30:00'
description: 'phone:+919820000001'
customer_email: 'priya@example.com'
Response: {{status: 'ok', event_id: '...'}}
WA.Expert replies to Priya:
'Your appointment is confirmed for 25 June at 10:00 AM.
You will receive a reminder on WhatsApp the day before.
See you then!'
Next morning (8 AM), the daily reminder script fires:
Reads tomorrow's event for Priya
Extracts phone from description: +919820000001
Posts to WA.Expert webhook
WA.Expert sends Priya:
'Reminder: your consultation is tomorrow at 10:00 AM.
Reply CONFIRM to confirm or CANCEL to reschedule.'| Symptom | Likely cause | Fix |
|---|---|---|
| Event not created | Script not deployed or wrong URL | Ensure you deployed as a Web App (not just saved). Use the /exec URL, not the /dev URL. Redeploy after any script changes. |
| Date parsing error | Invalid datetime string | Pass ISO 8601 format: 2026-06-25T10:00:00. Ensure the variable contains the full datetime, not just a date or time. |
| No invite sent to customer | sendInvites not set or no email provided | Include customer_email in the payload and set sendInvites: true in the script. For the direct API, add sendUpdates=all as a query parameter. |
| Reminder not firing | Missing time-driven trigger | In Apps Script, add a trigger: Triggers -> Add Trigger -> sendReminders -> Time-driven -> Day timer -> 8am-9am. |
| Direct API 401 | Invalid or expired OAuth token | Access tokens expire after about an hour. Use the Apps Script method to avoid token management entirely. |
| Calendar event goes to wrong calendar | Default calendar is not what you expect | Use CalendarApp.getCalendarById('calendar@email.com') to target a specific calendar instead of getDefaultCalendar(). |
Calendly webhooks: simpler booking integration with native webhook support.
Read guide →Log WhatsApp bookings to a Google Sheet alongside the Calendar event.
Read guide →Free trial, no credit card. If you get stuck, we answer live on WhatsApp.