Kommo + Whereby: Video Calls from the Pipeline Without Switching Apps
Whereby Embedded lets you create video call rooms via API with a single HTTP request. For Kommo, this solves a specific problem: when a sales rep moves a deal to the “Demo” or “Onboarding” stage, a room is created automatically, the link is added as a note on the deal - and you can send it to the client right away. No switching to Whereby, no manual link copying.
The Whereby Embedded API uses a Bearer token (an API Key from your Whereby Embedded account). There is one endpoint for creating a room: POST /v1/meetings. The response includes roomUrl for guests and hostRoomUrl with host privileges. The minimum request body requires just 3 fields.
Whereby Embedded is the developer-facing version of Whereby with an API for programmatically creating rooms and embedding video into your own interface. It differs from standard Whereby: Embedded requires a paid plan and an API Key.
Why the Standard Approach Falls Short
The standard Zapier connector for Whereby creates “permanent” rooms with no tie to a specific time slot and without a hostRoomUrl. As a result, the sales rep gets a room link that is either already occupied by another call or accessible to others without their knowledge.
The deeper problem: Zapier-created rooms are not deleted automatically. If a deal is cancelled, the room stays open. Over a month, 20-30 abandoned rooms accumulate.
Architecture
Kommo: deal -> "Demo" or "Onboarding" stage
-> Kommo webhook leads.status.changed
-> Your server
Your server:
-> POST /v1/meetings (endDate, roomNamePrefix)
-> Response: {roomUrl, meetingId, hostRoomUrl}
-> Kommo: note with roomUrl (for the client) and hostRoomUrl (for the manager)
Implementation
import requests, os
from datetime import datetime, timedelta, timezone
from flask import Flask, request, jsonify
app = Flask(__name__)
WHEREBY_API_KEY = os.environ["WHEREBY_API_KEY"]
WHEREBY_BASE = "https://api.whereby.dev/v1"
WHEREBY_HDR = {"Authorization": f"Bearer {WHEREBY_API_KEY}",
"Content-Type": "application/json"}
KOMMO_SUBDOMAIN = os.environ["KOMMO_SUBDOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_ACCESS_TOKEN"]
DEMO_STAGE_ID = int(os.environ["KOMMO_DEMO_STAGE_ID"])
KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR = {"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json"}
MEETING_DURATION_HOURS = 2 # room lives for 2 hours after creation
def create_whereby_room(lead_id: int) -> dict:
end_date = (
datetime.now(timezone.utc) + timedelta(hours=MEETING_DURATION_HOURS)
).strftime("%Y-%m-%dT%H:%M:%S.000Z")
r = requests.post(
f"{WHEREBY_BASE}/meetings",
headers=WHEREBY_HDR,
json={
"endDate": end_date,
"fields": ["hostRoomUrl"],
"roomNamePrefix": f"kommo-{lead_id}-",
"roomMode": "normal",
},
)
r.raise_for_status()
return r.json()
def delete_whereby_room(meeting_id: str):
requests.delete(
f"{WHEREBY_BASE}/meetings/{meeting_id}",
headers=WHEREBY_HDR,
)
def add_note(lead_id: int, text: str):
requests.post(
f"{KOMMO_BASE}/notes",
headers=KOMMO_HDR,
json=[{"entity_id": lead_id, "entity_type": "leads",
"note_type": "common", "params": {"text": text}}],
)
def save_meeting_id(lead_id: int, meeting_id: str):
# Save meetingId to a custom Kommo field for later deletion
cf_meeting_id = int(os.environ.get("CF_WHEREBY_MEETING_ID", "0"))
if cf_meeting_id:
requests.patch(
f"{KOMMO_BASE}/leads/{lead_id}",
headers=KOMMO_HDR,
json={"custom_fields_values": [
{"field_id": cf_meeting_id,
"values": [{"value": meeting_id}]}
]},
)
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
data = request.json or {}
# Create a room when a deal moves to the Demo stage
for lead_data in data.get("leads", {}).get("status", []):
lead_id = lead_data.get("id")
new_status = lead_data.get("status_id")
if new_status != DEMO_STAGE_ID:
continue
meeting = create_whereby_room(lead_id)
room_url = meeting.get("roomUrl", "")
host_url = meeting.get("hostRoomUrl", "")
meeting_id = meeting.get("meetingId", "")
save_meeting_id(lead_id, meeting_id)
add_note(
lead_id,
f"Whereby room created:\n"
f"Client link: {room_url}\n"
f"Manager link (host): {host_url}\n"
f"Meeting ID: {meeting_id}"
)
return jsonify({"status": "ok"}), 200
Deleting Rooms When a Deal Is Closed
Whereby does not delete rooms automatically after endDate - they move to an inactive state but still count against your limit. The right approach is to delete them when a deal is closed or lost.
def get_cf_value(lead: dict, field_id: int) -> str:
for cf in lead.get("custom_fields_values", []) or []:
if cf.get("field_id") == field_id:
vals = cf.get("values", [])
return vals[0].get("value", "") if vals else ""
return ""
@app.route("/webhooks/kommo/closed", methods=["POST"])
def kommo_closed():
data = request.json or {}
cf_meeting_id = int(os.environ.get("CF_WHEREBY_MEETING_ID", "0"))
if not cf_meeting_id:
return jsonify({"status": "no_cf_configured"}), 200
for lead_data in data.get("leads", {}).get("delete", []):
lead_id = lead_data.get("id")
# Fetch the full deal data to retrieve the custom field
r = requests.get(
f"{KOMMO_BASE}/leads/{lead_id}",
headers=KOMMO_HDR,
params={"with": "custom_fields_values"},
)
lead = r.json()
meeting_id = get_cf_value(lead, cf_meeting_id)
if meeting_id:
delete_whereby_room(meeting_id)
return jsonify({"status": "ok"}), 200
Setting Up Whereby Embedded
- Register at whereby.com/embedded (a paid plan is required)
- Create an organization, then go to Configure -> API Keys
- Generate an API Key - this is the Bearer token used for all requests
- Configure
roomNamePrefixandroomModeto fit your needs
Room modes: normal (standard) and group (up to 100 participants, requires an Enterprise plan).
Room Parameters
# Extended request with additional parameters
meeting = requests.post(
f"{WHEREBY_BASE}/meetings",
headers=WHEREBY_HDR,
json={
"endDate": "2026-07-01T12:00:00.000Z",
"fields": ["hostRoomUrl", "viewerRoomUrl"],
"roomNamePrefix": "acme-demo-",
"roomMode": "normal",
"recording": {"type": "none"}, # or "cloud"
"chat": {"enabled": True},
"screenshare": {"enabled": True},
},
)
The viewerRoomUrl field provides a link for a viewer with no speaking rights - useful for recording presentations.
Who This Is For
B2B companies with a sales process that includes demo calls or onboarding sessions. Especially relevant for SaaS and professional services where demos are a required pipeline stage. Whereby Embedded is popular in the EU specifically because data does not leave EU servers - important for GDPR-compliant companies.
Other communication integrations: Kommo + Telnyx (SMS/calls via CPaaS), Kommo + Sinch (SMS in the EU).
Frequently Asked Questions
Can I retrieve a call recording via the Whereby API?
Yes, if recording is enabled in the room settings ("recording": {"type": "cloud"}). After the meeting ends, recordings are available via GET /v1/recordings - a list of recordings with a downloadUrl. Recordings are stored on Whereby servers (the EU region is available on the Enterprise plan).
How do I restrict room access to invited participants only?
Whereby Embedded supports roomLock: true when creating a room - participants must wait for the host to let them in. The host manages access via hostRoomUrl. You can also add knock: {"enabled": true} to require a knock before entry.
Does Whereby support GDPR and EU data storage?
Yes. Whereby is a Norwegian company with servers in the EU. The Enterprise plan provides a Data Processing Agreement (DPA) under GDPR. Recordings are stored in the EU region. This is one of the key advantages over Zoom for European B2B companies.
Does Whereby work in the browser without installing an app?
Yes - this is a key differentiator from Zoom. Meetings open directly in the browser with no plugins or apps required. The client simply follows the link. Supported browsers include Chrome, Firefox, Edge, and Safari.
Summary
Kommo + Whereby Embedded - video calls built into your pipeline:
- Bearer token,
POST /v1/meetingswith endDate and roomNamePrefix - Response:
roomUrl(client) +hostRoomUrl(manager as host) - Store
meetingIdin Kommo for deletion when the deal is closed - Rooms are not deleted automatically - explicitly delete via
DELETE /v1/meetings/{id} - EU servers, GDPR compliant, no app required for the client
If your team runs demo calls through Kommo and you need to automate Whereby room creation - describe the task to the Exceltic.dev team.