# Calendars (https://www.cal-sdk.com/docs/guides/calendars)

Most accounts hold more than one calendar: the user's own, a shared team calendar, someone's holidays. When your app needs to put an event somewhere other than the default, or let the user choose where it goes, start with `listCalendars`:

```ts
import { listCalendars } from '@cal-sdk/core';

const { calendars } = await listCalendars({ calendar });

for (const item of calendars) {
  console.log(item.id, item.name, item.isPrimary, item.accessRole, item.timeZone);
}
```

Exactly one calendar in the list has `isPrimary: true`.

## The `'primary'` id [#the-primary-id]

You often don't need the list at all. Every function that takes a `calendarId` defaults to `'primary'`, and every provider resolves it to the user's default calendar, so you only pass a `calendarId` when you want a different one:

```ts
const { calendars } = await listCalendars({ calendar });
const team = calendars.find((item) => item.name === 'Team');

if (team) await createEvent({ calendar, calendarId: team.id, event });
```

What counts as the default depends on the provider. Booking tools don't have calendars in the usual sense, so calsdk maps what they do have:

| Provider        | `'primary'` is                                                  |
| --------------- | --------------------------------------------------------------- |
| Google, Outlook | The account's default calendar                                  |
| CalDAV          | The server's default calendar for invitations, or else the first calendar that holds events |
| Cal.com         | Every booking of the user. Each event type is another calendar, with the event type id as its id |
| Calendly, Zoom  | Every meeting the user hosts. There are no other calendars      |
| ICS             | The feed                                                        |

## Access roles [#access-roles]

Check `accessRole` before you offer a calendar as somewhere to save events. `owner` and `writer` can read and write events, and `reader` can only read them. A `freeBusyReader` sees nothing but busy times, so ask for those with [`getFreeBusy`](/docs/guides/free-time) instead of listing events.

## The `Calendar` shape [#the-calendar-shape]

<TypeTable
  type={{
    id: { type: 'string', description: 'Pass it as `calendarId`.', required: true },
    name: { type: 'string', required: true },
    description: { type: 'string' },
    timeZone: { type: 'string', description: "IANA time zone, such as 'Asia/Kolkata'." },
    color: { type: 'string', description: "Hex color, `'#RRGGBB'`." },
    isPrimary: { type: 'boolean', description: "The user's default calendar. 'primary' resolves to it.", required: true },
    accessRole: { type: "'owner' | 'writer' | 'reader' | 'freeBusyReader'", required: true },
    providerMetadata: { type: 'ProviderMetadata', description: 'Provider-specific fields, keyed by provider id.' },
  }}
/>
