Kommo + Better Proposals: интерактивные предложения из карточки сделки с трекингом

Kommo + Better Proposals: интерактивные предложения из карточки сделки с трекингом

Better Proposals — платформа для создания интерактивных веб-предложений (не PDF): потенциальный клиент открывает ссылку в браузере, видит красиво оформленный документ, может подписать электронно и оплатить прямо на странице. В отличие от PandaDoc или DocuSign, Better Proposals специализируется именно на proposal-стадии воронки — с детальным трекингом просмотров, heat maps и A/B тестами шаблонов. Без интеграции с Kommo: каждое предложение создаётся вручную, данные о просмотрах не попадают в CRM, момент подписания менеджер узнаёт из email.

Better Proposals vs PandaDoc vs Qwilr

ПараметрBetter ProposalsPandaDocQwilr
ФорматВеб-страницаВеб + PDFВеб-страница
Трекинг просмотровДетальный (scroll, time per section)БазовыйБазовый
Электронная подписьДаДа (eSign)Да
Встроенный платёжДа (Stripe)НетДа
Шаблоны200+750+60+
Ценаот $19/месот $35/месот $35/мес

Better Proposals выбирают агентства и консалтинговые компании, где визуальное качество предложения влияет на close rate, а трекинг «когда клиент читал» — критичен для тайминга follow-up.

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

Kommo -> Better Proposals:
— Won (или кастомный этап) -> создать предложение из шаблона, подставить данные контакта и сделки
— Изменение суммы в Kommo -> обновить цену в черновике предложения

Better Proposals -> Kommo:
proposal.opened -> Note: «Предложение открыто клиентом» + timestamp
proposal.signed -> Note: «Подписано» + смена статуса сделки или этапа воронки
proposal.paid -> Note: «Оплата получена через страницу предложения»
proposal.expired -> Task: «Предложение истекло — follow-up»

Better Proposals API: создание предложения

Base URL: https://api.betterproposals.io/v1. Аутентификация: заголовок Authorization: Bearer {api_token} (токен из Better Proposals -> Settings -> Integrations -> API).

import requests

BP_TOKEN   = "your_bearer_token"
BP_BASE    = "https://api.betterproposals.io/v1"
BP_HEADERS = {
    "Authorization": f"Bearer {BP_TOKEN}",
    "Content-Type":  "application/json",
    "Accept":        "application/json",
}

def create_proposal(template_id: int, contact_name: str, contact_email: str,
                    company: str, deal_value: float, currency: str = "USD") -> dict:
    # template_id из Better Proposals -> Templates -> Edit -> URL
    payload = {
        "template_id": template_id,
        "name":        f"Proposal for {company}",
        "contacts": [
            {
                "name":    contact_name,
                "email":   contact_email,
                "company": company,
            }
        ],
        "variables": {
            "company_name": company,
            "deal_value":   f"{deal_value:,.2f} {currency}",
        },
        "expiry_date": None,
        "currency":    currency,
        "price":       deal_value,
    }
    resp = requests.post(f"{BP_BASE}/proposals", headers=BP_HEADERS, json=payload)
    resp.raise_for_status()
    return resp.json()

def get_proposal_link(proposal_id: int) -> str:
    resp = requests.get(f"{BP_BASE}/proposals/{proposal_id}", headers=BP_HEADERS)
    resp.raise_for_status()
    data = resp.json()
    return data.get("url", "")

# Маппинг шаблонов Kommo -> Better Proposals
TEMPLATE_MAP = {
    "consulting": 12345,
    "saas":       12346,
    "retainer":   12347,
}

def on_deal_reached_proposal_stage(lead: dict, contact: dict):
    # Вызывается когда сделка переходит в этап "Proposal"
    company    = get_custom_field(lead, COMPANY_FIELD_ID) or contact.get("name", "")
    email      = get_contact_email(contact)
    deal_type  = get_custom_field(lead, DEAL_TYPE_FIELD_ID) or "saas"
    template_id = TEMPLATE_MAP.get(deal_type.lower(), TEMPLATE_MAP["saas"])

    proposal   = create_proposal(
        template_id   = template_id,
        contact_name  = contact.get("name", ""),
        contact_email = email,
        company       = company,
        deal_value    = lead.get("price", 0),
    )
    proposal_id  = proposal.get("id")
    proposal_url = get_proposal_link(proposal_id)

    save_to_kommo_deal(lead["id"], {
        "bp_proposal_id":  proposal_id,
        "bp_proposal_url": proposal_url,
    })
    create_kommo_note(
        lead["id"],
        f"Better Proposals: предложение создано -> {proposal_url}",
    )

Webhooks: Better Proposals -> Kommo

Better Proposals поддерживает webhooks: Settings -> Webhooks -> Add Webhook. Payload подписывается HMAC-SHA256 заголовком X-BP-Signature.

import hmac, hashlib

BP_WEBHOOK_SECRET = "your_webhook_secret"

