Salesmsg - платформа бизнес-SMS и звонков для команд продаж, популярная в США и Канаде: локальные номера, двустороннее SMS, интеграция с CRM. Kommo - CRM с воронкой продаж. Без интеграции SMS-переписка с клиентом существует в Salesmsg, а менеджер переключается между двумя интерфейсами. С интеграцией каждое SMS и звонок из Salesmsg автоматически попадают в заметки карточки сделки в Kommo.
SMS остаётся недооцененным каналом в B2B: open rate около 98% против 20-30% у email. Для north american рынка SMS от локального номера - стандартный способ напомнить о встрече, подтвердить решение, отправить ссылку на документ. Salesmsg предоставляет именно такую инфраструктуру: локальный номер, business messaging compliant, A2P 10DLC регистрация.
Salesmsg - платформа двустороннего бизнес-SMS и звонков с REST API, webhook-уведомлениями о входящих сообщениях и звонках, а также возможностью отправлять SMS программно из любой системы.
Почему это важно для воронки в Kommo
Kommo поддерживает мессенджеры (WhatsApp, Telegram, Instagram), но не SMS на US/CA номера напрямую. Salesmsg закрывает этот пробел для компаний, работающих с north american рынком.
Два направления интеграции:
- Kommo -> Salesmsg: при смене статуса сделки автоматически отправить SMS-напоминание клиенту
- Salesmsg -> Kommo: входящие SMS и звонки логировать как заметки в карточке сделки
Техническая архитектура
Kommo CRM
-> deal.status_changed (стадия "Встреча назначена")
-> POST https://app.salesmsg.com/api/v2/messages/send
{to: client_phone, body: "Напоминание о встрече..."}
Клиент
-> Ответить на SMS / позвонить
Salesmsg
-> POST /your-server/webhooks/salesmsg
{type: "message.received", contact_phone, body, lead_number}
Ваш сервер
-> Найти сделку в Kommo по номеру телефона
-> POST /api/v4/leads/{id}/notes {text: "SMS от клиента: ..."}
Реализация: отправка SMS из Kommo
import requests, os
from flask import Flask, request, jsonify
app = Flask(__name__)
KOMMO_DOMAIN = os.environ["KOMMO_DOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_TOKEN"]
SALESMSG_KEY = os.environ["SALESMSG_API_KEY"]
SALESMSG_SECRET = os.environ["SALESMSG_WEBHOOK_SECRET"]
SMS_FROM_NUMBER = os.environ["SMS_FROM_NUMBER"] # ваш Salesmsg номер
KOMMO_BASE = f"https://{KOMMO_DOMAIN}/api/v4"
KOMMO_HDR = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
SM_BASE = "https://app.salesmsg.com/api/v2"
SM_HDR = {"Authorization": f"Bearer {SALESMSG_KEY}"}
MEETING_STATUS_ID = 12345 # ID стадии "Встреча назначена"
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_event():
data = request.json or {}
for lead in data.get("leads", {}).get("status", []):
if lead.get("status_id") == MEETING_STATUS_ID:
send_meeting_reminder(lead["id"])
return jsonify({"ok": True}), 200
def get_client_phone(lead_id: int) -> str | None:
r = requests.get(
f"{KOMMO_BASE}/leads/{lead_id}",
headers=KOMMO_HDR,
params={"with": "contacts"},
)
if not r.ok:
return None
contacts = r.json().get("_embedded", {}).get("contacts", [])
if not contacts:
return None
contact_id = contacts[0]["id"]
cr = requests.get(f"{KOMMO_BASE}/contacts/{contact_id}", headers=KOMMO_HDR)
if not cr.ok:
return None
for f in cr.json().get("custom_fields_values") or []:
if f.get("field_code") == "PHONE":
vals = f.get("values", [])
if vals:
return str(vals[0]["value"])
return None
def send_meeting_reminder(lead_id: int):
phone = get_client_phone(lead_id)
if not phone:
return
body = (
"Добрый день! Напоминаем о нашей встрече. "
"Если возникли вопросы - ответьте на это сообщение."
)
r = requests.post(
f"{SM_BASE}/messages/send",
headers=SM_HDR,
json={
"to": phone,
"from": SMS_FROM_NUMBER,
"body": body,
},
timeout=10,
)
if r.ok:
requests.post(
f"{KOMMO_BASE}/leads/{lead_id}/notes",
headers=KOMMO_HDR,
json=[{"note_type": "common", "params": {"text": f"SMS отправлено: {body}"}}],
)
Реализация: логирование входящих сообщений в Kommo
import hmac, hashlib
def verify_salesmsg_webhook(raw_body: bytes, sig_header: str) -> bool:
expected = hmac.new(
SALESMSG_SECRET.encode(), raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, sig_header)
@app.route("/webhooks/salesmsg", methods=["POST"])
def salesmsg_event():
sig = request.headers.get("X-Salesmsg-Signature", "")
if not verify_salesmsg_webhook(request.data, sig):
return jsonify({"error": "unauthorized"}), 401
data = request.json or {}
event_type = data.get("type", "")
from_phone = data.get("contact_phone", "")
body_text = data.get("body", "")
if event_type == "message.received" and from_phone:
log_sms_to_kommo(from_phone, body_text, direction="in")
elif event_type == "call.completed":
duration = data.get("duration", 0)
recording = data.get("recording_url", "")
log_call_to_kommo(from_phone, duration, recording)
return jsonify({"ok": True}), 200
def find_lead_by_phone(phone: str) -> int | None:
# Search Kommo contacts by phone number.
r = requests.get(
f"{KOMMO_BASE}/contacts",
headers=KOMMO_HDR,
params={"query": phone, "limit": 1},
)
if not r.ok:
return None
contacts = r.json().get("_embedded", {}).get("contacts", [])
if not contacts:
return None
# Найти связанные сделки
contact_id = contacts[0]["id"]
lr = requests.get(
f"{KOMMO_BASE}/contacts/{contact_id}/links",
headers=KOMMO_HDR,
)
if not lr.ok:
return None
leads = [l for l in lr.json().get("_embedded", {}).get("links", []) if l.get("to_entity_type") == "leads"]
return leads[0]["to_entity_id"] if leads else None
def log_sms_to_kommo(phone: str, text: str, direction: str):
lead_id = find_lead_by_phone(phone)
if not lead_id:
return
direction_label = "Входящее SMS" if direction == "in" else "Исходящее SMS"
requests.post(
f"{KOMMO_BASE}/leads/{lead_id}/notes",
headers=KOMMO_HDR,
json=[{"note_type": "common", "params": {"text": f"{direction_label} ({phone}): {text}"}}],
)
def log_call_to_kommo(phone: str, duration: int, recording_url: str):
lead_id = find_lead_by_phone(phone)
if not lead_id:
return
note_text = f"Звонок Salesmsg ({phone}): {duration}с."
if recording_url:
note_text += f" Запись: {recording_url}"
requests.post(
f"{KOMMO_BASE}/leads/{lead_id}/notes",
headers=KOMMO_HDR,
json=[{"note_type": "call_in", "params": {"text": note_text, "duration": duration}}],
)
Сценарии использования
Автоматические SMS по стадиям воронки:
- “Встреча назначена” -> напоминание за день до встречи
- “КП отправлено” -> “Получили наше предложение? Готовы ответить на вопросы.”
- “Счёт выставлен” -> напоминание об оплате через 3 дня
Входящие SMS в Kommo:
- Клиент отвечает на SMS -> заметка в карточке сделки с текстом
- Менеджер видит всю SMS-переписку в хронологии сделки
Звонки:
call.completedwebhook -> заметка с длительностью и ссылкой на запись
Реальный кейс
SaaS-компания с US-клиентами, 6 менеджеров. До интеграции: SMS вёлась в личных телефонах менеджеров, нет лога в CRM, при уходе менеджера теряется история. После интеграции: все SMS и звонки через корпоративный Salesmsg номер, каждое сообщение в карточке сделки. Onboarding нового менеджера с историей переписки занял 15 минут вместо нескольких часов выяснения контекста.
Для кого актуально
Компании с US/CA клиентами, использующие SMS как основной канал follow-up. Если ваши менеджеры активно пишут клиентам с личных телефонов - это первый сигнал: коммуникация существует вне CRM и при уходе сотрудника теряется.
Смежная задача - телефонные звонки с транскриптами - разобрана в статье о интеграции IP-телефонии с Kommo.
Часто задаваемые вопросы
Как найти сделку в Kommo если клиент пишет с нового номера?
Если номер не совпадает ни с одним контактом в Kommo - создайте новый контакт и новую сделку через API. Укажите тег “Salesmsg inbound” чтобы менеджеры могли отфильтровать такие лиды.
Поддерживает ли Salesmsg MMS и файлы?
Да, Salesmsg поддерживает MMS (фото, PDF). В webhook-событии поле media_urls содержит массив URL вложений. Добавьте ссылки в заметку Kommo вместе с текстом.
Как обеспечить соответствие требованиям A2P 10DLC?
A2P 10DLC (Application-to-Person 10-Digit Long Code) - регуляторное требование для бизнес-SMS в США. Salesmsg проводит вас через процесс регистрации Brand и Campaign. Без регистрации carrier carriers фильтруют сообщения. Среднее время одобрения - 3-5 рабочих дней.
Итог
Kommo + Salesmsg связывает SMS/звонки и CRM:
- Kommo webhook -> автоматические SMS по событиям воронки
- Входящие SMS -> заметки в карточке сделки через find-by-phone
- Завершённые звонки -> note с длительностью и записью
- Webhook верификация через HMAC-SHA256 заголовок
Если ваша команда работает с US/CA рынком и хочет перевести SMS-коммуникацию в CRM-контекст - обратитесь в Exceltic.dev. Настроим интеграцию под ваш стек воронки.