Calendar Functions
Four edge functions handle calendar OAuth, availability checking, and event creation. All support dual-mode operation -- they work with both client-owned calendars (calendar_connections) and user-owned calendars (user_calendar_connections).
google-calendar-callback
Handles the OAuth callback after a user authorizes Google Calendar access. Exchanges the authorization code for tokens and stores them.
Flow
State Parameter Parsing
const state = url.searchParams.get('state');
const parts = state.split(':');
if (parts[0] === 'user') {
// Internal mode
const userId = parts[1]; // user:{userId}:{provider}
const provider = parts[2];
// Upsert into user_calendar_connections
} else {
// Client mode
const clientId = parts[0]; // {clientId}:{provider}
const provider = parts[1];
// Upsert into calendar_connections
}
Side Effects
- Upserts
calendar_connectionsoruser_calendar_connectionswith tokens - Sets
is_active = true - Stores
connected_emailfrom the token response
outlook-calendar-callback
Same as google-calendar-callback but for Microsoft Outlook/Office 365.
Differences from Google
- Token endpoint:
https://login.microsoftonline.com/common/oauth2/v2.0/token - Scopes:
Calendars.ReadWrite,offline_access - Calendar ID discovery via Microsoft Graph API
- Stores
provider = 'outlook'
Side Effects
- Same dual-mode upsert as Google callback
- Redirects to the same destinations based on state format
get-calendar-availability
Checks calendar busy times for a specific date to calculate available booking slots. Called by the booking page when a user selects a date.
Input
interface AvailabilityRequest {
bookingLinkId: string; // UUID of the booking link
date: string; // ISO date string (YYYY-MM-DD)
}
Flow
Slot Calculation Logic
- Load the owner's availability settings (e.g., Monday 9:00-17:00)
- Generate all possible slots for the requested date at the booking link's
duration_minutesinterval - Query the calendar provider's FreeBusy API for busy times on that date
- Subtract busy times from available slots
- Return remaining open slots
Output
interface AvailabilityResponse {
slots: Array<{
start: string; // ISO datetime
end: string; // ISO datetime
}>;
}
Token Refresh
If the stored access token is expired, the function automatically refreshes it:
if (new Date(connection.token_expires_at) < new Date()) {
const newTokens = await refreshOAuthToken(connection);
await supabaseAdmin
.from(tableName)
.update({
access_token: newTokens.access_token,
token_expires_at: new Date(Date.now() + newTokens.expires_in * 1000).toISOString(),
})
.eq('id', connection.id);
}
create-calendar-event
Creates an event in the owner's calendar (Google or Outlook) when a meeting is booked.
Input
interface CreateEventRequest {
bookingLinkId: string;
slot: { start: string; end: string };
bookerName: string;
bookerEmail: string;
bookerPhone?: string;
// For internal mode:
salesMeetingId?: string;
prospectId?: string;
// For client mode:
meetingId?: string;
contactId?: string;
}
Flow
Side Effects
- Creates event in Google Calendar or Outlook
- Updates
meetingsorsales_meetingswithcalendar_event_idandmeeting_link - Triggers
send-booking-notificationfor confirmation email - Google events include a Google Meet link automatically
- Outlook events include a Teams link if the organization supports it