Kommo + Contractbook: автоматическая отправка контрактов из карточки сделки

Kommo + Contractbook: автоматическая отправка контрактов из карточки сделки

Contractbook — CLM-платформа (Contract Lifecycle Management): создание контрактов из шаблонов, электронная подпись, хранение и отслеживание версий. Без интеграции с Kommo менеджер закрывает сделку, вручную открывает Contractbook, копирует имя клиента, email и условия договора. С интеграцией Won в воронке автоматически создаёт контракт из шаблона с заполненными данными сделки и отправляет его на подпись — менеджер получает уведомление только когда контракт подписан.

Чем Contractbook отличается от DocuSign и PandaDoc

DocuSign и Adobe Sign — инструменты электронной подписи. Они берут готовый документ и собирают подписи.

Contractbook — полноценный CLM: шаблоны с динамическими полями, переговорный процесс (комментарии к клаузам), версионность, автоматическое напоминание о продлении, AI-анализ рисков в контракте. Для SaaS с нестандартными условиями, корпоративных продаж с редлайнами и команд, которым важна история изменений контракта — Contractbook закрывает больше, чем просто сбор подписи.

Если у вас стандартный контракт без правок — подписание через DocuSign или Dropbox Sign проще. Contractbook оправдывает себя когда контракт согласовывается, а не просто подписывается.

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

Kommo -> Contractbook:
— Won -> создать Draft контракт из шаблона с полями из сделки (имя, email, сумма, тариф, срок)
— Won -> отправить контракт на подпись контакту сделки
— Обновление суммы сделки -> обновить переменную deal_amount в черновике

Contractbook -> Kommo:
contract.signed -> Note: «Contractbook: контракт подписан» + смена этапа
contract.declined -> Note + задача менеджеру: «Клиент отклонил контракт — обсудить условия»
contract.expired -> Note + задача: «Контракт истёк без подписи»
contract.sent -> Note: «Contractbook: контракт отправлен на подпись»

Архитектура

Kommo Webhook: сделка перешла в Won
  ↓ Backend
  1. GET /api/v4/leads/{id} + contacts
     -> имя, email, сумма, тариф, условия из кастомных полей
  2. Contractbook API: POST /drafts
     -> template_id + variables (данные из сделки)
     -> создаёт черновик контракта
  3. Contractbook API: POST /drafts/{draft_id}/send
     -> signee: {email, name}
     -> отправляет контракт на подпись
  4. Kommo: PATCH /leads/{id}
     -> кастомное поле contractbook_draft_id = draft_id
  5. Kommo: POST /leads/{id}/notes
     -> «Contractbook: контракт отправлен на подпись»

Contractbook Webhook: contract.signed
  ↓ Backend
  1. Верификация подписи (X-Contractbook-Signature)
  2. Найти сделку по contractbook_draft_id
  3. Kommo: PATCH /leads/{id} -> смена этапа на «Контракт подписан»
  4. Kommo: POST /leads/{id}/notes
     -> «Contractbook: контракт подписан - сделка активирована»

Contractbook API: ключевые запросы

Base URL: https://api.contractbook.com/v1.
Аутентификация: API key в заголовке Authorization: ApiKey {api_key}.

Создать черновик из шаблона:

import requests

CB_API_KEY = "your_contractbook_api_key"
CB_BASE_URL = "https://api.contractbook.com/v1"

headers = {
    "Authorization": f"ApiKey {CB_API_KEY}",
    "Content-Type": "application/json"
}

def create_contract_draft(template_id: str, variables: dict, signee_email: str, signee_name: str) -> dict:
    resp = requests.post(
        f"{CB_BASE_URL}/drafts",
        headers=headers,
        json={
            "template_id": template_id,
            "variables": variables,
            "signatories": [
                {"email": signee_email, "name": signee_name, "role": "client"}
            ]
        }
    )
    resp.raise_for_status()
    return resp.json()

def send_contract_for_signing(draft_id: str) -> None:
    resp = requests.post(
        f"{CB_BASE_URL}/drafts/{draft_id}/send",
        headers=headers
    )
    resp.raise_for_status()

def on_deal_won(lead: dict, contact: dict):
    email = get_contact_email(contact)
    name = contact["name"]
    deal_amount = lead.get("price", 0)
    plan = get_custom_field(lead, PLAN_FIELD_ID) or "Growth"

    # Переменные шаблона Contractbook - должны совпадать с полями шаблона
    variables = {
        "client_name": name,
        "client_email": email,
        "deal_amount": str(deal_amount),
        "plan": plan,
        "contract_date": datetime.now().strftime("%d.%m.%Y"),
        "kommo_deal_id": str(lead["id"])
    }

    draft = create_contract_draft(
        template_id=CONTRACTBOOK_TEMPLATE_ID,
        variables=variables,
        signee_email=email,
        signee_name=name
    )
    draft_id = draft["id"]

    send_contract_for_signing(draft_id)

    update_kommo_deal(lead["id"], {"contractbook_draft_id": draft_id})
    create_kommo_note(lead["id"], f"Contractbook: контракт {draft_id} отправлен на подпись")

Обработка Contractbook Webhook:

from flask import Flask, request, abort
import hmac, hashlib

app = Flask(__name__)
CB_WEBHOOK_SECRET = "your_webhook_secret"

