Open-Source Wikis

/

Cal.com

/

Features

/

Calendars

calcom/cal.com

Calendars

Active contributors: Pedro, Hariom, Joe, Lauris

Purpose

Calendar federation is the layer that lets Cal.diy read free/busy from any number of external calendars and write confirmed events into a single chosen destination calendar. It abstracts over Google, Microsoft (Office 365 / Exchange / Outlook), Apple, CalDAV, ICS feeds, Lark, Feishu, Zoho — anything that implements the Calendar interface.

Where it lives

Concern Code
Domain logic packages/features/calendars/
Provider adapters packages/app-store/<provider>calendar/lib/CalendarService.ts
Base adapter class packages/lib/CalendarService.ts (37 KB)
Event payload parser packages/lib/CalEventParser.ts
Calendar interface packages/types/Calendar.d.ts
Selected calendars (read) SelectedCalendar model + packages/features/selectedCalendar
Destination calendar (write) DestinationCalendar model + packages/features/calendars
Push subscription / webhooks packages/features/calendar-subscription
Busy-time aggregation packages/features/busyTimes
Unified calendar view (API v2) apps/api/v2/src/modules/cal-unified-calendars

Key abstractions

Symbol Purpose
Calendar interface (packages/types/Calendar.d.ts) The contract every adapter implements: createEvent, updateEvent, deleteEvent, getAvailability, listCalendars, optional push-subscription methods
BaseCalendarService (packages/lib/CalendarService.ts) Concrete base class with OAuth refresh + redaction — most adapters extend it
CalEventParser (packages/lib/CalEventParser.ts) Translates Cal.com's internal event shape to vendor JSON / iCal
CalendarSubscriptionService (packages/features/calendar-subscription) Manages provider push notifications (Google watch, MS subscriptions)
getBusyTimes (packages/features/busyTimes) Aggregates busy-time intervals from every selected calendar

How it works (read path)

sequenceDiagram
    participant Slots as features/slots
    participant Busy as features/busyTimes
    participant SelectedCals as features/selectedCalendar
    participant Cred as features/credentials
    participant Adapter as app-store/<provider>/CalendarService
    participant Vendor as Vendor API

    Slots->>Busy: getBusyTimes(userId, dateRange)
    Busy->>SelectedCals: list(userId)
    SelectedCals-->>Busy: SelectedCalendar[] (calendarId + integration + externalId)
    loop per selected calendar
        Busy->>Cred: getCredential(userId, app type)
        Cred-->>Busy: encrypted Credential
        Busy->>Adapter: getAvailability(start, end, [externalId])
        Adapter->>Vendor: free/busy query (with auto-refresh)
        Vendor-->>Adapter: busy intervals
        Adapter-->>Busy: EventBusyDate[]
    end
    Busy-->>Slots: merged busy intervals

How it works (write path)

sequenceDiagram
    participant Booking as RegularBookingService
    participant EM as EventManager
    participant Dest as DestinationCalendar
    participant Adapter as app-store/<provider>/CalendarService
    participant Vendor as Vendor API
    participant Refs as BookingReference

    Booking->>EM: create(event)
    EM->>Dest: get organizer's destination calendar
    EM->>Adapter: createEvent(event)
    Adapter->>Vendor: HTTP POST
    Vendor-->>Adapter: { id, iCalUID, htmlLink, ... }
    Adapter-->>EM: result
    EM->>Refs: write BookingReference rows

EventManager (packages/features/bookings/lib/EventManager.ts) is where multiple calendars / video providers are coordinated. It handles partial failures (e.g., calendar create succeeds but video create fails), updates references, and rolls back where possible.

OAuth refresh and credentials

Every credential is stored in the Credential Prisma table with the key JSON column encrypted. Adapters call into BaseCalendarService for token refresh, which:

  1. Checks the access-token expiry.
  2. If expired, calls the provider's refresh endpoint.
  3. Re-encrypts the new tokens and writes them back via packages/features/credentials.
  4. Retries the original request.

AGENTS.md is explicit: never expose credential.key in any query. Every repository that touches it must select only the columns it needs.

Push notifications

For providers that support push (Google Calendar, Microsoft Graph), packages/features/calendar-subscription registers a webhook subscription on credential install and renews it on a schedule. Incoming pushes land at apps/web/pages/api/integrations/<provider>/webhook and trigger a re-fetch of the affected calendar window.

Unified calendar view

The API v2 module cal-unified-calendars (apps/api/v2/src/modules/cal-unified-calendars) exposes a single endpoint that returns events from every selected calendar, normalized through CalEventParser. This is what the React <CalendarView /> atom in packages/platform/atoms/calendar-view consumes.

Integration points

  • Bookings — both read (via slots) and write (via EventManager).
  • App Store — every calendar provider lives under packages/app-store/*calendar.
  • Selected/Destination repositoriespackages/features/selectedCalendar, packages/features/calendars.

Entry points for modification

  • Add a calendar provider: scaffold via yarn create-app (calendar template). Implement lib/CalendarService.ts extending BaseCalendarService. Add OAuth handlers in api/. Run yarn app-store:build so the provider is registered in calendar.services.generated.ts.
  • Add a free/busy heuristic: edit packages/features/busyTimes.
  • Change destination calendar selection: edit packages/features/calendars and the event-type editor's destination tab.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Calendars – Cal.com wiki | Factory