Kommo + Hive: автоматическое создание проекта онбординга при закрытии сделки

Hive - инструмент управления проектами с REST API для создания проектов и задач программно. Для компаний, которые продают через Kommo, а реализуют через Hive, интеграция закрывает типовой разрыв: сделка выиграна в CRM, но project manager вручную создаёт проект онбординга с нуля. При 10+ новых клиентах в месяц это становится систематической потерей времени.

Hive API использует api_key как query-параметр (не Bearer token). Основные эндпоинты: POST /workspaces/{workspaceId}/projects - создать проект, POST /workspaces/{workspaceId}/actions - создать задачу (в Hive задача называется “action”). Workspace ID и User ID для assignee берутся из настроек Hive.

Hive - project management платформа с аналитикой, time tracking и portfolio-режимом. Популярна в агентствах и командах от 10 человек, которые ведут несколько клиентских проектов параллельно. В отличие от Asana и ClickUp - имеет встроенную portfolio-аналитику и resource management из коробки.

В чём проблема без интеграции

Когда сделка закрывается в Kommo, project manager получает уведомление в Slack или email. Он открывает Hive, создаёт проект, добавляет 5-8 стандартных задач онбординга, назначает ответственных и проставляет дедлайны. На это уходит 20-30 минут. Умножьте на 15 новых клиентов в месяц - и это 5-8 часов рутины.

Стандартные шаблоны проектов в Hive не привязаны к CRM: название берётся из руки, данные клиента копируются вручную, дедлайны рассчитываются заново каждый раз.

Архитектура

Kommo: сделка -> Closed Won
  -> Kommo webhook leads.status.changed
  -> Ваш сервер

Ваш сервер:
  -> GET Kommo: название сделки, контакт, email, сумма
  -> POST /workspaces/{id}/projects -> projectId
  -> POST /workspaces/{id}/actions (x5) -> создать задачи онбординга
  -> Kommo: note "Hive проект создан: #{projectId}"

Реализация

import requests, os
from datetime import datetime, timedelta
from flask import Flask, request, jsonify

app = Flask(__name__)

HIVE_API_KEY     = os.environ["HIVE_API_KEY"]
HIVE_WORKSPACE   = os.environ["HIVE_WORKSPACE_ID"]
HIVE_BASE        = "https://app.hive.com/api/v1"
HIVE_PM_USER_ID  = os.environ["HIVE_PM_USER_ID"]  # ID PM в Hive

KOMMO_SUBDOMAIN  = os.environ["KOMMO_SUBDOMAIN"]
KOMMO_TOKEN      = os.environ["KOMMO_ACCESS_TOKEN"]
CLOSED_WON_ID    = int(os.environ["KOMMO_CLOSED_WON_ID"])

KOMMO_BASE = f"https://{KOMMO_SUBDOMAIN}.kommo.com/api/v4"
KOMMO_HDR  = {"Authorization": f"Bearer {KOMMO_TOKEN}",
              "Content-Type": "application/json"}

def hive_params():
    return {"api_key": HIVE_API_KEY}

def create_project(name: str, description: str) -> str:
    r = requests.post(
        f"{HIVE_BASE}/workspaces/{HIVE_WORKSPACE}/projects",
        params=hive_params(),
        json={
            "name":        name,
            "description": description,
        },
    )
    r.raise_for_status()
    return r.json()["id"]

def create_action(title: str, project_id: str,
                  due_days: int = 7) -> str:
    due_date = (datetime.now() + timedelta(days=due_days)).strftime("%Y-%m-%d")
    r = requests.post(
        f"{HIVE_BASE}/workspaces/{HIVE_WORKSPACE}/actions",
        params=hive_params(),
        json={
            "title":      title,
            "projectId":  project_id,
            "assigneeId": HIVE_PM_USER_ID,
            "dueDate":    due_date,
            "status":     "NOT_STARTED",
        },
    )
    r.raise_for_status()
    return r.json()["id"]

def get_lead_contact(lead_id: int) -> tuple:
    r = requests.get(
        f"{KOMMO_BASE}/leads/{lead_id}",
        headers=KOMMO_HDR,
        params={"with": "contacts"},
    )
    lead = r.json()
    contacts = lead.get("_embedded", {}).get("contacts", [])
    contact = {}
    if contacts:
        rc = requests.get(
            f"{KOMMO_BASE}/contacts/{contacts[0]['id']}",
            headers=KOMMO_HDR,
            params={"with": "custom_fields_values"},
        )
        contact = rc.json()
    return lead, contact

def get_email(contact: dict) -> str:
    for cf in contact.get("custom_fields_values", []) or []:
        if cf.get("field_code") == "EMAIL":
            vals = cf.get("values", [])
            return vals[0].get("value", "") if vals else ""
    return ""

def add_note(lead_id: int, text: str):
    requests.post(
        f"{KOMMO_BASE}/notes",
        headers=KOMMO_HDR,
        json=[{"entity_id": lead_id, "entity_type": "leads",
               "note_type": "common", "params": {"text": text}}],
    )

