Skip to content

Built for people who want to own their automations. Join the waitlist for an invite.

Package listing

@kody/cal-com

README.md

181 lines · 7.7 KB · Markdown

@kody/cal-com

Intent

Reusable Cal.com helpers so Kody agents can inspect booking pages, event types, availability slots, bookings, and webhooks on the caller's Cal.com account — not a shared platform calendar. Auth is a saved API key by default, or a bring-your-own OAuth client. Reads are free-form. Mutations support dryRun: true, and live writes also require confirm: true.

This listing is meant to be forked. After you fork, save your own calComApiKey (or connect OAuth) and call the helpers in your account. Booking URLs are built from the connected profile username plus each event-type slug (or the event type's own link). No personal Cal.com booking paths are hard-coded. The earlier @kentcdodds/cal-com listing stored cal-com-api-key; this official package uses calComApiKey.

Use a Google Calendar helpers package for direct Google Calendar event CRUD instead of Cal.com booking flows.

Auth

LaneCredentialWhen to use
A. API key (default)User secret calComApiKeyFastest. Cal.com recommends API keys for agents.
B. Bring-your-own OAuthSaved integration named cal-com (or another name you pass as integrationName)When you already have a Cal.com OAuth client, or need scoped tokens. There is no built-in Cal.com platform app.

Do not paste API keys or client secrets into chat.

Lane A: API key
  1. Create a key at Settings → Developer → API Keys. Keys look like cal_… or cal_live_….
  2. Save it in Kody (do not paste the value in chat):
https://kody.codes/account/secrets/new?name=calComApiKey&description=Cal.com%20API%20key%20(Bearer%20token%20for%20api.cal.com)&allowedHosts=api.cal.com&scope=user
  1. In the account secrets UI, approve host api.cal.com.
  2. Smoke-test with ./smoke-test (see Smoke test).

Default helper input: omit secretName and integrationName. The package sends Authorization: Bearer using calComApiKey.

Pass account: "work" to use secret calComApiKey-work, or pass secretName: "calComApiKey-live". There are no hard-coded account aliases.

Lane B: OAuth

Cal.com OAuth clients are created at Settings → Developer → OAuth and stay pending until a Cal.com admin approves them. Register the redirect URI exactly:

https://kody.codes/connect/oauth

Then open this prefilled connect URL while signed in to Kody. Paste the client ID and client secret into the setup form (flow=confidential):

https://kody.codes/connect/oauth?provider=cal-com&authorizeUrl=https%3A%2F%2Fapp.cal.com%2Fauth%2Foauth2%2Fauthorize&tokenUrl=https%3A%2F%2Fapi.cal.com%2Fv2%2Fauth%2Foauth2%2Ftoken&flow=confidential&scopes=PROFILE_READ%20EVENT_TYPE_READ%20BOOKING_READ%20SCHEDULE_READ%20WEBHOOK_READ%20WEBHOOK_WRITE%20BOOKING_WRITE&allowedHosts=api.cal.com%2Capp.cal.com&apiBaseUrl=https%3A%2F%2Fapi.cal.com&dashboardUrl=https%3A%2F%2Fapp.cal.com%2Fsettings%2Fdeveloper%2Foauth&providerSetupInstructions=Create%20an%20OAuth%20client%20at%20https%3A%2F%2Fapp.cal.com%2Fsettings%2Fdeveloper%2Foauth.%20Register%20redirect%20URI%20exactly%20https%3A%2F%2Fkody.codes%2Fconnect%2Foauth.%20Cal.com%20must%20approve%20the%20client%20before%20authorize%20works.%20Paste%20the%20client%20id%20and%20client%20secret%20into%20this%20form.

Decoded: authorize https://app.cal.com/auth/oauth2/authorize, token https://api.cal.com/v2/auth/oauth2/token, scopes PROFILE_READ EVENT_TYPE_READ BOOKING_READ SCHEDULE_READ WEBHOOK_READ WEBHOOK_WRITE BOOKING_WRITE, hosts api.cal.com,app.cal.com.

Call helpers with integrationName: "cal-com" (or your chosen provider name). secretName selects the API-key lane and ignores integrationName.

Reconnect later at https://kody.codes/connect/oauth?provider=cal-com.

This is not Cal.com Platform / managed-user auth (x-cal-client-id / x-cal-secret-key). Those credentials are a different product.

Hosts

  • api.cal.com — all REST calls (required)
  • app.cal.com — OAuth authorize + developer settings (OAuth lane)

Mutation safety

Pass dryRun: true on create-booking, cancel-booking, reschedule-booking, create-webhook, and mutating request calls to return { dryRun: true, method, path, body } without contacting Cal.com.

Those same writes also throw unless confirm: true.

import createBooking from 'kody:@kody/cal-com/create-booking'

const preview = await createBooking({
	eventTypeId: 123,
	start: '2026-06-01T16:00:00Z',
	attendee: { name: 'Ada', email: 'ada@example.com' },
	dryRun: true,
})

const booking = await createBooking({
	eventTypeId: 123,
	start: '2026-06-01T16:00:00Z',
	attendee: { name: 'Ada', email: 'ada@example.com' },
	confirm: true,
})

Smoke test

Run this from execute after the API key (or OAuth) is saved. Prefer packages.invoke so secret mounts and OAuth run in package runtime.

import { packages } from 'kody:runtime'

export default async function main() {
	return await packages.invoke({
		kodyId: 'cal-com',
		exportName: './smoke-test',
	})
}

Pass the bare kody id cal-com, not @kody/cal-com.

Without calComApiKey (and without a connected cal-com integration) this still returns { ok: true, live: false } plus the setup URLs. With credentials it reads a trimmed /me profile — no writes.

Dry-run preview (no network):

import smokeTest from 'kody:@kody/cal-com/smoke-test'

export default async function main() {
	return await smokeTest({ dryRun: true })
}

Exports

  • kody:@kody/cal-com — action dispatcher (defaults to smoke-test)
  • kody:@kody/cal-com/request — low-level Cal.com API request helper (escape hatch)
  • kody:@kody/cal-com/get-profile — account profile (read-only)
  • kody:@kody/cal-com/list-bookings — list bookings (read-only)
  • kody:@kody/cal-com/get-booking — booking detail (read-only)
  • kody:@kody/cal-com/create-booking — create booking (dryRun / confirm)
  • kody:@kody/cal-com/cancel-booking — cancel booking (dryRun / confirm)
  • kody:@kody/cal-com/reschedule-booking — reschedule booking (dryRun / confirm)
  • kody:@kody/cal-com/list-event-types — list event types (read-only)
  • kody:@kody/cal-com/get-event-type — event type detail (read-only)
  • kody:@kody/cal-com/get-available-slots — available slots (read-only)
  • kody:@kody/cal-com/list-webhooks — list webhooks (read-only)
  • kody:@kody/cal-com/create-webhook — create webhook (dryRun / confirm)
  • kody:@kody/cal-com/summarize-booking-pages — booking-page summary (read-only)
  • kody:@kody/cal-com/smoke-test — credential smoke test (read-only)

Examples

import listEventTypes from 'kody:@kody/cal-com/list-event-types'

export default async function main() {
	return await listEventTypes()
}
import getAvailableSlots from 'kody:@kody/cal-com/get-available-slots'

export default async function main() {
	return await getAvailableSlots({
		eventTypeId: 123,
		start: '2026-06-01',
		end: '2026-06-08',
		timeZone: 'America/Denver',
	})
}
import summarizeBookingPages from 'kody:@kody/cal-com/summarize-booking-pages'

export default async function main() {
	return await summarizeBookingPages()
}
import listWebhooks from 'kody:@kody/cal-com/list-webhooks'

export default async function main() {
	return await listWebhooks()
}

Branding

community-icon.svg is Cal.com's official wordmark (white "Cal" on #292929). Cal.com is a trademark of Cal.com, Inc. This package is not affiliated with or endorsed by Cal.com.

Docs