Last Updated: 6/9/2026
Creating Calendar Events
Create new calendar events directly from ZCal Buddy with full control over event details, attendees, and Zoom meeting settings. The app automatically generates Zoom meetings for “Zoom Meeting” events and syncs them to your calendar.
Prerequisites
- Zoom account connected to ZCal Buddy
- At least one writable calendar (requires
accessRoleof “owner” or “writer”) - Internet connection for API calls
Starting Event Creation
Open ZCal Buddy and tap New Event on the home screen, or tap the + button in the widget header. The app opens the CreateEventScreen composable.
The screen loads your writable calendars:
val writableCalendars = calendars.filter { it.canWrite }If no writable calendars are found, the app provides a default calendar entry to ensure you can create events.
Event Creation Form
Event Name
Enter the event title in the Event Name field. This becomes the calendar event summary and, for Zoom Meeting events, the meeting topic. If left blank, Zoom meetings default to “Zoom Meeting” as the topic.
Date and Time
Start Date/Time: Tap the date button to open a date picker. Tap the time button to open a time picker. The default start time is one hour from now, rounded to the nearest hour:
val defaultStart = LocalTime.now().plusHours(1).withMinute(0)End Date/Time: Defaults to one hour after the start time. When you change the start time, the end time automatically adjusts to maintain a one-hour duration:
onStartTimeChange = { newStart ->
startTime.value = newStart
endTime.value = TimeSelection.fromLocalTime(
newStart.toLocalTime().plusHours(1)
)
}All Day: Toggle the All Day switch to create an all-day event. This hides the time pickers and creates an event spanning the entire day.
Time Zone: The time zone field defaults to your device’s system time zone (ZoneId.systemDefault().id). You can edit this to create events in different time zones. The time zone is passed to Zoom’s meeting API and stored with the calendar event.
Event Type
Choose between two event types using the Event Type dropdown:
Offline: Standard calendar event without a Zoom meeting. Location and description fields are available but not required. No meeting is created in Zoom.
Zoom Meeting: Calendar event with an automatically generated Zoom meeting. When you select this type, the app displays additional meeting settings (see Meeting Settings section below).
The event type determines whether the app calls createZoomMeeting before creating the calendar event.
Calendar Selection
Use the Calendar dropdown to choose which calendar receives the event. The dropdown shows only calendars where canWrite == true:
val canWrite: Boolean
get() = accessRole.equals("owner", true) ||
accessRole.equals("writer", true)The dropdown displays each calendar’s summary property (typically the calendar name or email address).
Invitees
Add attendees to your event:
- Enter an email address in the Email address field
- Tap Add to add the invitee to the list
- The app creates an
EventAttendeewithresponseStatus = "needsAction" - Repeat for additional invitees
- Tap Remove next to any invitee to remove them
The invitees list prevents duplicates using distinctBy { it.email.lowercase() }. All invitees are included in the calendar event and receive meeting invitations.
Location and Description
Location: Optional text field for event location. For Zoom Meeting events, this field is included in the calendar event but doesn’t affect the Zoom meeting itself.
Description: Optional text field for event notes. For Zoom Meeting events, this is included in both the calendar event and passed to the Zoom API.
Meeting Settings (Zoom Meeting Events Only)
When you select “Zoom Meeting” as the event type, the app displays a “Meeting settings” card with security and feature options. These settings are passed to createZoomMeeting:
Use Personal Meeting ID
Toggle: Use Personal Meeting ID
Parameter: usePmi (Boolean)
Default: false
When enabled, the meeting uses your Personal Meeting ID instead of generating a new meeting ID. Your PMI is a permanent meeting room associated with your Zoom account.
Security Settings
Require meeting passcode
Toggle: Require meeting passcode
Parameter: requirePasscode (Boolean)
Default: true
When enabled, attendees must enter a passcode to join the meeting. A passcode field appears below the toggle.
Passcode field
Parameter: passcode (String)
Default: "123456"
Enter a numeric passcode for the meeting. This is only sent to the API when requirePasscode == true:
if (requirePasscode && passcode.isNotBlank()) {
put("password", passcode)
}Waiting Room
Toggle: Waiting Room
Parameter: waitingRoom (Boolean)
Default: false
When enabled, participants wait in a virtual waiting room until the host admits them. This provides additional control over who joins your meeting.
Only authenticated users can join
Toggle: Only authenticated users can join
Parameter: authenticatedUsersOnly (Boolean)
Default: false
When enabled, only users signed in to a Zoom account can join the meeting. This is mapped to the meeting_authentication setting in the Zoom API.
AI Features
Automatically start AI Companion
Toggle: Automatically start AI Companion
Parameter: aiCompanion (Boolean)
Default: false
When enabled, Zoom’s AI Companion automatically starts when the meeting begins. This controls two API settings:
put("auto_start_meeting_summary", aiCompanion)
put("auto_start_ai_companion_questions", aiCompanion)Creating the Event
Tap the Save button at the bottom of the screen to create the event. The app performs these steps:
Step 1: Validate Access Token
The app retrieves a valid access token:
val accessToken = ZoomCalendarSyncService().getUsableAccessToken(context)
?: return@withContext "No saved Zoom access token. Connect Zoom again."If no token is found or the token is expired and can’t be refreshed, the operation fails with an error message.
Step 2: Create Zoom Meeting (If Applicable)
For “Zoom Meeting” events, the app calls createZoomMeeting:
val meetingResponse = authRepository.createZoomMeeting(
accessToken = accessToken,
title = title.value,
startDate = mmDdYyyyToIso(startDate.value),
startTime24 = startTime.value.to24Hour(),
endTime24 = endTime.value.to24Hour(),
timeZone = timeZone.value,
usePmi = usePmi.value,
requirePasscode = requirePasscode.value,
passcode = passcode.value,
waitingRoom = waitingRoom.value,
authenticatedUsersOnly = authenticatedUsersOnly.value,
aiCompanion = aiCompanion.value
)The function posts to https://api.zoom.us/v2/users/me/meetings with a JSON body containing:
topic: Event title (or “Zoom Meeting” if blank)type:2(scheduled meeting)start_time: RFC 3339 formatted timestamptimezone: Time zone IDduration: Calculated duration in minutessettings: Object with security and feature flags
The API returns a JSON response containing join_url, which is the Zoom meeting link.
Step 3: Create Calendar Event
The app calls createCalendarEvent with the event details and Zoom URL (if applicable):
authRepository.createCalendarEvent(
accessToken = accessToken,
calendarId = selectedCalendar.value.id,
title = title.value,
eventType = eventType.value,
allDay = allDay.value,
startDate = startDate.value,
startTime24 = startTime.value.to24Hour(),
endDate = endDate.value,
endTime24 = endTime.value.to24Hour(),
timeZone = timeZone.value,
description = description.value,
location = location.value,
zoomJoinUrl = zoomJoinUrl,
attendees = invitees.value
)This posts to https://api.zoom.us/v2/calendars/{calendarId}/events with the event data. The Zoom URL is included in the event’s conferencing data.
Step 4: Sync and Refresh
After successful creation, the app:
- Refreshes the calendar from Zoom’s API to fetch the new event
- Updates local storage with the refreshed events
- Triggers a widget refresh via
forceWidgetRefresh(context) - Returns to the home screen
The status message changes from “Creating event…” to “Event created.” on success.
Verify Event Creation
After creating an event:
- Check the widget: The new event should appear in the widget within a few seconds
- Open the app: Tap the event in the widget to view full details
- Verify Zoom meeting: For Zoom Meeting events, check that the “Join Zoom” button appears in the event details
- Check Zoom app: Open the Zoom app and navigate to Meetings to see the new meeting listed
Troubleshooting Event Creation
“No saved Zoom access token. Connect Zoom again.”
Your Zoom connection expired or was disconnected. Tap Connect Zoom on the home screen to re-authenticate.
“Event created.” but event doesn’t appear in widget
The event was created successfully but the widget hasn’t refreshed yet. Try:
- Wait 15 seconds for the automatic refresh
- Tap the refresh button (↻) in the widget header
- Check widget settings to ensure the event’s calendar is selected
Meeting created but no join URL
The Zoom API created the meeting but didn’t return a join URL. This can happen if:
- The API response was malformed
- Network issues interrupted the response
- Zoom service was temporarily unavailable
Edit the event and try adding the Zoom meeting again.
“We couldn’t complete that request. Try again.”
This generic error covers various API failures. Common causes:
- Network connectivity issues
- Zoom API rate limiting
- Invalid calendar ID or permissions
- Malformed request data
Check your internet connection and try again. If the error persists, verify your calendar permissions in Zoom’s settings.
Date and Time Format Details
The app uses specific date and time formats throughout the creation flow:
Display format: MM-dd-yyyy (e.g., “01-15-2024”)
ISO format: yyyy-MM-dd (e.g., “2024-01-15”) - used for API calls
Time format: HH:mm in 24-hour format (e.g., “14:30”) - used for API calls
Time display: 12-hour format with AM/PM (e.g., “2:30 PM”) - shown in UI
The TimeSelection data class handles conversion between 12-hour display format and 24-hour API format:
fun to24Hour(): String {
val hour24 = when {
period == "AM" && hour == 12 -> 0
period == "AM" -> hour
period == "PM" && hour == 12 -> 12
else -> hour + 12
}
return "${hour24.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}"
}What’s Next
After creating events, you may need to modify event details or meeting settings. See Editing Events to learn how to update existing events, add or remove Zoom meetings, and change meeting configurations.