Kommo + Customer.io: триггерные email-последовательности из воронки продаж

Kommo + Customer.io: триггерные email-последовательности из воронки продаж

Customer.io — платформа поведенческого email-маркетинга с Track API на Basic Auth. Без интеграции с Kommo маркетолог вручную добавляет контакты в Customer.io, менеджер не знает, открыл ли клиент письмо перед звонком, а отписка клиента не обновляет поля в CRM. С интеграцией смена этапа воронки в Kommo запускает Customer.io-кампанию автоматически — и каждое взаимодействие с письмом отражается в таймлайне сделки.

Что даёт связка Kommo + Customer.io

Без интеграции:
— Маркетолог ведёт список Customer.io вручную — с задержкой 1–3 дня от смены статуса в CRM
— Менеджер не знает, получил ли клиент welcome-письмо перед первым звонком
— Клиент отписался в Customer.io -> Kommo об этом не знает, менеджер снова пишет
— Email-последовательности и CRM-пайплайн живут в разных системах без связи

С интеграцией:
— Won в Kommo -> Customer.io: identify + событие deal_won -> onboarding-кампания запущена
email.opened -> Note в Kommo: «Клиент открыл письмо (тема)»
email.clicked -> Note: «Клик по ссылке в письме»
email.unsubscribed -> кастомное поле email_status = unsubscribed + задача менеджеру
email.bounced -> задача проверить email контакта

Что синхронизируется

Kommo -> Customer.io:
— Email, имя, телефон контакта -> Customer profile в Customer.io
— Тариф, сегмент из кастомных полей -> Customer attributes для персонализации писем
— Смена этапа воронки -> event -> триггер кампании
— ID сделки -> Customer attribute kommo_deal_id для обратной трассировки

Customer.io -> Kommo:
email.opened -> Note в сделку
email.clicked -> Note со ссылкой по которой кликнул
email.unsubscribed -> поле + задача
email.bounced -> поле + задача на проверку email
email.converted (если настроен goal) -> Note «Конверсия из письма»

Архитектура

Kommo Webhook: сделка перешла в этап «Онбординг»
  ↓ Backend
  1. GET /api/v4/leads/{id} + contacts
     -> email, имя, тариф из кастомных полей
  2. Customer.io Track API: PUT /api/v1/customers/{email}
     -> первичная идентификация с атрибутами
  3. Customer.io Track API: POST /api/v1/customers/{email}/events
     -> event: 'onboarding_started', properties: {plan, deal_id}
     -> запускает кампанию с trigger: event = 'onboarding_started'
  4. Kommo: POST /leads/{deal_id}/notes
     -> «Onboarding email-кампания запущена в Customer.io»

Customer.io Reporting Webhook: email.clicked
  ↓ Backend
  1. Из payload: customer_id (email), subject, link_url, timestamp
  2. Найти deal_id по email -> kommo_deal_id в Customer.io или по контакту Kommo
  3. Kommo: POST /leads/{deal_id}/notes

Customer.io Reporting Webhook: email.unsubscribed
  ↓ Backend
  1. customer_id, timestamp
  2. Найти deal_id
  3. Kommo: PATCH /leads/{deal_id} -> email_status = unsubscribed
  4. Kommo: POST /tasks -> «Клиент отписался - уточнить предпочтения»

Customer.io Track API: ключевые запросы

Base URL Track API: https://track.customer.io/api/v1/. Аутентификация: Basic Auth, username = site_id, password = api_key. Оба значения берутся из Customer.io: Settings -> API Credentials.

Идентификация пользователя:

import requests
from requests.auth import HTTPBasicAuth

CIO_SITE_ID = 'your_site_id'
CIO_API_KEY = 'your_api_key'
CIO_AUTH = HTTPBasicAuth(CIO_SITE_ID, CIO_API_KEY)
CIO_TRACK_URL = 'https://track.customer.io/api/v1'

def identify_customer(email: str, attributes: dict) -> None:
    # Создать или обновить профиль в Customer.io
    resp = requests.put(
        f'{CIO_TRACK_URL}/customers/{email}',
        auth=CIO_AUTH,
        json=attributes
    )
    resp.raise_for_status()

Отправить событие:

def track_event(email: str, event_name: str, data: dict = None) -> None:
    # Отправить событие для триггера кампании
    resp = requests.post(
        f'{CIO_TRACK_URL}/customers/{email}/events',
        auth=CIO_AUTH,
        json={'name': event_name, 'data': data or {}}
    )
    resp.raise_for_status()

def on_deal_won(lead: dict, contact: dict):
    email = get_contact_email(contact)
    plan = get_custom_field(lead, field_id=PLAN_FIELD_ID)

    identify_customer(email, {
        'first_name': contact['name'].split()[0],
        'plan': plan,
        'kommo_deal_id': lead['id'],
        'deal_amount': lead.get('price', 0)
    })

    track_event(email, 'deal_won', {'plan': plan, 'deal_id': lead['id']})

Маппинг событий Kommo -> Customer.io:

STAGE_EVENT_MAP = {
    '12345678': 'demo_scheduled',
    '12345679': 'demo_completed',
    '12345680': 'proposal_sent',
    '12345681': 'deal_won',
}

def on_stage_change(lead_id: int, new_status_id: int):
    event_name = STAGE_EVENT_MAP.get(str(new_status_id))
    if not event_name:
        return
    lead = get_kommo_lead(lead_id)
    contact = get_kommo_contact(lead_id)
    email = get_contact_email(contact)
    track_event(email, event_name, {'deal_id': lead_id})

Обработка Customer.io Reporting Webhook:

