MailerLite - email-маркетинг с простым тарифным планом, GDPR-compliant инфраструктурой и REST API v2. Для B2B команд интеграция с Kommo решает конкретную задачу: автоматически добавлять лид в нужную группу MailerLite при переходе между этапами воронки, и синхронизировать статус подписки обратно в Kommo. Без Zapier и без дублей - через кастомную интеграцию.
MailerLite API v2 использует Bearer token (Authorization: Bearer {API_KEY}). Основные операции: POST /api/subscribers - создать/обновить подписчика, POST /api/groups/{id}/subscribers - добавить в группу, DELETE /api/groups/{id}/subscribers/{email} - удалить из группы. Webhooks отправляются при действиях подписчика: открыл письмо, кликнул, отписался.
Группа MailerLite - список подписчиков, аналог HubSpot List или Mailchimp Audience. Каждый этап воронки Kommo соответствует определённой группе MailerLite.
Архитектура: воронка как источник сегментации
Kommo этап "Квалифицирован"
-> webhook leads.status.changed
-> Ваш сервер
Ваш сервер
-> GET Kommo: email и имя контакта по сделке
-> MailerLite API: upsert subscriber + поле lead_id
-> MailerLite API: добавить в группу "Квалифицированные лиды"
-> убрать из предыдущей группы (если была)
MailerLite: отправить nurturing-последовательность
-> webhook: subscriber.unsubscribed
-> Ваш сервер -> Kommo: note "Отписался от email"
Реализация: Kommo -> MailerLite
import requests, os
from flask import Flask, request, jsonify
app = Flask(__name__)
ML_API_KEY = os.environ["MAILERLITE_API_KEY"]
ML_BASE = "https://connect.mailerlite.com/api"
ML_HDR = {"Authorization": f"Bearer {ML_API_KEY}", "Content-Type": "application/json"}
KOMMO_SUBDOMAIN = os.environ["KOMMO_SUBDOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_ACCESS_TOKEN"]
KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR = {"Authorization": f"Bearer {KOMMO_TOKEN}", "Content-Type": "application/json"}
# Маппинг этапов Kommo -> группы MailerLite
STAGE_TO_GROUP = {
int(os.environ.get("STAGE_QUALIFIED", "0")): os.environ.get("ML_GROUP_QUALIFIED", ""),
int(os.environ.get("STAGE_PROPOSAL", "0")): os.environ.get("ML_GROUP_PROPOSAL", ""),
int(os.environ.get("STAGE_NEGOTIATION", "0")): os.environ.get("ML_GROUP_NEGOTIATION", ""),
int(os.environ.get("STAGE_WON", "0")): os.environ.get("ML_GROUP_WON", ""),
int(os.environ.get("STAGE_LOST", "0")): os.environ.get("ML_GROUP_LOST", ""),
}
def get_contact_for_lead(lead_id: int) -> tuple[str, str, str]:
r = requests.get(
f"{KOMMO_BASE}/leads/{lead_id}",
headers=KOMMO_HDR,
params={"with": "contacts"},
)
contacts = r.json().get("_embedded", {}).get("contacts", [])
if not contacts:
return "", "", ""
rc = requests.get(
f"{KOMMO_BASE}/contacts/{contacts[0]['id']}",
headers=KOMMO_HDR,
params={"with": "custom_fields_values"},
)
c = rc.json()
email = ""
for cf in c.get("custom_fields_values", []) or []:
if cf.get("field_code") == "EMAIL":
vals = cf.get("values", [])
if vals:
email = vals[0].get("value", "")
break
name = c.get("name", "")
parts = name.split(maxsplit=1)
first = parts[0] if parts else ""
last = parts[1] if len(parts) > 1 else ""
return email, first, last
def upsert_subscriber(email: str, first: str, last: str, lead_id: int) -> dict:
r = requests.post(
f"{ML_BASE}/subscribers",
headers=ML_HDR,
json={
"email": email,
"fields": {
"name": first,
"last_name": last,
"kommo_lead_id": str(lead_id),
},
"status": "active",
},
)
r.raise_for_status()
return r.json().get("data", {})
def add_to_group(subscriber_id: str, group_id: str):
requests.post(
f"{ML_BASE}/subscribers/{subscriber_id}/groups",
headers=ML_HDR,
json={"groups": [group_id]},
)
def remove_from_all_groups(subscriber_id: str, exclude_group: str):
r = requests.get(f"{ML_BASE}/subscribers/{subscriber_id}/groups", headers=ML_HDR)
for g in r.json().get("data", []) or []:
gid = g.get("id", "")
if gid and gid != exclude_group:
requests.delete(
f"{ML_BASE}/subscribers/{subscriber_id}/groups/{gid}",
headers=ML_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},
}],
)
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
data = request.json or {}
for lead_data in data.get("leads", {}).get("status", []):
lead_id = lead_data.get("id")
new_status = lead_data.get("status_id")
group_id = STAGE_TO_GROUP.get(new_status)
if not group_id:
continue
email, first, last = get_contact_for_lead(lead_id)
if not email:
continue
sub = upsert_subscriber(email, first, last, lead_id)
sub_id = sub.get("id", "")
if not sub_id:
continue
remove_from_all_groups(sub_id, group_id)
add_to_group(sub_id, group_id)
add_note(lead_id, f"MailerLite: подписчик {email} добавлен в группу {group_id}.")
return jsonify({"status": "ok"}), 200
Реализация: MailerLite webhook -> Kommo
@app.route("/webhooks/mailerlite", methods=["POST"])
def mailerlite_webhook():
# MailerLite подписывает webhooks через X-Mailerlite-Signature
event = request.json or {}
ev = event.get("event", {})
ev_type = ev.get("type", "")
if ev_type not in ("subscriber.unsubscribed", "subscriber.bounced", "subscriber.junk"):
return jsonify({"status": "ignored"}), 200
subscriber = event.get("subscriber", {}) or {}
fields = subscriber.get("fields", {}) or {}
lead_id = (fields.get("kommo_lead_id") or {}).get("value", "")
email = subscriber.get("email", "")
if not lead_id:
return jsonify({"status": "no_lead_id"}), 200
msgs = {
"subscriber.unsubscribed": f"MailerLite: {email} отписался от рассылки.",
"subscriber.bounced": f"MailerLite: email {email} недоступен (bounce).",
"subscriber.junk": f"MailerLite: {email} пометил письмо как спам.",
}
add_note(int(lead_id), msgs.get(ev_type, f"MailerLite: событие {ev_type} для {email}."))
return jsonify({"status": "ok"}), 200
Настройка webhook MailerLite
Dashboard -> Settings -> Webhooks -> Add webhook. URL: https://your-server.com/webhooks/mailerlite. Events: выбрать все subscriber-события.
MailerLite подписывает тело запроса через X-Mailerlite-Signature. Алгоритм: HMAC-SHA256 тела с webhook secret. Добавьте верификацию аналогично примеру выше.
Поле kommo_lead_id в MailerLite
При создании подписчика через API поле kommo_lead_id передаётся в fields. MailerLite хранит кастомные поля для каждого подписчика. При настройке: создайте кастомное поле kommo_lead_id (тип Text) в MailerLite Dashboard -> Settings -> Subscriber fields.
Предотвращение дублей
MailerLite использует email как уникальный ключ - POST /api/subscribers с существующим email обновит запись, не создаст дубль. Это работает корректно только если в Kommo у контактов нет нескольких email-адресов. Используйте основной (первый) email из field_code: EMAIL.
Для кого актуально
B2B команды с CRM-воронкой в Kommo и email-маркетингом в MailerLite. Особенно полезно если:
- Разные стадии сделки должны получать разные nurturing-цепочки
- Нужно останавливать рассылку при потере интереса (lead = Lost -> unsubscribe)
- Команда не хочет мониторить два инструмента отдельно
Аналогичные интеграции описаны для Kommo + Ortto и Kommo + ActiveCampaign.
Часто задаваемые вопросы
Как убедиться что подписчик не получит два письма из разных групп?
MailerLite отправляет automation только для группы, которая её тригерит. Если подписчик в двух группах, он получает оба automation. Решение: использовать remove_from_all_groups перед добавлением в новую - гарантирует что подписчик всегда только в одной Kommo-группе.
Работает ли MailerLite API v1 с этим кодом?
Нет. MailerLite v1 устарел и не поддерживается. Используйте v2 с базовым URL https://connect.mailerlite.com/api. API Key в v2 создаётся через Dashboard -> Settings -> Developer API.
Как сегментировать по стране через MailerLite из Kommo?
Добавьте поле country в fields при создании подписчика. Значение берите из custom field контакта в Kommo. Затем в MailerLite создайте Segment с условием fields.country = "US" - используйте его для гео-таргетинга кампаний.
Итог
Kommo + MailerLite - email-маркетинг из воронки:
- Bearer token,
POST /api/subscribers- upsert по email (без дублей) kommo_lead_idв кастомном поле для обратной корреляцииremove_from_all_groups->add_to_group- подписчик всегда в актуальной группе- MailerLite webhook
subscriber.unsubscribed-> note в Kommo - Один контакт = одна группа = одна nurturing-цепочка
Если нужна интеграция Kommo с MailerLite или другой email-платформой - опишите задачу команде Exceltic.dev.