Skip to content
← Community packages

Read Calendly event types, scheduled events, and invitees on the caller's account, with dry-run mutations.

Browse files

  • Integrations
  • calendly
  • calendar
  • scheduling
  • event-types
  • scheduled-events
  • invitees
  • oauth
  • pat
  • dry-run
License
MIT
Published
August 22, 2026
Pinned commit
0341360
Rating
No ratings yet
Forks
0
Stars
0
Adaptation effort

README

@kody/calendly

Intent

Reusable Calendly helpers so Kody agents can inspect the caller's event types, scheduled events, and invitees — not a shared platform calendar, and not Cal.com. Auth is a saved personal access token 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 calendlyPat (or connect OAuth) and call the helpers in your account. No personal Calendly scheduling URLs, user slugs, or organization URIs are hard-coded.

Use @kody/cal-com for Cal.com booking pages, slots, and webhooks. Use a Google Calendar helpers package for direct Google Calendar event CRUD.

Share this package as https://kody.codes/@kody/calendly (never a /community/{listing_id} URL).

Auth

Calendly has no built-in Kody OAuth app. Choose one lane:

LaneCredentialWhen to use
A. Personal access token (fastest)User secret calendlyPatInternal / single-account automation. Calendly recommends PATs for private apps.
B. Bring-your-own OAuthSaved integration named calendly (or another name you pass as integrationName)Multi-account or public apps. There is no built-in Calendly platform app.

Both lanes send Authorization: Bearer … to https://api.calendly.com. Do not paste tokens or client secrets into chat.

Lane A: Personal access token

  1. Create a token at Integrations → API & Webhooks. Grant users:read, event_types:read, scheduled_events:read, and scheduled_events:write for the helpers in this package.
  2. Save it in Kody (do not paste the value in chat):
https://kody.codes/account/secrets/new?name=calendlyPat&description=Calendly%20personal%20access%20token%20(Bearer%20token%20for%20api.calendly.com)&allowedHosts=api.calendly.com&scope=user
  1. In the account secrets UI, approve host api.calendly.com.
  2. Smoke-test with ./smoke-test (see Smoke test).

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

Lane B: OAuth

Create an OAuth app at developer.calendly.com. Register the redirect URI exactly:

https://kody.codes/connect/oauth

Use Production for live account data. Calendly shows the client secret only once. Then open this prefilled connect URL while signed in to Kody and paste the client ID and client secret into the setup form (flow=confidential plus S256 PKCE):

https://kody.codes/connect/oauth?provider=calendly&authorizeUrl=https%3A%2F%2Fauth.calendly.com%2Foauth%2Fauthorize&tokenUrl=https%3A%2F%2Fauth.calendly.com%2Foauth%2Ftoken&apiBaseUrl=https%3A%2F%2Fapi.calendly.com&scopes=users%3Aread%20event_types%3Aread%20scheduled_events%3Aread%20scheduled_events%3Awrite&flow=confidential&pkce=true&allowedHosts=api.calendly.com%2Cauth.calendly.com&dashboardUrl=https%3A%2F%2Fdeveloper.calendly.com%2F&providerSetupInstructions=Create%20an%20OAuth%20app%20at%20https%3A%2F%2Fdeveloper.calendly.com%2F.%20Register%20redirect%20URI%20exactly%20https%3A%2F%2Fkody.codes%2Fconnect%2Foauth.%20Use%20Production%20for%20live%20account%20data.%20Calendly%20shows%20the%20client%20secret%20only%20once.%20Paste%20the%20client%20id%20and%20client%20secret%20into%20this%20Kody%20form.%20Request%20scopes%20users%3Aread%20event_types%3Aread%20scheduled_events%3Aread%20scheduled_events%3Awrite.%20Do%20not%20paste%20secrets%20into%20chat.

Decoded: authorize https://auth.calendly.com/oauth/authorize, token https://auth.calendly.com/oauth/token, scopes users:read event_types:read scheduled_events:read scheduled_events:write, hosts api.calendly.com,auth.calendly.com.

Call helpers with integrationName: "calendly" (or your chosen provider name). secretName selects the PAT lane and ignores integrationName unless you also pass auth: "oauth". When both a calendly integration and calendlyPat exist, helpers prefer OAuth unless you pass auth: "pat".

Reconnect later at https://kody.codes/connect/oauth?provider=calendly.

To connect a second account, change provider (for example provider=calendly-work) and pass account: "work" or integrationName: "calendly-work" / secretName: "calendlyPat-work" on every call.