from flask import Flask, request

app = Flask(__name__)

@app.route('/webhooks/customerio', methods=['POST'])
def customerio_webhook():
    payload = request.json
    event_type = payload.get('event_type')
    customer_id = payload.get('data', {}).get('customer_id')

    deal_id = find_kommo_deal_by_email(customer_id)
    if not deal_id:
        return '', 200

    if event_type == 'email_opened':
        subject = payload.get('data', {}).get('subject', '')
        create_kommo_note(deal_id, f'Customer.io: открыл письмо - {subject}')

    elif event_type == 'email_clicked':
        link = payload.get('data', {}).get('href', '')
        subject = payload.get('data', {}).get('subject', '')
        create_kommo_note(deal_id, f'Customer.io: кликнул в письме {subject} -> {link}')

    elif event_type == 'email_unsubscribed':
        update_kommo_deal(deal_id, {'email_status': 'unsubscribed'})
        create_kommo_task(deal_id,
            'Клиент отписался от рассылки Customer.io - уточнить предпочтения')

    elif event_type == 'email_bounced':
        bounce_type = payload.get('data', {}).get('type', '')
        update_kommo_deal(deal_id, {'email_status': f'bounced_{bounce_type}'})
        create_kommo_task(deal_id,
            f'Email недоставлен (bounce: {bounce_type}) - проверить адрес')

    return '', 200

Настройка Reporting Webhook в Customer.io: Settings -> Integrations -> Reporting Webhooks -> Add Endpoint. Выбрать события: email_opened, email_clicked, email_unsubscribed, email_bounced, email_converted. Customer.io подписывает payload через HMAC-SHA256, заголовок X-CIO-Signature для верификации.

EU-инстанс: если аккаунт на EU-серверах — Track API URL: https://track-eu.customer.io/api/v1. Проверить в настройках: Settings -> Account -> Data Region.

Персонализация писем через атрибуты Kommo

Customer.io позволяет использовать атрибуты клиента в шаблонах письма через Liquid: {{ customer.plan }}, {{ customer.first_name }}. Данные из Kommo передаются при identify_customer:

identify_customer(email, {
    'first_name': 'John',
    'plan': 'Pro',
    'company': 'Acme Inc',
    'deal_amount': 1500,
    'account_manager': 'Sarah'
})

Это даёт персонализацию писем без дополнительных усилий — все переменные из CRM уже в профиле.

Реальный кейс

B2B SaaS (US, 50–70 новых клиентов в месяц, Kommo + Customer.io + Stripe, onboarding-кампания из 7 писем):

  • До: маркетолог добавлял новых клиентов в Customer.io вручную раз в день по выгрузке из Kommo. Первое письмо уходило с задержкой 24–48 часов от момента Won. Отписки не попадали в CRM.
  • После: Won -> Customer.io -> первое письмо за 3 минуты. Персонализация по тарифу и имени. При клике на ссылку документации — Note в Kommo, менеджер видит активность клиента.
  • Дополнительно: если клиент не открыл ни одного письма за 5 дней — триггер onboarding_inactive -> задача CSM-у на ручной аутрич.

Для кого актуально

  • SaaS-компании с активным email-онбордингом (welcome-серии, обучающие кампании)
  • Продажи через воронку Kommo, маркетинг через Customer.io
  • Менеджер должен видеть email-активность клиента перед звонком
  • 30+ новых клиентов в месяц — ручная синхронизация становится нерентабельной

Часто задаваемые вопросы

Customer.io API — Basic Auth или Bearer token?

Track API (для identify и событий) использует Basic Auth: site_id как username, api_key как password. App API (для управления кампаниями, сегментами) использует Bearer token. Для серверной интеграции с Kommo нужен Track API — Basic Auth.

Как настроить Reporting Webhook в Customer.io?

Settings -> Integrations -> Reporting Webhooks -> Add Endpoint. Указать URL вашего сервера, выбрать события. Customer.io подписывает каждый запрос через HMAC-SHA256 (X-CIO-Signature). Проверяйте подпись на сервере перед обработкой.

Customer.io vs Mailchimp для интеграции с Kommo?

Mailchimp ориентирован на списочные кампании. Customer.io — на поведенческие триггеры: событие в CRM -> кампания. Если нужен onboarding по этапам воронки, последовательности на основе действий в продукте — Customer.io. Если массовые рассылки по сегментам — Mailchimp.

Что делать если контакт уже есть в Customer.io до интеграции?

PUT /customers/{email} — idempotent: если профиль существует — обновит атрибуты, если нет — создаст. Атрибуты мерджатся, не перезаписываются полностью.

Как передавать данные из кастомных полей Kommo в Customer.io?

Через identify_customer передаётся произвольный словарь атрибутов. Для каждого нужного кастомного поля Kommo сделайте маппинг field_id -> имя атрибута Customer.io. Атрибуты сразу доступны в Liquid-шаблонах писем.

Итого

  • Customer.io Track API: Basic Auth (site_id:api_key), Base URL https://track.customer.io/api/v1/
  • Identify: PUT /customers/{email} с атрибутами из Kommo
  • Track event: POST /customers/{email}/events при смене этапа
  • Reporting Webhook: email_opened/clicked/unsubscribed/bounced -> Notes и задачи в Kommo
  • EU-инстанс: https://track-eu.customer.io/api/v1
  • Типовой срок разработки — 1–2 недели

Если вы используете Customer.io и Kommo и хотите замкнуть воронку продаж с email-маркетингом — опишите ваши этапы и кампании. Exceltic.dev настроит маппинг событий и обработку отписок в CRM.

Ещё статьи

Все →