RingCentral has a native integration with Kommo: click-to-call, automatic lead creation on an incoming call from an unknown number, and a basic call log in the deal timeline. However, the native integration only records the call itself — duration and number. There is no call recording, call outcome, or transcript in the card. This is addressed through the RingCentral REST API.
What the Native Kommo + RingCentral Integration Misses
The standard RingCentral integration via the Kommo Marketplace provides: — Click-to-call from the contact card — Incoming call -> Kommo notification, lead creation if the contact is new — Recording the call fact (who called, duration) in the deal timeline
What is missing: — Call recording is not attached to the deal — it remains only in RingCentral — Call outcome (status, manager comment) does not go into custom fields — Transcript is not available in the CRM even if RingCentral AI created it — Routing logic — who to assign the deal to after a call — cannot be configured
For teams with 20+ calls per day, this means the Sales Director cannot see call context in Kommo without switching to RingCentral. Customer Success does not know what was discussed with the client before handoff. When a manager changes, the history is lost.
Extended Integration Architecture
RingCentral Webhook: telephony/sessions -> session ended (Disconnected)
↓ Backend
1. Get session_id, extension_id, from/to numbers
2. Wait 60 sec (recording is processed asynchronously)
3. GET /account/~/call-log?sessionId={session_id}&view=Detailed
-> duration, result, recording.id
4. GET /account/~/recording/{recording_id}/content
-> download MP3 audio
5. Upload MP3 to storage (S3/R2)
-> get public URL
6. Kommo: find deal by phone number (contact -> deals)
7. Kommo: POST /leads/{deal_id}/notes
-> Note with "call" type: duration, link to recording
8. Kommo: PATCH /leads/{deal_id}
-> custom field last_call_result = 'Completed' / 'No Answer' / 'Busy'
-> last_call_date = timestamp
RingCentral REST API: Key Requests
Base URL: https://platform.ringcentral.com/restapi/v1.0/. Authentication: JWT flow for server-to-server (create JWT credential in Developer Console -> exchange for access_token).
Get access token via JWT:
import requests
RC_CLIENT_ID = 'your_client_id'
RC_CLIENT_SECRET = 'your_client_secret'
RC_JWT = 'your_jwt_credential'
def get_access_token() -> str:
resp = requests.post(
'https://platform.ringcentral.com/restapi/oauth/token',
auth=(RC_CLIENT_ID, RC_CLIENT_SECRET),
data={
'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': RC_JWT
}
)
resp.raise_for_status()
return resp.json()['access_token']
Get call details:
def get_call_details(session_id: str, token: str) -> dict:
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get(
'https://platform.ringcentral.com/restapi/v1.0/account/~/call-log',
headers=headers,
params={
'sessionId': session_id,
'view': 'Detailed',
'dateFrom': '2024-01-01T00:00:00Z' # or minus 1 hour
}
)
resp.raise_for_status()
records = resp.json().get('records', [])
if not records:
return {}
record = records[0]
return {
'duration': record.get('duration'),
'result': record.get('result'), # 'Accepted', 'No Answer', 'Busy', etc.
'from': record.get('from', {}).get('phoneNumber'),
'to': record.get('to', {}).get('phoneNumber'),
'recording_id': record.get('recording', {}).get('id')
}
Download call recording:
def download_recording(recording_id: str, token: str) -> bytes:
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get(
f'https://platform.ringcentral.com/restapi/v1.0'
f'/account/~/recording/{recording_id}/content',
headers=headers
)
resp.raise_for_status()
return resp.content # MP3 bytes
Handling telephony/sessions webhook:
from flask import Flask, request
import time
app = Flask(__name__)
@app.route('/webhooks/ringcentral', methods=['POST'])
def ringcentral_webhook():
# RingCentral requires validation on webhook registration
validation_token = request.headers.get('Validation-Token')
if validation_token:
return validation_token, 200, {'Validation-Token': validation_token}
payload = request.json
event = payload.get('event', '')
# Only process completed sessions
if 'telephony/sessions' not in event:
return '', 200
body = payload.get('body', {})
session_id = body.get('sessionId')
parties = body.get('parties', [])
# Check that at least one party is in Disconnected status
has_disconnected = any(
p.get('status', {}).get('code') == 'Disconnected'
for p in parties
)
if not has_disconnected:
return '', 200
# Queue for async processing (recording appears with a delay)
enqueue_call_processing(session_id, delay_seconds=60)
return '', 200
def process_completed_call(session_id: str):
token = get_access_token()
details = get_call_details(session_id, token)
if not details:
return
from_number = details['from']
result = details['result']
duration = details['duration']
recording_id = details.get('recording_id')
# Find deal in Kommo by phone number
deal_id = find_kommo_deal_by_phone(from_number)
if not deal_id:
return
# Download and save recording
recording_url = None
if recording_id:
audio = download_recording(recording_id, token)
recording_url = upload_to_storage(audio, f'{session_id}.mp3')
# Note in Kommo
note_text = f'RingCentral call: {duration} sec, result: {result}'
if recording_url:
note_text += f'\nRecording: {recording_url}'
create_kommo_note(deal_id, note_text)
# Update custom fields
update_kommo_deal(deal_id, {
'last_call_result': result,
'last_call_duration': duration
})
Registering a webhook in RingCentral:
def register_webhook(webhook_url: str, token: str):
resp = requests.post(
'https://platform.ringcentral.com/restapi/v1.0/subscription',
headers={'Authorization': f'Bearer {token}'},
json={
'eventFilters': [
'/restapi/v1.0/account/~/telephony/sessions'
],
'deliveryMode': {
'transportType': 'WebHook',
'address': webhook_url
},
'expiresIn': 604800 # 7 days, needs renewal
}
)
return resp.json()
Important: RingCentral webhook subscriptions expire (default 7 days). They must be renewed on a schedule via PUT /subscription/{subscriptionId} or by subscribing to the event /restapi/v1.0/subscription/~?threshold=60&interval=30 for automatic renewal.
RingCentral AI Integration — Transcripts
RingCentral RingSense AI creates call transcripts and summaries on plans with AI features. They are available via GET /account/~/call-log/{callId}?view=Detailed — the aiTranscriptUrl field contains a link to the transcript.
def get_call_transcript(call_id: str, token: str) -> str:
headers = {'Authorization': f'Bearer {token}'}
resp = requests.get(
f'https://platform.ringcentral.com/restapi/v1.0'
f'/account/~/call-log/{call_id}',
headers=headers,
params={'view': 'Detailed'}
)
data = resp.json()
transcript_url = data.get('aiTranscriptUrl')
if not transcript_url:
return ''
tr = requests.get(transcript_url, headers=headers)
return tr.text
The transcript is saved as a separate Note in Kommo with a “RingCentral Transcript” tag — separate from the Note with the recording link. A similar approach is used in the Kommo + Fireflies.ai integration.
Deal Routing After a Call
An additional capability: automatically reassign the deal or change the pipeline stage based on the call outcome.
CALL_RESULT_ACTIONS = {
'Accepted': None, # call accepted - no changes
'No Answer': 'schedule_followup', # call back in one hour
'Busy': 'schedule_followup',
'Voicemail': 'send_followup_email'
}
def handle_call_outcome(deal_id: int, result: str):
action = CALL_RESULT_ACTIONS.get(result)
if action == 'schedule_followup':
create_kommo_task(
deal_id,
f'Call back - client did not answer ({result})',
due_in_minutes=60
)
Real-World Case
B2B company (EU, SaaS, 8 salespeople, 80–100 outbound calls per day via RingCentral + Kommo):
- Before: call recordings existed only in RingCentral. After a call, the manager manually entered the outcome in Kommo. 30–40% of calls were not logged — managers “forgot.” The Sales Director listened to recordings in RingCentral without CRM context alongside.
- After: every completed call -> Note in Kommo with recording and result within 90 seconds. “No Answer” outcome -> automatic follow-up task in one hour. Sales Director reviews calls directly from the deal card.
- Additionally: when a deal is transferred to a new manager, they immediately see the last 5 call recordings in the timeline — context is not lost.
Who This Is Relevant For
- Teams using RingCentral as their corporate telephony and Kommo as their CRM
- 20+ calls per day — manual logging becomes impractical
- Call history is required in the deal card: for client handoffs, onboarding, and Customer Success
- Native integration is installed but recordings are not appearing in the CRM
Frequently Asked Questions
How does RingCentral JWT auth differ from OAuth?
JWT (RFC 7523) is a server-to-server flow without user involvement. A JWT credential is created in the Developer Console and allows obtaining an access_token to access account data. OAuth Authorization Code is used when a user must authorise access themselves (multi-tenant SaaS). For server-side Kommo integration — use JWT.
What permissions are required to access recordings?
Two API permissions are mandatory: ReadCallLog for access to the call log and ReadCallRecording for downloading audio. These are set in the application settings in the RingCentral Developer Console. Without them, /recording/{id}/content will return 403.
Does the recording appear immediately after the call ends?
No. RingCentral processes the recording asynchronously — typically 30–90 seconds. If you request call-log immediately after the Disconnected event, the recording.id field will be empty. A 60-second delay or polling every 30 seconds is recommended.
Is a Premium RingCentral plan required for API access?
REST API access is available on Premium and Ultimate plans. The Standard plan has limited API access. Call recording also requires Premium+. Before implementation, check the current plan: Settings -> Billing in the RingCentral Admin Portal.
How do I match a call to the correct deal when a contact has multiple open deals?
Logic: search for an active deal in statuses other than Won/Lost. If multiple are found — choose the most recently updated one. Or add a custom field “primary responsible number” to the deal and match by that.
Summary
- Native Kommo + RingCentral integration: click-to-call and basic log. No recordings or transcripts in the CRM
- RingCentral REST API: JWT auth, event filter
/account/~/telephony/sessions - After
Disconnected: call-log -> recording -> upload -> Note in Kommo + custom fields - Webhook subscription expires after 7 days — auto-renewal is required
- 60-second delay before requesting recording (asynchronous processing)
- Typical development time: 1–2 weeks
If you have RingCentral and Kommo and call recordings are not appearing in deal cards — describe your current configuration. Exceltic.dev will configure a custom IP telephony integration with full call logging.