Почему нативная интеграция не работает
Scrive - шведская платформа электронной подписи, широко используемая в Nordics (Швеция, Норвегия, Дания, Финляндия) и DACH-регионе. В отличие от DocuSign и Adobe Sign, Scrive изначально разрабатывался под требования европейского регулирования eIDAS, что делает его предпочтительным выбором для EU-компаний, которым важна юридическая сила электронной подписи в европейских судах.
Готовой интеграции Scrive + Kommo не существует. Scrive не представлен в маркетплейсе Kommo. Типичный сценарий без интеграции выглядит так: менеджер получает уведомление «сделка перешла на этап Договор», вручную открывает Scrive, создаёт документ, загружает шаблон, вводит email контакта, отправляет. После подписи возвращается в Kommo, меняет этап вручную, прикрепляет PDF. Каждый цикл - 10-15 минут ручной работы.
Для компаний с кастомными интеграциями Kommo это решаемая задача через REST API обеих систем.
Что реализуется - архитектура решения
Bidirectional flow через webhook:
Kommo: смена этапа "Договор"
--> Webhook --> Python сервис
--> Scrive API: создать документ, загрузить PDF шаблон
--> Scrive API: отправить signing invitations
Scrive: document.signed
--> Webhook --> Python сервис
--> Kommo API: обновить этап сделки
--> Kommo API: прикрепить подписанный PDF
Технические детали
Scrive API Auth. Bearer token. Получается через POST /api/v2/oauth/token с client_id и client_secret (из Scrive Admin Panel). Токен долгоживущий, но рекомендуется refresh при ошибке 401.
Ключевые эндпоинты Scrive API v2:
POST /api/v2/documents- создать документPOST /api/v2/documents/{id}/files/main- загрузить PDFPOST /api/v2/documents/{id}/start- запустить процесс подписания (отправить приглашения)GET /api/v2/documents/{id}/files/sealed- скачать подписанный PDFPOST /api/v2/hooks- создать webhook для событий документа
Структура документа Scrive. При создании документа через API передаётся JSON с описанием участников (parties) и полей для заполнения. Каждый party имеет role: signing_party (подписант) или viewer. Поля документа (signatory fields) могут быть signature, text, checkbox, date - они привязываются к координатам на странице PDF.
Kommo Webhooks. При переходе сделки на этап «Договор» Kommo отправляет webhook с leads[status][0][id] (ID сделки) и leads[status][0][status_id] (новый статус). Настройка: Kommo Admin -> Webhooks.
Пошаговая реализация
Шаг 1. Настройка Kommo Webhook
В Kommo Admin Panel -> Интеграции -> Webhooks добавьте URL вашего сервиса. Выберите событие «Смена этапа сделки». Запишите секретный ключ для верификации.
Шаг 2. Создание документа и отправка на подпись
import os
import requests
import json
from flask import Flask, request
app = Flask(__name__)
SCRIVE_BASE = "https://api.scrive.com"
SCRIVE_TOKEN = os.environ["SCRIVE_BEARER_TOKEN"]
KOMMO_DOMAIN = os.environ["KOMMO_DOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_ACCESS_TOKEN"]
# ID этапа "Договор" в вашей воронке Kommo
CONTRACT_STAGE_ID = int(os.environ.get("KOMMO_CONTRACT_STAGE_ID", 0))
# ID этапа "Договор подписан"
SIGNED_STAGE_ID = int(os.environ.get("KOMMO_SIGNED_STAGE_ID", 0))
# Путь к PDF-шаблону договора
CONTRACT_TEMPLATE_PATH = os.environ.get("CONTRACT_TEMPLATE_PATH", "contract_template.pdf")
def get_lead_details(lead_id: int) -> dict:
"""Получаем данные сделки из Kommo."""
url = f"https://{KOMMO_DOMAIN}/api/v4/leads/{lead_id}"
params = {"with": "contacts"}
headers = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
r = requests.get(url, params=params, headers=headers, timeout=10)
r.raise_for_status()
return r.json()
def get_contact_details(contact_id: int) -> dict:
"""Получаем данные контакта."""
url = f"https://{KOMMO_DOMAIN}/api/v4/contacts/{contact_id}"
headers = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
r = requests.get(url, headers=headers, timeout=10)
r.raise_for_status()
return r.json()
def create_scrive_document(title: str, signer_email: str, signer_name: str) -> dict:
"""Создаём документ в Scrive и загружаем PDF шаблон."""
scrive_headers = {
"Authorization": f"Bearer {SCRIVE_TOKEN}",
"Content-Type": "application/json",
}
# Создаём документ
doc_payload = {
"title": title,
"parties": [
{
"role": "signing_party",
"is_author": False,
"delivery_method": "email",
"fields": [
{"type": "email", "value": signer_email},
{"type": "name", "value": signer_name},
{
"type": "signature",
"name": "client_signature",
"placements": [
{"xrel": 0.1, "yrel": 0.85, "wrel": 0.3, "hrel": 0.05, "page": 1}
]
}
]
},
{
"role": "signing_party",
"is_author": True,
"delivery_method": "email",
}
],
"lang": "en",
"is_template": False,
}
r = requests.post(
f"{SCRIVE_BASE}/api/v2/documents",
json=doc_payload,
headers=scrive_headers,
timeout=30,
)
r.raise_for_status()
doc = r.json()
doc_id = doc["id"]
# Загружаем PDF шаблон
with open(CONTRACT_TEMPLATE_PATH, "rb") as pdf_file:
upload_r = requests.post(
f"{SCRIVE_BASE}/api/v2/documents/{doc_id}/files/main",
files={"file": ("contract.pdf", pdf_file, "application/pdf")},
headers={"Authorization": f"Bearer {SCRIVE_TOKEN}"},
timeout=60,
)
upload_r.raise_for_status()
# Запускаем процесс подписания
start_r = requests.post(
f"{SCRIVE_BASE}/api/v2/documents/{doc_id}/start",
headers=scrive_headers,
timeout=30,
)
start_r.raise_for_status()
return doc
def save_scrive_doc_to_kommo(lead_id: int, scrive_doc_id: str):
"""Сохраняем ID Scrive документа в кастомное поле сделки Kommo."""
url = f"https://{KOMMO_DOMAIN}/api/v4/leads"
headers = {
"Authorization": f"Bearer {KOMMO_TOKEN}",
"Content-Type": "application/json",
}
SCRIVE_DOC_FIELD_ID = int(os.environ.get("KOMMO_SCRIVE_DOC_FIELD_ID", 0))
payload = [{
"id": lead_id,
"custom_fields_values": [
{"field_id": SCRIVE_DOC_FIELD_ID, "values": [{"value": scrive_doc_id}]}
]
}]
requests.patch(url, json=payload, headers=headers, timeout=10)
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
"""Обрабатываем webhook Kommo при смене этапа."""
data = request.form
lead_id = int(data.get("leads[status][0][id]", 0))
new_status_id = int(data.get("leads[status][0][status_id]", 0))
if lead_id and new_status_id == CONTRACT_STAGE_ID:
# Сделка перешла на этап "Договор"
lead = get_lead_details(lead_id)
contacts = lead.get("_embedded", {}).get("contacts", [])
if contacts:
contact_id = contacts[0]["id"]
contact = get_contact_details(contact_id)
# Находим email контакта
signer_email = ""
signer_name = contact.get("name", "")
for cf in contact.get("custom_fields_values", []) or []:
if cf.get("field_code") == "EMAIL":
signer_email = cf["values"][0]["value"]
break
if signer_email:
doc_title = f"Договор - {lead.get('name', 'Сделка')} #{lead_id}"
doc = create_scrive_document(doc_title, signer_email, signer_name)
save_scrive_doc_to_kommo(lead_id, doc["id"])
return {"ok": True}
Шаг 3. Обработка webhook от Scrive (document.signed)
@app.route("/webhooks/scrive", methods=["POST"])
def scrive_webhook():
"""Обрабатываем уведомление Scrive о подписании документа."""
event = request.json
if event.get("event") != "document_signed":
return {"ok": True}
doc_id = event.get("document_id")
if not doc_id:
return {"ok": True}
# Находим сделку в Kommo по doc_id (кастомное поле)
lead_id = find_lead_by_scrive_doc_id(doc_id)
if not lead_id:
return {"ok": True}
# Скачиваем подписанный PDF
scrive_headers = {"Authorization": f"Bearer {SCRIVE_TOKEN}"}
pdf_r = requests.get(
f"{SCRIVE_BASE}/api/v2/documents/{doc_id}/files/sealed",
headers=scrive_headers,
timeout=60,
)
if pdf_r.ok:
# Прикрепляем PDF к сделке в Kommo
attach_pdf_to_lead(lead_id, pdf_r.content, f"contract_signed_{lead_id}.pdf")
# Меняем этап сделки на "Договор подписан"
update_lead_stage(lead_id, SIGNED_STAGE_ID)
return {"ok": True}
def attach_pdf_to_lead(lead_id: int, pdf_bytes: bytes, filename: str):
"""Прикрепляем PDF файл к сделке в Kommo."""
url = f"https://{KOMMO_DOMAIN}/api/v4/leads/{lead_id}/files"
headers = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
files = {"file": (filename, pdf_bytes, "application/pdf")}
requests.post(url, headers=headers, files=files, timeout=30)
Реальный кейс с цифрами
В типовом проекте для B2B-компании из DACH с циклом продаж 3-6 недель и 20-40 договорами в месяц интеграция Kommo + Scrive даёт следующий результат:
До интеграции: менеджер тратил 12-18 минут на цикл «подготовить договор -> отправить -> зафиксировать подписание». При 30 договорах в месяц - 6-9 часов ручной работы.
После интеграции: переход сделки на этап «Договор» автоматически запускает отправку в Scrive. После подписания PDF прикрепляется к сделке, этап меняется автоматически. Ручная работа - фактически нулевая.
Дополнительный эффект - трекинг статусов. Комmo показывает сколько договоров сейчас «на подписании» - отдельный этап воронки. Раньше эта информация была размыта между почтой и Scrive.
Для кого подходит
Интеграция актуальна для компаний, которые:
- Работают с EU-клиентами и которым важна юридическая сила подписи по eIDAS
- Используют Scrive из-за поддержки расширенной (AES) и квалифицированной (QES) электронной подписи для контрактов с высокими требованиями
- Имеют выделенный этап воронки «Договор» в Kommo и хотят автоматизировать переход
- Работают в Nordics или DACH, где Scrive имеет высокий уровень доверия у юридических служб
Если вы работаете с другими инструментами электронной подписи, логика интеграции аналогична - меняется только API.
Часто задаваемые вопросы
Нужно ли хранить Scrive Bearer Token в зашифрованном виде? Обязательно. Используйте secrets manager (AWS Secrets Manager, HashiCorp Vault) или как минимум переменные окружения без хранения в коде. Scrive токен даёт полный доступ к вашим документам.
Как настроить webhook от Scrive?
В Scrive Admin Panel -> Integrations -> Webhooks. Укажите URL вашего сервиса и выберите событие document_signed. Для верификации Scrive не использует HMAC - проверяйте IP-адрес источника (документированные IP Scrive) или ограничьте endpoint фаерволом.
Что делать, если PDF шаблон меняется при каждой сделке (нужно подставить имя клиента)?
Используйте библиотеку reportlab или pypdf для генерации PDF из шаблона с подстановкой данных перед загрузкой в Scrive. Либо используйте механизм Scrive Templates, который позволяет задавать placeholder-поля напрямую в API.
Можно ли добавить несколько подписантов?
Да. В массиве parties при создании документа добавьте несколько объектов с role: signing_party. Scrive поддерживает параллельное и последовательное подписание - задаётся через параметр signing_order.
Если вам нужна интеграция Kommo со Scrive - опишите ваш сценарий команде Exceltic.dev. Разберём архитектуру за одну встречу.