def verify_cb_signature(payload: bytes, signature: str) -> bool:
    expected = hmac.new(
        CB_WEBHOOK_SECRET.encode(),
        payload,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

@app.route("/webhooks/contractbook", methods=["POST"])
def contractbook_webhook():
    sig = request.headers.get("X-Contractbook-Signature", "")
    if not verify_cb_signature(request.data, sig):
        abort(403)

    payload = request.json
    event = payload.get("event")
    draft_id = payload.get("data", {}).get("id")

    deal_id = find_deal_by_field("contractbook_draft_id", draft_id)
    if not deal_id:
        return "", 200

    if event == "contract.signed":
        update_kommo_deal(deal_id, {"stage_id": STAGE_CONTRACT_SIGNED})
        create_kommo_note(deal_id, "Contractbook: контракт подписан клиентом")

    elif event == "contract.declined":
        create_kommo_note(deal_id, "Contractbook: клиент отклонил контракт")
        create_kommo_task(deal_id, "Обсудить условия - контракт отклонён в Contractbook")

    elif event == "contract.expired":
        create_kommo_note(deal_id, "Contractbook: контракт истёк без подписи")
        create_kommo_task(deal_id, "Контракт в Contractbook истёк - напомнить клиенту")

    return "", 200

Настройка Webhook в Contractbook: Settings -> Integrations -> Webhooks -> Add webhook. Указать URL, выбрать события. Секрет для верификации генерируется при создании.

Управление шаблонами: маппинг переменных

В Contractbook шаблон содержит переменные — {{client_name}}, {{deal_amount}}, {{plan}}. При создании черновика эти переменные заменяются значениями из variables в теле запроса.

Маппинг кастомных полей Kommo -> переменные Contractbook настраивается один раз:

FIELD_TO_VARIABLE = {
    PLAN_FIELD_ID:     "plan",
    COMPANY_FIELD_ID:  "client_company",
    ADDRESS_FIELD_ID:  "billing_address",
    TERM_FIELD_ID:     "contract_term_months",
}

def build_variables(lead: dict, contact: dict) -> dict:
    variables = {
        "client_name": contact["name"],
        "client_email": get_contact_email(contact),
        "deal_amount": str(lead.get("price", 0)),
        "contract_date": datetime.now().strftime("%d.%m.%Y"),
    }
    for field_id, var_name in FIELD_TO_VARIABLE.items():
        value = get_custom_field(lead, field_id)
        if value:
            variables[var_name] = value
    return variables

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

B2B SaaS (EU, 25–35 новых корпоративных клиентов в месяц, Kommo + Contractbook):

  • До: менеджер после Won вручную создавал контракт в Contractbook, копируя данные из Kommo. Занимало 15–20 минут на сделку. Ошибки в имени или сумме -> повторная отправка. О том, что клиент подписал, узнавали из email Contractbook, а в Kommo никто не обновлял.
  • После: Won -> контракт с корректными данными отправлен за 10 секунд. При подписании — автоматическая смена этапа в Kommo. CSM видит статус без переключения систем.
  • Дополнительно: contract.expired без подписи за 7 дней -> задача менеджеру -> retention 40% незакрытых контрактов превратились в подписанные после напоминания.

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

  • B2B с корпоративными контрактами, которые нужно согласовывать (редлайны, версии)
  • Продажи с кастомными условиями — не стандартный договор оферты, а индивидуальный контракт
  • Команды, которым важна история версий и аудит изменений контракта
  • 20+ новых клиентов в месяц — при меньшем объёме ручная работа ещё терпима

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

Contractbook vs PandaDoc для интеграции с Kommo?

PandaDoc — лучше для sales-документов: пропозалы, коммерческие предложения, прайс-листы. Contractbook — для юридических контрактов с историей версий, AI-анализом рисков и управлением продлениями. Если нужны оба сценария — часто используют PandaDoc на стадии предложения и Contractbook на стадии контракта.

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

Contractbook позволяет редактировать черновик через API до отправки. PATCH /drafts/{draft_id} с content в формате Contractbook JSON обновляет текст. Для типовых кастомных клауз — добавьте отдельный шаблон под каждый сценарий, маппинг тарифа -> template_id в коде.

Как отслеживать статус контракта если webhook не пришёл?

Периодический polling: GET /drafts/{draft_id} -> поле status. Статусы: draft, sent, signed, declined, expired. Cron раз в час проверяет все сделки с contractbook_draft_id и статусом sent дольше N дней.

Contractbook поддерживает многостороннее подписание?

Да. В signatories можно передать массив получателей с разными ролями (client, witness, internal). Внутренняя подпись от CEO компании + подпись клиента настраиваются в одном запросе.

Итого

  • Contractbook: API key в заголовке Authorization: ApiKey, base URL https://api.contractbook.com/v1
  • Создать черновик: POST /drafts с template_id и variables из полей Kommo
  • Отправить на подпись: POST /drafts/{draft_id}/send
  • Webhook верификация: HMAC-SHA256 через X-Contractbook-Signature
  • Ключевые события: contract.signed, contract.declined, contract.expired
  • Хранить contractbook_draft_id в кастомном поле сделки для обратного поиска

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

Ещё статьи

Все →