Kommo + Aircall: автоматическое сохранение звонков и заметок в карточку сделки
Aircall — облачная телефония, популярная в EU и US-рынках, с полноценным REST API и webhook’ами на каждое событие звонка. Из коробки Aircall интегрируется с HubSpot, Salesforce, Intercom — но не с Kommo. Кастомная интеграция строится через Aircall Public API: входящий звонок -> создание или обновление контакта и сделки в Kommo -> после звонка запись разговора и заметки агента автоматически появляются в карточке.
Что даёт интеграция Kommo + Aircall
Без интеграции:
— Агент звонит из Aircall, после звонка вручную открывает Kommo
— Вводит результат звонка как Note
— Прикрепляет ссылку на запись из Aircall — вручную
— Обновляет этап сделки — вручную
С интеграцией:
— Входящий звонок от номера в Kommo -> карточка открывается автоматически
— Звонок завершён -> Note с длительностью, результатом и ссылкой на запись создаётся автоматически
— Агент добавил заметку в Aircall -> синхронизируется в Kommo
— Пропущенный звонок -> Task для менеджера с напоминанием перезвонить
Что синхронизируется
Aircall -> Kommo:
— call.ended -> Note на сделке: дата, длительность, результат (answered/voicemail/missed)
— Ссылка на аудиозапись -> кастомное поле или Note
— call.commented -> заметка агента из Aircall -> Note в Kommo
— call.tagged -> теги звонка -> теги или кастомное поле сделки
— Пропущенный звонок -> Task «Перезвонить» с дедлайном
Kommo -> Aircall:
— Создание/обновление Contact в Aircall при изменении контакта в Kommo
— Номер телефона клиента -> Contact в Aircall для определения входящих
Архитектура
Aircall Webhook: call.created (входящий звонок)
↓ Backend
1. Искать контакт по номеру: GET /api/v4/contacts
params: filter[phone]={caller_number}
-> найден: получить связанную сделку
-> не найден: создать сделку на первом этапе
2. Сохранить aircall_call_id -> кастомное поле сделки
3. (опционально) Отправить pop-up агенту с данными клиента
Aircall Webhook: call.ended
↓ Backend
1. Получить call_id из payload
2. Aircall API: GET /v1/calls/{call_id}
-> длительность, статус, ссылка на запись, user_id агента
3. Найти deal_id по aircall_call_id в хранилище
4. Kommo: POST /leads/{deal_id}/notes
-> Note с результатом: длительность, статус, ссылка на запись
5. Если missed -> Kommo: POST /tasks
-> задача «Перезвонить» с дедлайном +2 часа
Aircall Webhook: call.commented
↓ Backend
1. Получить comment и call_id
2. Найти deal_id
3. Kommo: POST /leads/{deal_id}/notes
-> заметка агента из Aircall
Aircall REST API: ключевые запросы
Base URL: https://api.aircall.io/v1/. Аутентификация: Basic Auth (api_id:api_token) или OAuth 2.0.
Получение деталей звонка:
import requests
from requests.auth import HTTPBasicAuth
AIRCALL_ID = 'your_api_id'
AIRCALL_TOKEN = 'your_api_token'
AUTH = HTTPBasicAuth(AIRCALL_ID, AIRCALL_TOKEN)
def get_call_details(call_id: int) -> dict:
resp = requests.get(
f'https://api.aircall.io/v1/calls/{call_id}',
auth=AUTH
)
call = resp.json()['call']
return {
'duration': call.get('duration'), # секунды
'status': call.get('status'), # answered, missed, voicemail
'recording': call.get('recording'), # URL аудио
'user_id': call.get('user', {}).get('id'),
'user_name': call.get('user', {}).get('name'),
'started_at': call.get('started_at'),
'tags': [t['name'] for t in call.get('tags', [])]
}
Создание Note в Kommo с данными звонка:
import requests
from datetime import datetime
def create_call_note(deal_id: int, call: dict, kommo_token: str):
duration_min = call['duration'] // 60
duration_sec = call['duration'] % 60
status_ru = {'answered': 'Состоялся', 'missed': 'Пропущен',
'voicemail': 'Голосовая почта'}.get(call['status'], call['status'])
note_text = (
f'📞 Звонок {status_ru}\n'
f'Длительность: {duration_min}:{duration_sec:02d}\n'
f'Агент: {call["user_name"]}\n'
)
if call.get('recording'):
note_text += f'Запись: {call["recording"]}\n'
if call.get('tags'):
note_text += f'Теги: {', '.join(call['tags'])}'
requests.post(
f'https://{KOMMO_DOMAIN}.kommo.com/api/v4/leads/{deal_id}/notes',
headers={'Authorization': f'Bearer {kommo_token}'},
json=[{
'note_type': 'common',
'params': {'text': note_text}
}]
)
Обработка webhook’ов:
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks/aircall', methods=['POST'])
def aircall_webhook():
data = request.json
event = data.get('event')
call_id = data.get('data', {}).get('id')
if event == 'call.ended':
call = get_call_details(call_id)
deal_id = get_deal_by_call_id(call_id) # из вашего хранилища
if deal_id:
create_call_note(deal_id, call, KOMMO_TOKEN)
if call['status'] == 'missed':
create_kommo_task(deal_id, 'Перезвонить клиенту', KOMMO_TOKEN)
elif event == 'call.commented':
comment = data.get('data', {}).get('comment', '')
deal_id = get_deal_by_call_id(call_id)
if deal_id and comment:
create_simple_note(deal_id, f'Заметка по звонку: {comment}', KOMMO_TOKEN)
return '', 200
Определение звонящего по номеру телефона
При входящем звонке (call.created) нужно быстро найти контакт в Kommo:
def find_kommo_contact_by_phone(phone: str) -> dict | None:
# Нормализовать номер (убрать +, пробелы)
clean_phone = ''.join(filter(str.isdigit, phone))
resp = requests.get(
f'https://{KOMMO_DOMAIN}.kommo.com/api/v4/contacts',
headers={'Authorization': f'Bearer {KOMMO_TOKEN}'},
params={
'query': clean_phone,
'with': 'leads'
}
)
contacts = resp.json().get('_embedded', {}).get('contacts', [])
return contacts[0] if contacts else None
Если контакт найден — берём его активную сделку. Если нет — создаём новую сделку на первом этапе воронки.
Синхронизация контактов Kommo -> Aircall
Для корректного определения входящих Aircall должен знать телефоны клиентов из Kommo:
def upsert_aircall_contact(name: str, phone: str, email: str,
kommo_contact_id: int):
# Поиск существующего контакта
resp = requests.get(
'https://api.aircall.io/v1/contacts',
auth=AUTH,
params={'phone_number': phone}
)
contacts = resp.json().get('contacts', [])
payload = {
'first_name': name.split()[0] if name else '',
'last_name': ' '.join(name.split()[1:]) if len(name.split()) > 1 else '',
'phone_numbers': [{'label': 'Work', 'value': phone}],
'emails': [{'label': 'Work', 'value': email}] if email else []
}
if contacts:
requests.put(f'https://api.aircall.io/v1/contacts/{contacts[0]['id']}',
auth=AUTH, json=payload)
else:
requests.post('https://api.aircall.io/v1/contacts',
auth=AUTH, json=payload)
Реальный кейс
SaaS-компания (EU-рынок, команда 8 агентов, 150–200 звонков в день):
- До: агент после каждого звонка вручную открывал Kommo, писал Note, копировал ссылку на запись. 3–5 минут на каждый звонок — из 200 звонков это до 15 часов команды в неделю только на ведение CRM.
- После: все данные звонка появляются в Kommo автоматически в течение 30 секунд после окончания разговора. Агент добавляет только заметку о результате — она тоже синхронизируется из Aircall.
- Дополнительный эффект: руководитель видит сводку звонков прямо в Kommo — без переключения в Aircall. Пропущенные звонки превращаются в задачи автоматически, ни один не теряется.
Аналогичная интеграция реализована для Twilio и Kommo — там программная телефония через API, Aircall — готовое SaaS-решение для команд продаж.
Для кого актуально
- Команда использует Aircall как основную телефонию
- 50+ звонков в день — ручное ведение CRM нерентабельно
- Нужна история звонков прямо в карточке клиента в Kommo
- Важен контроль: руководитель должен видеть кто звонил, сколько, с каким результатом
- Пропущенные звонки должны превращаться в задачи автоматически
Часто задаваемые вопросы
Есть ли нативная интеграция Aircall и Kommo?
Нативной интеграции нет — Aircall поддерживает нативные коннекторы для HubSpot, Salesforce, Pipedrive, Intercom. Для Kommo интеграция строится через Aircall Public API и Kommo Webhooks. Это 2–3 недели разработки, но результат полностью кастомный под логику вашей воронки.
Aircall API — Basic Auth или OAuth?
Оба варианта. Basic Auth с api_id:api_token — проще для серверных интеграций, подходит для большинства кейсов. OAuth 2.0 — если нужно чтобы каждый менеджер авторизовался индивидуально (действия от имени конкретного пользователя). Для интеграции с CRM — Basic Auth достаточен.
Как получить ссылку на запись звонка?
Через GET /v1/calls/{id} — поле recording содержит прямую ссылку на аудиофайл. Записи доступны только если запись включена в настройках номера Aircall. Ссылки временные (истекают через N дней) — лучше скачивать и хранить в собственном S3/R2.
Какие тарифы Aircall включают API?
API доступен на тарифе Professional ($50/пользователь/мес) и выше. Essential ($40/польз./мес) API не включает. Webhook’и доступны с Professional.
Итого
- Aircall Webhooks:
call.created,call.ended,call.commented,call.tagged— основа интеграции - Aircall API:
GET /v1/calls/{id}для деталей звонка,POST /v1/contactsдля синхронизации контактов - Kommo: Note с результатом звонка, Task при пропущенном, кастомные поля с метаданными
- Типовой срок — 2 недели разработки + 1 неделя тестирования на реальных звонках
Если вы используете Aircall и Kommo — опишите вашу схему работы со звонками: что агенты сейчас делают вручную. Exceltic.dev спроектирует автоматический workflow и покроет все сценарии (входящий, исходящий, пропущенный, голосовая почта).