Когда сделка переходит в «Выиграна», Kommo отправляет webhook на ваш backend, backend вызывает POST /rest/api/3/issue Jira REST API v3 и возвращает ключ задачи (например, DEV-47) обратно в карточку Kommo. Всё это занимает около 3 секунд и не требует участия менеджера.
Это не про Zapier и не про Kommo Marketplace. Это про прямое подключение двух API с контролем над каждым полем - от ADF-описания задачи до кастомных полей Jira и идемпотентности при ретраях.
Компании, которые работают на Kommo и ведут разработку в Jira, часто сталкиваются с одним и тем же разрывом: продажи закрывают сделку и ждут. Разработчики не знают, что появился новый клиент, пока кто-то не напишет им вручную. В интеграционных проектах команды Exceltic.dev эта задержка стабильно составляет 1-2 рабочих дня, а при высокой загрузке продаж - и больше. В этой статье разбираем полную схему: webhook -> создание issue -> обратная запись key в CRM, включая обработку дублей.
Почему нативного решения нет
Kommo Marketplace содержит Jira-виджеты, но они решают другую задачу - отображение Jira-тикета в карточке. Создать issue с данными из нескольких полей сделки (сумма, контакт, кастомные поля) через эти виджеты нельзя. Двусторонней синхронизации нет - статус задачи в Jira не попадает обратно в Kommo.
Zapier поддерживает создание Jira-задачи при смене статуса в Kommo, но при объёме 20+ сделок в месяц стоимость и надёжность Zapier становятся проблемой: polling-модель Zapier задерживает обработку события на 5-15 минут и не гарантирует идемпотентность при ретраях. Для команд, у которых POST /rest/api/3/issue должен срабатывать ровно один раз - это неприемлемо.
Zapier - инструмент быстрого прототипирования, не производственной интеграции с гарантиями.
Что реализуется в кастомной интеграции
Webhook Kommo на переход в статус «Выиграна»
Kommo отправляет webhook при смене статуса сделки. Событие - leads.status, в payload передаётся id сделки, status_id (новый), old_status_id, pipeline_id, price. Тип события leads.status нужно зарегистрировать в Kommo: Settings -> Integrations -> Webhooks.
Идентификация «выигранной» сделки - по связке pipeline_id + status_id. В Kommo нет единого «won» статуса - у каждого пайплайна свои ID стадий. Получить нужный ID: Settings -> Pipelines -> нажать на стадию «Выиграна» -> в URL появится status_id. Либо через API: GET /api/v4/leads/pipelines - там все стадии с полями id и type (тип 142 = «Выиграна» в стандартных пайплайнах Kommo).
После получения webhook backend запрашивает полные данные сделки через GET /api/v4/leads/{id}?with=contacts,companies - так получаем контакт и кастомные поля, которые не входят в webhook payload.
Jira REST API v3: создание issue с данными из сделки
Аутентификация: Basic Auth - email пользователя Jira + API Token. API Token создаётся по адресу id.atlassian.com/manage-profile/security/api-tokens. Важно: токен привязан к пользователю, а не к проекту. Для интеграций используйте сервисный аккаунт, не личный.
Строка для Basic Auth: base64(email:api_token), передаётся в заголовке Authorization: Basic <encoded>.
Base URL: https://{your-site}.atlassian.net/rest/api/3/.
Минимальный payload для создания issue:
import requests
from requests.auth import HTTPBasicAuth
import base64
JIRA_URL = 'https://yourcompany.atlassian.net'
JIRA_AUTH = HTTPBasicAuth('[email protected]', 'your_api_token')
def create_jira_issue_from_deal(lead: dict, contact: dict) -> str:
"""
Создаёт Jira issue из данных сделки Kommo.
Возвращает ключ задачи, например 'DEV-47'.
"""
deal_amount = lead.get('price', 0)
contact_name = contact.get('name', 'Неизвестный контакт')
contact_email = get_contact_email(contact)
deal_name = lead.get('name', f'Сделка #{lead["id"]}')
# Описание в Atlassian Document Format (ADF) - обязательно для Jira Cloud
description_text = (
f'Клиент: {contact_name}\n'
f'Email: {contact_email}\n'
f'Сумма сделки: ${deal_amount}\n'
f'Kommo Deal ID: {lead["id"]}\n'
f'Менеджер: {lead.get("responsible_user_id")}'
)
payload = {
'fields': {
'project': {'key': 'DEV'}, # ключ проекта Jira
'issuetype': {'name': 'Task'}, # Task, Story, Bug, etc.
'summary': f'[CRM] {deal_name}',
'description': {
'type': 'doc',
'version': 1,
'content': [{
'type': 'paragraph',
'content': [{
'type': 'text',
'text': description_text
}]
}]
},
'priority': {'name': 'Medium'},
# кастомное поле для хранения Kommo Deal ID
# ID кастомного поля узнать через GET /rest/api/3/field
'customfield_10200': str(lead['id'])
}
}
resp = requests.post(
f'{JIRA_URL}/rest/api/3/issue',
auth=JIRA_AUTH,
json=payload
)
resp.raise_for_status()
return resp.json()['key'] # 'DEV-47'
Для получения ID кастомного поля под kommo_deal_id - один раз вызвать GET /rest/api/3/field и найти нужное поле в ответе. ID вида customfield_XXXXX. Это нужно для обратной трассировки: когда задача закрывается в Jira, нам нужно найти сделку в Kommo.
Обратная запись Jira issue key в Kommo
После создания задачи backend записывает ключ обратно в Kommo через PATCH /api/v4/leads/{id} - в кастомное поле jira_ticket_key. Затем добавляет Note: POST /api/v4/leads/{id}/notes. Менеджер видит ключ прямо в карточке без входа в Jira.
def write_jira_key_to_kommo(
deal_id: int,
jira_key: str,
jira_base_url: str,
kommo_access_token: str
) -> None:
headers = {'Authorization': f'Bearer {kommo_access_token}'}
jira_url = f'{jira_base_url}/browse/{jira_key}'
# Записать ключ в кастомное поле Kommo
requests.patch(
f'https://yourcommo.kommo.com/api/v4/leads/{deal_id}',
headers=headers,
json={'custom_fields_values': [{
'field_id': JIRA_KEY_FIELD_ID,
'values': [{'value': jira_key}]
}]}
)
# Добавить заметку в карточку
requests.post(
f'https://yourcommo.kommo.com/api/v4/leads/{deal_id}/notes',
headers=headers,
json=[{'note_type': 4, 'params': {
'text': f'Создана задача в Jira: {jira_key} - {jira_url}'
}}]
)
Идемпотентность: защита от дублей
Webhook Kommo может прийти дважды - при нестабильном соединении или при повторной смене статуса. Без защиты каждый webhook создаст новую задачу в Jira.
Решение - хранить маппинг kommo_deal_id -> jira_issue_key в Redis или PostgreSQL. Перед вызовом POST /rest/api/3/issue проверять: если для данного deal_id уже есть ключ - пропустить создание, вернуть существующий ключ. Это стандартный паттерн идемпотентности для webhook-обработчиков.
def handle_kommo_webhook(payload: dict) -> None:
lead_data = payload.get('leads', {}).get('status', [])
if not lead_data:
return
lead = lead_data[0]
deal_id = int(lead['id'])
pipeline_id = int(lead.get('pipeline_id', 0))
status_id = int(lead.get('status_id', 0))
# Проверить что это именно Won-стадия нужного пайплайна
if not is_won_status(pipeline_id, status_id):
return
# Идемпотентность: проверить существующий ключ
existing_key = get_jira_key_for_deal(deal_id) # из Redis/БД
if existing_key:
return # дубль, пропускаем
# Получить полные данные сделки
full_lead, contact = fetch_lead_with_contact(deal_id)
# Создать issue в Jira
jira_key = create_jira_issue_from_deal(full_lead, contact)
# Сохранить маппинг
save_jira_key_for_deal(deal_id, jira_key)
# Записать результат в Kommo
write_jira_key_to_kommo(deal_id, jira_key, JIRA_URL, KOMMO_TOKEN)
Пошаговая схема
- Сделка переходит в стадию «Выиграна» в Kommo
- Kommo отправляет POST на ваш endpoint с событием
leads.status - Backend проверяет
pipeline_id+status_id- это Won? - Проверка идемпотентности: есть уже созданная задача для этого deal_id?
- Если нет -
GET /api/v4/leads/{id}?with=contactsдля получения полных данных POST /rest/api/3/issueв Jira с ADF-описанием и кастомными полями- Jira возвращает
key(например,DEV-47) - Сохранить маппинг
deal_id -> DEV-47в хранилище PATCH /api/v4/leads/{id}- записать ключ в кастомное поле KommoPOST /api/v4/leads/{id}/notes- Note менеджеру: «Создана задача DEV-47»- Webhook от Jira при закрытии задачи (Done) -> Note в Kommo: «Задача DEV-47 закрыта»
Реальный кейс с цифрами
B2B SaaS компания (Европа, 25-35 новых клиентов в месяц): команда продаж в Kommo, команда разработки и CS в Jira. Задержка передачи клиента после Won составляла в среднем 1.5 дня - менеджер закрывал сделку, писал письмо или Slack-сообщение, разработчик создавал тикет вручную с той информацией, которую успевал собрать.
После внедрения кастомной интеграции:
- Время от Won до появления задачи в Jira: под 10 секунд (включая webhook delivery)
- 0 задач с пустым описанием - контакт, email, сумма, plan заполняются автоматически из полей сделки
- Менеджер видит статус задачи (In Progress / Done) прямо в карточке Kommo через обратный webhook
- Экономия: около 20 минут в расчёте на одну сделку (ручное создание + поиск информации + уточнения)
При 30 сделках в месяц это около 10 часов в месяц - только на передаче контекста между командами. Плюс устранение ошибок из-за неполной информации в задачах.
Для сравнения - у команды Exceltic.dev также была интеграция Kommo с ClickUp для другого клиента, где логика аналогична, но REST API ClickUp проще - нет ADF-формата описания.
Для кого актуально
Эта интеграция нужна, если:
- Продажи ведёте в Kommo, задачи разработки / CS / внедрения - в Jira
- После Won клиент требует технического онбординга, разработки или настройки - и это фиксируется задачей
- 15+ передач клиентов в месяц - ручное создание тикетов занимает ощутимое время
- Нужна двусторонняя связь: менеджер должен видеть статус Jira-задачи прямо в CRM
Zapier-вариант не подходит, если у вас строгие требования к идемпотентности или объём достаточен чтобы оправдать кастомную разработку.
Подробнее о том, как вообще строить интеграции и разработку под Kommo - в отдельном разделе.
Термин: Atlassian Document Format (ADF) - JSON-структура для описания rich text в Jira Cloud. В отличие от Jira Server/Data Center, где description принимает plaintext, Jira Cloud требует ADF-документ с явным type: doc, version: 1 и деревом content. Без правильного формата POST /rest/api/3/issue вернёт 400 Bad Request.
Часто задаваемые вопросы
Чем кастомная интеграция лучше Zapier для Kommo -> Jira?
Zapier работает по polling-модели с интервалом 5-15 минут, не гарантирует идемпотентность при сбоях и не умеет заполнять Jira custom fields из нескольких полей сделки одновременно. Кастомный webhook-обработчик реагирует на событие в реальном времени, поддерживает идемпотентность через хранилище и дает полный контроль над структурой issue - включая ADF-описание, labels, priority и кастомные поля.
Как Kommo передаёт данные о выигранной сделке?
Kommo отправляет POST-запрос с событием leads.status в payload. Поля в webhook payload: id (deal ID), status_id (новый статус), old_status_id, pipeline_id, price. Контакты и кастомные поля в webhook не входят - их нужно запрашивать отдельно через GET /api/v4/leads/{id}?with=contacts. Стадия «Выиграна» идентифицируется по связке pipeline_id + status_id, или через type: 142 в ответе GET /api/v4/leads/pipelines.
Нужен ли OAuth для Jira API или достаточно Basic Auth?
Для серверной интеграции без участия пользователя - достаточно Basic Auth с email и API Token. API Token создаётся по адресу id.atlassian.com/manage-profile/security/api-tokens. OAuth 2.0 нужен только для публичных приложений, где каждый пользователь авторизует доступ от своего имени. По состоянию на 2026 год Atlassian планировал ввести истечение срока действия API токенов - проверяйте актуальную политику в документации Atlassian.
Что такое ADF и зачем он нужен в Jira Cloud?
ADF (Atlassian Document Format) - обязательный формат для поля description в Jira Cloud REST API v3. Минимальная структура: {"type": "doc", "version": 1, "content": [{"type": "paragraph", "content": [{"type": "text", "text": "текст"}]}]}. Если передать plain string - API вернёт 400. В Jira Server/Data Center (не cloud) description принимает plain text или wiki-markup - это другое API.
Как избежать дублей при повторных webhook от Kommo?
Hранить маппинг kommo_deal_id -> jira_issue_key в Redis или PostgreSQL. В начале обработки каждого webhook проверять: если запись уже есть - пропустить создание задачи. Это стандартный паттерн идемпотентности. Дополнительно: Kommo может прислать webhook повторно при сетевой ошибке (ответ не 200 в течение 2 секунд) - поэтому endpoint должен возвращать 200 даже при пропуске дубля.
Что если нам нужна интеграция с Kommo и другими трекерами задач?
Логика идентична для большинства task-трекеров: webhook Kommo на Won -> вызов API трекера -> обратная запись ID задачи в CRM. Разница только в деталях API: ClickUp использует REST с простым JSON-телом, Linear - GraphQL с мутациями. Jira отличается обязательным ADF-форматом описания и необходимостью хранить custom field ID для трассировки.
Итого
- Kommo webhook
leads.status+ проверкаpipeline_id+status_id- надёжная идентификация Won - Jira REST API v3: Basic Auth (email + API Token),
POST /rest/api/3/issueс обязательным ADF-описанием - Идемпотентность через хранилище
deal_id -> issue_key- защита от дублей при ретраях - Обратная запись
issue_keyв Kommo черезPATCH /leads/{id}и Note - менеджер видит статус задачи без Jira - Типовой срок разработки: 1-2 недели с учётом конфигурации маппинга полей
Если у вас Kommo и Jira и передача клиентов происходит вручную - опишите вашу структуру: какие проекты Jira, какие поля сделки нужны в задаче. Команда Exceltic.dev разберёт архитектуру и оценит объём работ.