Skip to Content
📱 Using the Appcreating-events

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 accessRole of “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:

  1. Enter an email address in the Email address field
  2. Tap Add to add the invitee to the list
  3. The app creates an EventAttendee with responseStatus = "needsAction"
  4. Repeat for additional invitees
  5. 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 timestamp
  • timezone: Time zone ID
  • duration: Calculated duration in minutes
  • settings: 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:

  1. Refreshes the calendar from Zoom’s API to fetch the new event
  2. Updates local storage with the refreshed events
  3. Triggers a widget refresh via forceWidgetRefresh(context)
  4. Returns to the home screen

The status message changes from “Creating event…” to “Event created.” on success.

Verify Event Creation

After creating an event:

  1. Check the widget: The new event should appear in the widget within a few seconds
  2. Open the app: Tap the event in the widget to view full details
  3. Verify Zoom meeting: For Zoom Meeting events, check that the “Join Zoom” button appears in the event details
  4. 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:

  1. Wait 15 seconds for the automatic refresh
  2. Tap the refresh button (↻) in the widget header
  3. 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.