Todoist - популярный менеджер задач с REST API v2, используемый sales-специалистами для личного планирования. Kommo - CRM с воронкой продаж. Без интеграции задачи из Kommo не попадают в Todoist, а личные задачи менеджеров никак не связаны с карточками сделок. С интеграцией: при закрытии сделки автоматически создаётся набор задач онбординга в Todoist, при завершении задачи в Todoist - отметка в Kommo.
Todoist особенно популярен у менеджеров, работающих с мобильного устройства: iOS и Android приложения мгновенно синхронизируются, push-уведомления надёжные. Для B2B команд с циклом продаж 2-6 недель Todoist как персональный task manager дополняет Kommo: крупные задачи в CRM, ежедневный список дел - в Todoist.
Todoist REST API v2 - JSON API с Bearer token аутентификацией. Создание задач: POST /tasks, чтение: GET /tasks, завершение: POST /tasks/{task_id}/close. Webhook-события отправляются при создании, обновлении и завершении задач.
Архитектура интеграции
Kommo: сделка status_id = 142 (Выиграна)
-> POST /api/v1/tasks (Todoist)
Onboarding tasks for client X
Todoist: task completed
-> POST /your-server/webhooks/todoist
{event_name: item:completed, item: {id, content}}
-> Kommo: POST /api/v4/leads/{id}/notes {text: "Todoist: завершено - task name"}
Реализация: создание задач онбординга при победе в сделке
import requests, os, hmac, hashlib
from flask import Flask, request, jsonify
app = Flask(__name__)
KOMMO_DOMAIN = os.environ["KOMMO_DOMAIN"]
KOMMO_TOKEN = os.environ["KOMMO_TOKEN"]
TODOIST_TOKEN = os.environ["TODOIST_API_TOKEN"]
TODOIST_SECRET = os.environ["TODOIST_CLIENT_SECRET"] # для webhook верификации
KOMMO_BASE = f"https://{KOMMO_DOMAIN}/api/v4"
KOMMO_HDR = {"Authorization": f"Bearer {KOMMO_TOKEN}"}
TD_BASE = "https://api.todoist.com/rest/v2"
TD_HDR = {"Authorization": f"Bearer {TODOIST_TOKEN}"}
KOMMO_WON_STATUS = 142
# Шаблон задач онбординга после закрытия сделки
ONBOARDING_TASKS = [
("Отправить приветственное письмо клиенту", 1, 0), # (title, priority, offset_days)
("Запланировать kickoff-встречу", 2, 0),
("Настроить доступы и onboarding-ресурсы", 2, 1),
("Первый check-in с клиентом (конец 1-й недели)", 1, 7),
("Review по итогам первого месяца", 1, 30),
]
@app.route("/webhooks/kommo", methods=["POST"])
def kommo_event():
import time
data = request.json or {}
for lead in data.get("leads", {}).get("status", []):
if lead.get("status_id") == KOMMO_WON_STATUS:
create_onboarding_tasks(lead["id"])
return "ok", 200
def get_lead_info(lead_id: int) -> dict:
r = requests.get(f"{KOMMO_BASE}/leads/{lead_id}", headers=KOMMO_HDR, params={"with": "contacts"})
return r.json() if r.ok else {}
def create_todoist_project(name: str) -> str | None:
r = requests.post(
f"{TD_BASE}/projects",
headers=TD_HDR,
json={"name": name},
)
return r.json().get("id") if r.ok else None
def create_onboarding_tasks(lead_id: int):
from datetime import date, timedelta
lead = get_lead_info(lead_id)
client = lead.get("name", f"Lead {lead_id}")
# Создать проект под клиента
project_id = create_todoist_project(f"Onboarding: {client}")
today = date.today()
for title, priority, offset_days in ONBOARDING_TASKS:
due_date = today + timedelta(days=offset_days)
payload = {
"content": f"{title} - {client}",
"priority": priority, # 1=normal, 2=high, 3=urgent, 4=very urgent
"due_string": due_date.strftime("%Y-%m-%d"),
"description": f"Kommo Lead ID: {lead_id}",
}
if project_id:
payload["project_id"] = project_id
requests.post(f"{TD_BASE}/tasks", headers=TD_HDR, json=payload)
# Заметка в Kommo
requests.post(
f"{KOMMO_BASE}/leads/{lead_id}/notes",
headers=KOMMO_HDR,
json=[{"note_type": "common", "params": {"text": f"Todoist: создано {len(ONBOARDING_TASKS)} задач онбординга для {client}"}}],
)
Реализация: Todoist webhook -> Kommo
Todoist отправляет webhook-события через App Console (Apps -> Your App -> Webhooks). Верификация через HMAC-SHA256:
@app.route("/webhooks/todoist", methods=["POST"])
def todoist_event():
# Верификация подписи
user_agent = request.headers.get("X-Todoist-Hmac-SHA256", "")
raw_body = request.data
computed = hmac.new(
TODOIST_SECRET.encode(), raw_body, hashlib.sha256
).digest()
import base64
computed_b64 = base64.b64encode(computed).decode()
if not hmac.compare_digest(computed_b64, user_agent):
return "unauthorized", 401
data = request.json or {}
event_name = data.get("event_name", "")
item = data.get("event_data", {})
if event_name == "item:completed":
task_title = item.get("content", "")
task_id = item.get("id", "")
description = item.get("description", "")
# В description хранили Kommo Lead ID: "Kommo Lead ID: 123456"
lead_id = extract_lead_id_from_description(description)
if lead_id:
requests.post(
f"{KOMMO_BASE}/leads/{lead_id}/notes",
headers=KOMMO_HDR,
json=[{"note_type": "common", "params": {
"text": f"Todoist: завершено - {task_title}"
}}],
)
return "ok", 200
def extract_lead_id_from_description(description: str) -> int | None:
prefix = "Kommo Lead ID: "
if prefix in description:
try:
return int(description.split(prefix)[1].strip().split()[0])
except (ValueError, IndexError):
return None
return None
Дополнительные сценарии
Задача в Todoist при любой смене статуса (не только Won):
Настройте маппинг стадий на задачи:
- “КП отправлено” -> задача “Follow up через 3 дня” (due: +3 дня)
- “Счёт выставлен” -> задача “Контроль оплаты” (due: +5 дней)
- “Потеря сделки” -> задача “Анализ причины проигрыша”
Синхронизация статусов задач Kommo -> Todoist:
При создании задачи в Kommo через API - также создать зеркальную задачу в Todoist. Для этого нужно подписаться на task webhook-события Kommo.
Реальный кейс
IT-интегратор, команда 5 менеджеров. До интеграции: менеджеры вручную создавали задачи в Todoist после каждой выигранной сделки - 8-10 минут на сделку при 10-15 победах в месяц. После интеграции: автоматически создаётся 5 задач онбординга с датами, привязанными к дате закрытия. Менеджер видит задачу в Todoist мгновенно без переключения интерфейсов.
Для кого актуально
Менеджеры по продажам, активно использующие Todoist как персональный инструмент планирования. Компании с чётким онбординг-процессом после закрытия сделки.
Альтернативный подход - создание задач в ClickUp описан в Kommo + ClickUp: задачи и лиды без Zapier.
Часто задаваемые вопросы
Можно ли создавать задачи в разделах (Sections) проекта?
Да. Сначала создайте секции через POST /sections с project_id, затем при создании задачи указывайте section_id. Для онбординга можно создавать секции: “Неделя 1”, “Неделя 2”, “Месяц 1”.
Как избежать дублирования задач если webhook сработал дважды?
Добавьте идемпотентный ключ: перед созданием задач проверьте через GET /tasks?filter=#{lead_id} (если вы используете label с lead_id). Или храните список уже обработанных lead_id в кэше (Redis) с TTL 24h.
Todoist бесплатный план поддерживает webhook?
Webhook-события в Todoist доступны только через OAuth App в Todoist App Console - это требует создания приложения в Todoist, что бесплатно. Personal Access Token для API работает на всех планах.
Итог
Kommo + Todoist:
- Kommo Won event -> создать проект + набор задач с датами в Todoist
- В description задачи -
Kommo Lead ID: {id}для обратной связи - Todoist
item:completedwebhook -> заметка в Kommo - HMAC-SHA256 верификация через
X-Todoist-Hmac-SHA256(base64-encoded)
Если нужна интеграция Kommo с Todoist под ваш onboarding-процесс - опишите задачу команде Exceltic.dev.