ONBOARDING_TASKS = [
    ("Отправить приветственное письмо клиенту", 1),
    ("Провести kickoff-звонок", 3),
    ("Настроить доступ к продукту / предоставить credentials", 5),
    ("Онбординг-сессия: обзор ключевых функций", 7),
    ("Проверить первый результат работы клиента", 14),
    ("Запросить отзыв по итогам 30 дней", 30),
]

@app.route("/webhooks/kommo", methods=["POST"])
def kommo_webhook():
    data = request.json or {}
    for lead_data in data.get("leads", {}).get("status", []):
        lead_id    = lead_data.get("id")
        new_status = lead_data.get("status_id")
        if new_status != CLOSED_WON_ID:
            continue

        lead, contact = get_lead_contact(lead_id)
        deal_name   = lead.get("name", f"Deal #{lead_id}")
        contact_name = contact.get("name", "")
        email        = get_email(contact)
        amount       = lead.get("price", 0)

        project_name = f"Onboarding: {contact_name or deal_name}"
        description  = (
            f"Deal: {deal_name}\n"
            f"Contact: {contact_name} ({email})\n"
            f"Amount: {amount}\n"
            f"Kommo Deal ID: {lead_id}"
        )

        project_id = create_project(project_name, description)

        action_ids = []
        for task_title, due_days in ONBOARDING_TASKS:
            action_id = create_action(task_title, project_id, due_days)
            action_ids.append(action_id)

        add_note(
            lead_id,
            f"Hive проект создан: {project_name}\n"
            f"Project ID: {project_id}\n"
            f"Создано {len(action_ids)} задач онбординга."
        )

    return jsonify({"status": "ok"}), 200

Получение Workspace ID и User ID

# Workspace ID:
r = requests.get(
    f"{HIVE_BASE}/workspaces",
    params={"api_key": HIVE_API_KEY},
)
workspaces = r.json()
# [{"id": "ws_xxx", "name": "My Company", ...}, ...]

# User ID (PM для назначения задач):
r = requests.get(
    f"{HIVE_BASE}/workspaces/{HIVE_WORKSPACE}/users",
    params={"api_key": HIVE_API_KEY},
)
users = r.json()
# [{"id": "usr_xxx", "email": "pm@company.com", ...}, ...]

Запустите один раз локально и сохраните нужные ID в переменные окружения.

Кастомизация шаблона задач

Список ONBOARDING_TASKS - это шаблон. Для разных типов сделок можно использовать разные шаблоны:

TEMPLATES = {
    "saas":       [...],  # SaaS onboarding
    "consulting": [...],  # Consulting project
    "agency":     [...],  # Agency deliverables
}

def get_template(lead: dict) -> list:
    # Определяем тип по кастомному полю сделки или названию воронки
    pipeline_id = lead.get("pipeline_id", 0)
    if pipeline_id == int(os.environ.get("SAAS_PIPELINE_ID", "0")):
        return TEMPLATES["saas"]
    return TEMPLATES["consulting"]

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

Агентства, консалтинговые компании и B2B SaaS, где после выигрыша сделки начинается структурированный процесс реализации. Особенно актуально для команд от 10 человек, где PM и sales - разные роли, и передача информации о новом клиенте занимает отдельное время. Hive популярен в компаниях, где нужен portfolio-режим: видеть все активные onboarding-проекты в одном месте с timeline.

Другие task-интеграции: Kommo + Shortcut (engineering tasks), Kommo + Fibery (linked projects), Kommo + Linear (dev tasks).

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

Поддерживает ли Hive API вложенные задачи (subtasks)?

Да. После создания action, создайте subaction: POST /workspaces/{id}/actions/{actionId}/subactions с аналогичными полями. Глубина вложенности - 1 уровень (action -> subaction).

Как назначить разных исполнителей на разные задачи?

Передавайте разный assigneeId для каждого create_action вызова. Список пользователей workspace: GET /workspaces/{id}/users. Можно хранить mapping должность -> userId в конфигурации и назначать автоматически.

Есть ли у Hive webhook’и для уведомления Kommo о завершении проекта?

Hive поддерживает базовые интеграции через Zapier/Make, но нативного webhook API для кастомных событий нет. Для мониторинга статуса проекта - периодический polling: GET /workspaces/{id}/projects/{projectId} и проверка статуса.

Можно ли создавать проекты из шаблонов Hive через API?

На момент Q2 2026 Hive API не поддерживает создание проектов из шаблонов напрямую. Обходной путь: хранить список задач шаблона в своём коде и создавать их через API, как показано выше.

Итог

Kommo + Hive - автоматический onboarding project при Closed Won:

  • api_key query-параметр (не Bearer token)
  • POST /workspaces/{id}/projects -> projectId
  • POST /workspaces/{id}/actions с dueDate, assigneeId, status
  • Шаблон задач в коде: разные задачи для разных типов сделок
  • Workspace ID и User ID - получить один раз через API, сохранить в env

Если ваша команда хочет автоматизировать передачу данных из Kommo в Hive - опишите задачу команде Exceltic.dev.

Ещё статьи

Все →