@app.route("/webhooks/better-proposals", methods=["POST"])
def bp_webhook():
    sig = request.headers.get("X-BP-Signature", "")
    expected = hmac.new(
        BP_WEBHOOK_SECRET.encode(),
        request.data,
        hashlib.sha256,
    ).hexdigest()
    if not hmac.compare_digest(sig, expected):
        return "", 401

    payload     = request.json
    event       = payload.get("event")
    proposal_id = payload.get("proposal", {}).get("id")

    lead_id = find_kommo_deal_by_custom_field("bp_proposal_id", str(proposal_id))
    if not lead_id:
        return "", 200

    if event == "proposal.opened":
        opened_at = payload.get("proposal", {}).get("opened_at", "")
        create_kommo_note(lead_id, f"Better Proposals: предложение открыто клиентом ({opened_at})")

    elif event == "proposal.signed":
        signed_at = payload.get("proposal", {}).get("signed_at", "")
        create_kommo_note(lead_id,
            f"Better Proposals: предложение подписано ({signed_at}) - ожидаем оплату")
        move_kommo_deal_to_stage(lead_id, SIGNED_STAGE_ID)

    elif event == "proposal.paid":
        amount = payload.get("proposal", {}).get("price", 0)
        create_kommo_note(lead_id,
            f"Better Proposals: оплата получена - ${amount:.2f}")
        move_kommo_deal_to_stage(lead_id, WON_STAGE_ID)

    elif event == "proposal.expired":
        create_kommo_note(lead_id, "Better Proposals: срок предложения истёк")
        create_kommo_task(lead_id, "Better Proposals: follow-up - выслать обновлённое предложение")

    return "", 200

Трекинг просмотров: как использовать данные

Better Proposals фиксирует: время открытия каждого раздела, сколько секунд клиент провёл на каждой секции, с какого устройства. Через API можно получить эти данные:

def get_proposal_analytics(proposal_id: int) -> dict:
    resp = requests.get(
        f"{BP_BASE}/proposals/{proposal_id}/analytics",
        headers=BP_HEADERS,
    )
    resp.raise_for_status()
    return resp.json()

def sync_proposal_analytics_to_kommo(lead_id: int, proposal_id: int):
    analytics = get_proposal_analytics(proposal_id)
    views      = analytics.get("views", 0)
    avg_time   = analytics.get("average_time_spent", 0)
    note = (
        f"Better Proposals analytics: просмотров {views}, "
        f"среднее время на предложении {avg_time} сек."
    )
    create_kommo_note(lead_id, note)

Эти данные помогают менеджеру выбрать момент follow-up: если клиент провёл на странице цены 3 минуты — самое время позвонить.

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

Digital-агентство (EU, 25 человек, Kommo + Better Proposals):

  • До: менеджер вручную копировал данные из Kommo в Better Proposals. 15–20 минут на каждый proposal. Уведомление о подписании — email, которое иногда проходило мимо внимания. Proposal stage -> Won задерживался на 2–3 дня.
  • После: переход в этап «Proposal» в воронке -> автоматически создаётся предложение из шаблона (по типу сделки) -> ссылка сохраняется в Kommo. proposal.opened -> Note. proposal.signed -> автоматическая смена этапа на «Won».
  • Результат: время от «Proposal» до «Won» сократилось с 4.2 дня до 1.8 дня — менеджеры видели в реальном времени когда клиент изучал предложение и звонили в правильный момент.

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

  • Агентства (digital, consulting, marketing) где proposal — ключевой этап воронки
  • B2B с несколькими стандартными типами предложений (шаблоны по service line)
  • Компании где важен тайминг follow-up — трекинг просмотров даёт правильный момент
  • Команды где proposal стадия занимает > 3 дней — автоматизация ускоряет цикл

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

Better Proposals поддерживает переменные для автозаполнения данных сделки?

Да. В шаблоне Better Proposals можно создавать переменные ({company_name}, {deal_value}, {manager_name}) — они заполняются при создании предложения через API через поле variables. Стандартные поля контакта (имя, email, компания) заполняются автоматически из contacts объекта в payload.

Можно ли обновить цену в уже отправленном предложении?

Да, через PATCH /proposals/{id} с новым price — но только если предложение не подписано. После подписания предложение заблокировано. Если сумма изменилась после отправки — создаётся новое предложение (POST /proposals) с пометкой «Revised» в названии, старое закрывается через DELETE /proposals/{id}.

Как настроить разные шаблоны для разных типов сделок?

В Kommo добавить кастомное поле «Тип услуги» (select). При переходе в этап Proposal — webhook передаёт значение поля -> Python-обработчик смотрит TEMPLATE_MAP -> выбирает нужный template_id Better Proposals. Шаблоны создаются в Better Proposals один раз командой, далее используются API-автоматически.

Better Proposals vs Qwilr — в чём разница для интеграции с Kommo?

API-уровень аналогичен: Bearer token, CRUD proposals, webhooks. Главное отличие: Better Proposals даёт более детальную аналитику просмотров (секция-per-секция), Qwilr — более гибкий дизайн. Для интеграции с Kommo архитектура одинакова. Выбор платформы — вопрос UX для менеджеров и дизайна proposals, не технической стороны.

Итого

  • API: Bearer token, Authorization: Bearer {token}, base URL https://api.betterproposals.io/v1
  • Поток: этап «Proposal» в Kommo -> POST /proposals с template_id + данные контакта
  • Webhook: proposal.opened/signed/paid/expired -> Note/Task/смена этапа в Kommo
  • Аналитика просмотров: GET /proposals/{id}/analytics -> Note с engagement данными
  • Триггер не обязательно Won — можно любой этап воронки где начинается proposal-работа

Если у вас агентство или B2B с proposal-стадией воронки и вы хотите автоматизировать создание предложений из Kommo — опишите структуру шаблонов и типы сделок. Exceltic.dev настроит двустороннюю интеграцию с трекингом.

Ещё статьи

Все →