Install
Add calsdk and a provider package to a TypeScript project.
calsdk is split into a core package and one package per calendar, so your app only installs the providers it talks to. Start with @cal-sdk/core and one provider:
npm install @cal-sdk/core @cal-sdk/googlePick your providers
| Calendar | Package | Function |
|---|---|---|
| Google Calendar | @cal-sdk/google | google() |
| Microsoft Outlook | @cal-sdk/microsoft | microsoft() |
| iCloud, Zoho Calendar, any CalDAV server | @cal-sdk/caldav | icloud(), zoho(), caldav() |
| Cal.com | @cal-sdk/calcom | calcom() |
| Calendly | @cal-sdk/calendly | calendly() |
| Zoom | @cal-sdk/zoom | zoom() |
| ICS feeds | @cal-sdk/ics | ics() |
| In-memory, for tests and examples | @cal-sdk/mock | mockCalendar() |
Not sure which one fits? Choose a provider walks through the credentials each one needs.
Requirements
Every package is ESM only. Providers talk to their APIs with fetch and nothing else, so they run on Node.js 20 or later, Bun, Deno and edge runtimes. CI checks this by running the quickstart in Deno with no file, network or environment access.
TypeScript is optional, but worth it here. Provider options and metadata are typed by the provider you pass, so typos are caught before they reach an API.
Keep credentials on the server
Providers take OAuth access tokens, API keys or app passwords, which is everything someone needs to read and change a user's calendar. Create providers in server code, such as a route handler, a server action or a background job, and never ship them to the browser.
calsdk doesn't run OAuth flows or refresh tokens: your app owns the user's account, so it owns the tokens too. Pass a token, or a function that returns a fresh one. calsdk calls the function before each request, so it can refresh and cache tokens however your app already does:
import { google } from '@cal-sdk/google';
const calendar = google({
accessToken: async () => {
const account = await db.calendarAccounts.find(userId);
return account.expiresAt > Date.now() ? account.accessToken : refresh(account);
},
});