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 intervalsHow 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 rowsEventManager (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:
- Checks the access-token expiry.
- If expired, calls the provider's refresh endpoint.
- Re-encrypts the new tokens and writes them back via
packages/features/credentials. - 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 repositories —
packages/features/selectedCalendar,packages/features/calendars.
Entry points for modification
- Add a calendar provider: scaffold via
yarn create-app(calendar template). Implementlib/CalendarService.tsextendingBaseCalendarService. Add OAuth handlers inapi/. Runyarn app-store:buildso the provider is registered incalendar.services.generated.ts. - Add a free/busy heuristic: edit
packages/features/busyTimes. - Change destination calendar selection: edit
packages/features/calendarsand the event-type editor's destination tab.
Related pages
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.