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 URLhttps://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 настроит маппинг переменных и обработку событий.