Hosts

  • api.calendly.com — all REST calls (required)
  • auth.calendly.com — OAuth authorize + token (OAuth lane)

Scopes

ScopeNeeded for
users:read./get-user, ./smoke-test
event_types:read./list-event-types, ./get-event-type, ./get-available-times
scheduled_events:read./list-scheduled-events, ./get-scheduled-event, ./list-invitees, ./get-invitee
scheduled_events:write./cancel-scheduled-event, ./create-invitee, ./mark-no-show

If Calendly returns 401/403 or an insufficient-scope error, helpers throw a message that names the missing scope and the next setup URL.

Mutation safety

Pass dryRun: true on cancel-scheduled-event, create-invitee, mark-no-show, and mutating request calls to return { dryRun: true, wouldCall } without contacting Calendly.

Those same writes also throw unless confirm: true.

import cancelScheduledEvent from 'kody:@kody/calendly/cancel-scheduled-event'

const preview = await cancelScheduledEvent({
	event: 'AAAAAAAAAAAAAAAA',
	reason: 'Need to reschedule',
	dryRun: true,
})

const canceled = await cancelScheduledEvent({
	event: 'AAAAAAAAAAAAAAAA',
	reason: 'Need to reschedule',
	confirm: true,
})

Smoke test

Run this from execute after the PAT (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: 'calendly',
		exportName: './smoke-test',
	})
}

Pass the bare kody id calendly, not @kody/calendly.

Without calendlyPat (and without a connected calendly integration) this still returns { ok: true, live: false } plus the setup URLs. With credentials it reads a trimmed /users/me profile and does not return email.

Dry-run preview (no network):

import calendly from 'kody:@kody/calendly'

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

Exports

  • kody:@kody/calendly — action dispatcher (defaults to smoke-test)
  • kody:@kody/calendly/accounts — resolve integration/secret names and setup URLs
  • kody:@kody/calendly/smoke-test — credential smoke test (read-only)
  • kody:@kody/calendly/get-user — authorizing user (read-only, no email)
  • kody:@kody/calendly/list-event-types — list event types (read-only)
  • kody:@kody/calendly/get-event-type — event type detail (read-only)
  • kody:@kody/calendly/get-available-times — bookable start times (read-only)
  • kody:@kody/calendly/list-scheduled-events — list scheduled events (read-only)
  • kody:@kody/calendly/get-scheduled-event — scheduled event detail (read-only)
  • kody:@kody/calendly/cancel-scheduled-event — cancel an event (dryRun / confirm)
  • kody:@kody/calendly/list-invitees — list invitees (read-only)
  • kody:@kody/calendly/get-invitee — invitee detail (read-only)
  • kody:@kody/calendly/create-invitee — book a time (dryRun / confirm)
  • kody:@kody/calendly/mark-no-show — mark an invitee no-show (dryRun / confirm)
  • kody:@kody/calendly/request — low-level Calendly API escape hatch
  • kody:@kody/calendly/types — shared TypeScript types

Examples

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

export default async function main() {
	return await listEventTypes({ active: true, count: 20 })
}
import listScheduledEvents from 'kody:@kody/calendly/list-scheduled-events'
import listInvitees from 'kody:@kody/calendly/list-invitees'

export default async function main() {
	const { items } = await listScheduledEvents({ status: 'active', count: 10 })
	if (!items[0]) return { items, invitees: [] }
	return await listInvitees({ event: items[0].uuid })
}
import createInvitee from 'kody:@kody/calendly/create-invitee'

export default async function main() {
	return await createInvitee({
		eventType: 'AAAAAAAAAAAAAAAA',
		startTime: '2026-06-01T16:00:00Z',
		invitee: { name: 'Ada', email: 'ada@example.com', timezone: 'America/Denver' },
		dryRun: true,
	})
}

Notes

  • REST base: https://api.calendly.com
  • List helpers return { items, pageInfo }. Get helpers return a slim resource.
  • Uuids may be bare or full https://api.calendly.com/... URIs.
  • POST /invitees (create-invitee) can require a paid Calendly plan.
  • This package is not affiliated with or endorsed by Calendly.

Branding

community-icon.svg is Calendly's official brand mark (the C-in-circle logomark from Calendly's public media kit, color #006BFF). Paths are unmodified except for a square tile so the mark stays legible at 56 pixels. Calendly® is a trademark of Calendly. This package is not affiliated with or endorsed by Calendly.

Docs

Report this listing

Log in to report this listing.