To have a Calendly meeting appear inside a Kommo deal card, you need to configure a webhook on the Calendly side and a small handler service. When a booking is made, Calendly sends an invitee.created event containing the invitee’s email, name, date, time, and meeting link. The service looks up the contact in Kommo by email, finds the associated deal, and creates a task or note with the full details. When a meeting is cancelled, an invitee.canceled event arrives and the service marks or closes the task.
The native Calendly widget in Kommo does one thing: create a new inbound lead when a booking is made for the first time. This works for inbound traffic. But when a manager sends a Calendly link to an existing client, the widget has no awareness of that. The meeting happened, the contact exists, the deal is moving through the pipeline - and there is no trace of it in the CRM. A colleague looks at the card and has no idea whether a conversation took place.
This article explains exactly how a custom integration through the Calendly Webhook API and Kommo REST API works: which fields are delivered, how to find the right deal, and what to write into the card.
Where the native widget ends
The native Calendly integration in Kommo works through the Digital Pipeline: when a new booking is made, an inbound lead is created with a meeting task. As of Q2 2026, this is the only scenario the widget covers.
Three situations the widget does not handle:
- A manager takes a Calendly link from their own profile and sends it to a contact that already exists in the CRM. The booking happens, but there is no link to the existing deal.
- A client cancels a meeting. Nothing in the deal card reflects this - the manager only finds out by checking email.
- A meeting is rescheduled. Calendly first sends
invitee.canceledwith the flagrescheduled: true, theninvitee.createdwith the new time. The widget creates a duplicate lead instead of updating the existing task.
Additionally, the widget requires a paid Kommo plan and a paid Calendly plan - free accounts are not supported. This is an extra constraint for smaller teams.
Webhook - an HTTP request that Calendly sends to your server at the moment of an event: a booking, cancellation, or reschedule.
What the custom integration handles
The custom integration covers all scenarios the native widget misses. The logic is built on two Calendly events and two Kommo API operations.
Webhook invitee.created -> contact lookup -> task in deal
When someone books a meeting through Calendly, the platform sends a POST request to your server. The request body contains:
{
"event": "invitee.created",
"payload": {
"email": "[email protected]",
"name": "Ivan Petrov",
"event_type": {
"name": "30 Minute Meeting"
},
"calendar_event": {
"start_time": "2026-07-10T14:00:00Z",
"end_time": "2026-07-10T14:30:00Z"
},
"event": {
"uri": "https://api.calendly.com/scheduled_events/ABCDEF123456",
"location": {
"type": "zoom",
"join_url": "https://zoom.us/j/123456789"
}
},
"questions_and_answers": []
}
}
The full field specification is available in the official Calendly documentation.
The handler service does the following:
- Extracts
payload.emailfrom the request body. - Searches for the contact in Kommo via
GET /api/v4/contacts?query={email}. - If the contact is found - retrieves their open deals via
GET /api/v4/leads?contact_id={id}. - Creates a note in the deal via
POST /api/v4/leads/{id}/noteswith typecommonand text containing: date, time, meeting link, and attendee name. - Optionally creates a task via
POST /api/v4/taskswith fieldsentity_id,entity_type: leads,task_type_id: 2(meeting), andcomplete_tillset to the meeting start time. - If the contact is not found - creates an inbound lead, just as the native widget does.
Full Kommo API documentation for tasks and notes is at developers.kommo.com.
Meeting cancellation - webhook invitee.canceled
On cancellation, Calendly sends invitee.canceled. The field payload.canceled contains the cancellation reason; payload.rescheduled indicates whether this is a reschedule (true) or a real cancellation (false).
The handler service:
- With
rescheduled: false- adds a note to the deal: “Meeting cancelled. Reason: {payload.canceled.reason}”. Marks the task as completed or deletes it. - With
rescheduled: true- waits for the nextinvitee.createdwith the updated details and updates the task.
This approach preserves the full interaction history in the deal card, even if the client rescheduled multiple times.
Step-by-step integration flow
Here is how the process looks from booking to record in Kommo.
Step 1 - Register the webhook in Calendly
Through the Calendly API (or in account settings) a webhook subscription is registered for two events: invitee.created and invitee.canceled. The URL of your handler service is provided. Calendly supports request signature verification - connect this from the start to block forged requests.
Step 2 - Service receives the event and parses the payload
The server accepts the POST, verifies the signature, extracts event, payload.email, payload.name, payload.calendar_event.start_time, and payload.event.location.join_url.
Step 3 - Contact lookup in Kommo
Request to Kommo API: GET /api/v4/contacts?query={email}. If one or more contacts are returned - take the first one matching by email.
Step 4 - Active deal lookup
Using contact_id, retrieve the list of deals: GET /api/v4/leads?contact_id={id}&filter[statuses][]=0 (status 0 = active). If there are multiple - take the most recently modified.
Step 5 - Create the record in the deal
A note is written to the deal with the date, time, and meeting link (Zoom, Google Meet, or phone - depending on location.type). In parallel, a task is created with type “Meeting” and a deadline equal to start_time.
Step 6 - Handle cancellation
On invitee.canceled, the service finds the task by matching complete_till and entity_id, then closes it or adds a cancellation note.
Step 7 - Idempotency
To prevent duplicate tasks when a webhook is redelivered, the service stores event.uri from the payload as a unique identifier and checks it before creating anything.
Real-world case
One Exceltic.dev project involved a B2B sales team of 8 managers who used Kommo and actively used Calendly to schedule demos. The problem looked like this: a manager sent a link via LinkedIn, the client booked a slot - and the meeting disappeared from the CRM. The head of sales could not tell from the pipeline whether demos had been scheduled for specific deals or not.
During a pipeline review it turned out that around 30% of scheduled demos were not reflected in Kommo. Managers kept notes in their heads or in personal calendars.
After integrating via Calendly webhook + Kommo API:
- Every meeting automatically appears as a task in the corresponding deal within seconds of booking.
- Cancellations are recorded as notes - the manager can see when and why a meeting did not happen.
- Time spent manually entering meetings into the CRM dropped to zero.
- Pipeline visibility for the head of sales improved: it is now clear which deals have a scheduled touchpoint and which do not.
The rollout took about two weeks: one week for building the handler service and testing, one week for stabilization and edge cases (reschedules, multiple active deals for one contact).
Who this solution is for
The webhook integration makes sense for teams that simultaneously meet three conditions. First, managers actively use Calendly and send links to existing CRM contacts - not just embed a widget on the site for inbound traffic. Second, pipeline transparency matters: the manager or team lead needs to see which deal has a scheduled next touchpoint. Third, the team has already run into meetings being lost or cancellations going unrecorded.
If you are building custom integrations for Kommo or want to understand what the platform can do at the API level, see the Kommo CRM overview - it covers the data model and the limitations of native tools.
Typical profile: B2B team of 5+ managers, deal cycle of 2+ weeks, Calendly used for demos and onboarding. Zapier or Make are not suitable due to latency (delay of up to several minutes) and limitations around custom contact-lookup logic.
Term: Idempotency key - a unique identifier for an operation that allows a webhook to be reprocessed without creating duplicates. In this integration, event.uri from the Calendly payload serves as the idempotency key.
Frequently asked questions
What if one contact in Kommo has multiple open deals?
This is one of the edge cases that must be handled explicitly in the service logic. A simple option: create the task in the most recently modified deal and simultaneously write a note to all active deals for that contact. A more advanced option: Calendly allows custom questions when registering for a meeting (the questions_and_answers field in the payload). You can add a “Deal ID” field and use it for a direct link. This requires an agreement with managers but eliminates ambiguity entirely.
Does Calendly require a paid plan for webhooks?
Yes. Webhook subscriptions in Calendly are only available on paid plans - Standard and above. On the free Calendly plan, webhooks are not available. This needs to be factored in when planning the integration: if the team is on free Calendly, an upgrade is needed first.
How do you handle rescheduled meetings without creating duplicates?
When a meeting is rescheduled, Calendly sends two consecutive events: invitee.canceled with payload.rescheduled: true and then invitee.created with the new data. When the service receives invitee.canceled with the rescheduled: true flag, it should not close the task but mark it as “pending update”. On the next invitee.created, update complete_till and the task text. The unique meeting identifier (event.uri) changes on reschedule, so the binding must be stored by the pair contact_id + old event.uri.
Can Zapier be used instead of a custom service?
Technically, Zapier can listen to a Calendly webhook and make requests to Kommo. In practice, two limitations arise. First - latency: Zapier processes events not in real time but with a delay of up to several minutes on higher plans and longer on basic ones. Second - logic: looking up a contact by email, retrieving their deals, selecting the right one by criteria, and creating a task with idempotency is multi-step logic that is complex and expensive to implement in Zapier without custom code. For simple scenarios (inbound only, one contact - one deal) Zapier may be sufficient. For a production B2B team with historical contacts - it is not.
How do you verify the integration is working correctly?
A minimum set of checks after launch: book a test meeting through Calendly and confirm that a task with the correct time and link appeared in the deal. Cancel the meeting - check that a cancellation note appeared in the card. Reschedule the meeting - confirm the task was updated rather than a new one created. Set up alerting for cases where the service received a webhook but could not find a contact - this is a useful metric for identifying gaps in the CRM database.
If your managers use Calendly with existing clients and meetings are not appearing in Kommo - this is a standard problem. Describe your stack (how the pipeline is configured, how many managers, what meeting types) to the Exceltic.dev team. We will review the architecture and estimate the scope of work.
See also how we configured the Kommo pipeline - understanding the pipeline structure helps you decide which deal and at which stage a meeting should land. And if you are interested in syncing Kommo data with external spreadsheets, see the Kommo and Google Sheets integration - similar logic for contact lookup and record updates.