Calendly
Everything around a booking, in two nodes on one connected account. The action reads and acts: who booked what and when, cancelling an event, marking a no-show, the free slots of an event type and a booking link that works once — and can also be an AI toolkit. The trigger fires a flow when a meeting is booked, canceled or rescheduled, an invitee is marked no-show, a routing form is submitted or an event type changes.
Setup
Connect your Calendly account under Settings → Credentials (OAuth), or paste a personal access token, then pick the credential in the node — the trigger uses the same one. Calendly names everything by its full URI; wherever the node asks for an event, an invitee or a no-show, the URI or just the ID at its end both work. Whose — Mine or Whole organization — resolves to the account that connected; the whole organization needs a Calendly admin or owner.
Operations
| Value | In the dropdown | What it does |
|---|---|---|
| listEvents | List events | Scheduled events in a time window — yours or the organization's. Iterable over events. |
| getEvent | Get event | One event: start and end, event type, hosts, location, invitee count. |
| listInvitees | List invitees | Who booked an event, with their answers to the booking questions. Iterable over invitees. |
| cancelEvent | Cancel event | Cancels the event and emails the invitees, as when the host cancels. |
| markNoShow | Mark invitee as no-show | Marks an invitee of a past event as a no-show. |
| undoNoShow | Undo no-show | Removes a no-show mark, by the URI the mark returned. |
| listEventTypes | List event types | The event types on offer, with duration and scheduling URL. Iterable over eventTypes. |
| getAvailableTimes | Get available times | Free slots of an event type, up to 7 days, each with a URL that books exactly that slot. Iterable over slots. |
| createSchedulingLink | Create single-use scheduling link | A booking link for an event type that stops working after one booking. |
Dates without an offset (2026-10-01T09:00:00) are read in the operation's Time zone or, when none is picked, the workspace's. The node keeps Calendly's own field names (start_time, scheduling_url…), so its docs apply as they are.
AI toolkit mode
Once the credential is picked, the node asks for a Mode. AI toolkit turns it into nine tools that an AI Node — or an MCP client, through one of your MCP servers — calls by name. A scheduling assistant: it lists what is booked, offers free times and sends a link that books one of them.
| Tool | Arguments |
|---|---|
| list_events | whose? · status? · min_start_time? · max_start_time? · timezone? · invitee_email? · sort? · limit? |
| get_event | event |
| list_invitees | event · status? · invitee_email? · limit? |
| cancel_event | event · reason? — blocked by default |
| mark_no_show | invitee |
| undo_no_show | no_show |
| list_event_types | whose? · active_only? · limit? |
| get_available_times | event_type · start_time · end_time · timezone? |
| create_scheduling_link | event_type |
What you control
- Default event type. The one
get_available_timesandcreate_scheduling_linkuse when the model names none — like Slack's default channel. Empty, the Single operation's event type, if it is fixed; with neither, the model has to name one (list_event_typestells it which). - Characters per call sent to the model. 20,000 by default, anything from 1,000 to 200,000.
- Canceling starts blocked. It emails the invitee and can't be undone. Unblock
cancel_eventunder Block these tool calls if the agent needs it.
What goes back to the model
The same response as the operation. Lists return 20 unless the model asks for more, up to 100 — the model decides; a limit set in Single operation doesn't count in toolkit mode. Items that don't fit the characters limit are left out whole, with a notes field saying how many. Arguments are used as written: a {{payload.x}} the model writes is not resolved against the flow.
Testing a tool
operation in their payload that names another tool is refused.{ "operation": "get_available_times", "start_time": "2026-10-01T09:00:00-06:00", "end_time": "2026-10-03T18:00:00-06:00" }The trigger
Pick Calendly as the service on a Trigger node, and a Calendly credential — OAuth or a personal access token both work. Calendly calls HostWebhook the moment something happens; activating registers the webhook for you.
What fires it
Fires on takes one or more; pick at least one. Each run says which in operation:
| Fires on | operation | When |
|---|---|---|
| Meeting booked | booked | Someone books a time on one of the event types. |
| Meeting canceled | canceled | The invitee or the host cancels a booking. |
| Meeting rescheduled | rescheduled | The invitee moves a booking to another time — one run per reschedule. |
| Invitee marked no-show | no_show · no_show_undone | An invitee is marked as a no-show after the meeting, or the mark is removed. |
| Routing form submitted | routing_form | Someone fills in a routing form. Only with Whose = Whole organization. |
| Event type changed | event_type_created · event_type_updated · event_type_deleted | An event type is created, edited or deleted. |
Reschedules
In Calendly a reschedule is two things: the old time is canceled and a new booking is made. What reaches the flow depends on Meeting rescheduled:
- Picked — one run per reschedule, with
operationrescheduled: the new booking ininviteeandevent, the old one inprevious. The old time's cancellation doesn't run the flow on its own. - Not picked — it arrives as what it is in Calendly: the old time canceled, if Meeting canceled is picked (with
invitee.rescheduledset totrue), and a new booking, if Meeting booked is picked.
"previous": {
"inviteeUri": "https://api.calendly.com/scheduled_events/FFFFFFFFFFFFFFFF/invitees/GGGGGGGGGGGGGGGG",
"eventUri": "https://api.calendly.com/scheduled_events/FFFFFFFFFFFFFFFF",
"name": "30 Minute Meeting",
"startTime": "2026-10-01T15:00:00.000000Z",
"endTime": "2026-10-01T15:30:00.000000Z",
"reason": "Something came up",
"canceledBy": "Sam Rivera"
}If Calendly can't be read at that moment, previous carries only inviteeUri and the flow runs anyway.
Whose, and which event type
- Whose — Mine: the bookings on the connected account's event types. Whole organization: every member's, which needs the connected account to be an organization admin or owner. Routing forms only exist for the whole organization.
- Only this event type (optional) — one of the account's event types, picked from the list. Calendly can't filter a webhook by event type, so HostWebhook checks every delivery and drops those of other types before they reach the flow: bookings, cancellations, reschedules, no-shows and event-type changes. Routing form submissions aren't filtered.
Changing it while it's active
A new Only this event type counts from the next delivery, with nothing to apply. Changing Fires on or Whose changes what Calendly has to send, so the trigger asks you to Apply changes: the webhook is deleted in Calendly and created again. Ticking Meeting rescheduled next to Meeting booked and Meeting canceled doesn't ask — Calendly sends the same deliveries either way — and counts at once.
Every delivery is signed, and HostWebhook checks the signature before anything runs. Calendly's webhooks don't expire, so there is nothing to renew. Deactivating deletes the webhook in Calendly; reactivating registers a fresh one.
What the trigger sends downstream
Every run carries id, operation, calendlyEvent (Calendly's own name for it, like invitee.created), occurredAt, createdBy and raw — the delivery exactly as Calendly sent it, for anything not lifted to the top. A booking:
{
"id": "invitee.created:https://api.calendly.com/scheduled_events/DDDDDDDDDDDDDDDD/invitees/EEEEEEEEEEEEEEEE",
"operation": "booked",
"calendlyEvent": "invitee.created",
"occurredAt": "2026-09-30T16:02:11.000000Z",
"createdBy": "https://api.calendly.com/users/BBBBBBBBBBBBBBBB",
"invitee": {
"uri": "https://api.calendly.com/scheduled_events/DDDDDDDDDDDDDDDD/invitees/EEEEEEEEEEEEEEEE",
"uuid": "EEEEEEEEEEEEEEEE",
"name": "Sam Rivera",
"firstName": "Sam",
"lastName": "Rivera",
"email": "sam@example.com",
"timezone": "America/New_York",
"status": "active",
"answers": [
{ "question": "What would you like to talk about?", "answer": "Onboarding for my team" }
],
"rescheduled": false,
"rescheduleUrl": "https://calendly.com/reschedulings/EEEEEEEEEEEEEEEE",
"cancelUrl": "https://calendly.com/cancellations/EEEEEEEEEEEEEEEE",
"createdAt": "2026-09-30T16:02:10.512345Z",
"updatedAt": "2026-09-30T16:02:10.512345Z"
},
"event": {
"uri": "https://api.calendly.com/scheduled_events/DDDDDDDDDDDDDDDD",
"uuid": "DDDDDDDDDDDDDDDD",
"name": "30 Minute Meeting",
"status": "active",
"startTime": "2026-10-02T15:00:00.000000Z",
"endTime": "2026-10-02T15:30:00.000000Z",
"eventType": "https://api.calendly.com/event_types/CCCCCCCCCCCCCCCC",
"location": { "type": "google_conference", "location": null, "joinUrl": "https://meet.google.com/abc-defg-hij" },
"hosts": [{ "name": "Ana Host", "email": "ana@example.com" }],
"guests": [],
"inviteesCount": 1
},
"tracking": { "utm_source": "newsletter", "utm_campaign": null, "…": "…" },
"raw": { "…": "the delivery exactly as Calendly sent it" }
}Times come as Calendly sends them, in UTC; invitee.timezone is the invitee's own. The other operations:
canceled— the same, withinvitee.statuscanceledandcancellation:canceledBy,reasonandcancelerType(hostorinvitee).rescheduled— the new booking, the same as above, plusprevious(see Reschedules).no_showandno_show_undone—noShow(uri,uuid,invitee,createdAt) with theinviteeand theevent.{{payload.noShow.uri}}is what the action node's Undo no-show takes; once the mark is removed it no longer exists, so onno_show_undoneit isnull.routing_form—submission:uri,uuid,routingForm,submitter,submitterType,answers(question,answer),resultandcreatedAt.event_type_created,event_type_updatedandevent_type_deleted—eventType:uri,uuid,name,slug,duration,kind,activeandschedulingUrl.
id repeats, so tell them apart by occurredAt.Trying it out
The trigger's Test push shows what each event you picked will look like, without dispatching anything — the flow doesn't run:
- Meeting booked — the account's most recent real bookings, shaped exactly as a delivery and filtered by Only this event type. With none, Calendly's example.
- Meeting canceled, Invitee marked no-show and Routing form submitted — Calendly's own example payloads.
- Meeting rescheduled and Event type changed — Calendly has no example of these; they arrive live once the trigger is active.
Before the first event arrives, the node still shows the shape of each event you picked, so you can write {{payload.invitee.email}} in the nodes below it from the start. To see a real one, activate the trigger and book a time on your own booking page.
Gotchas
- Calendly allows 60 requests a minute per account. A 429 is retried once, after the wait Calendly asks for (up to 10 s).
- Available times look at 7 days at most, and the window has to start in the future. A longer window is cut to 7 days.
- The whole organization needs an admin. Otherwise Calendly answers 403 and the node — or the trigger, when you activate it — says to switch Whose to Mine.
- Routing forms are organization-wide. A trigger with Routing form submitted and Whose = Mine doesn't activate; it says to switch Whose or untick it.
- URIs belong to the account that created them. Connect another Calendly account and a saved event URI may not be readable any more — the node says so under the credential.