Интеграция Jira и n8n: создание issue, webhooks, JQL-поиск и защита от дублей ¶
Обновлено: 2026-05-30
Импортируйте JSON в n8n, замените credentials, URL API, project/list IDs, поля и лимиты под вашу инфраструктуру.
Проблема: Jira требует строгих project key, issue type, transitions и custom fields. Если отправлять в неё сырые события из CRM, мониторинга или формы, команда получает дубли, неправильные статусы и задачи без воспроизводимого контекста.
Решение: Используйте n8n как issue router: валидируйте project и issue type, собирайте summary/description, ищите дубль через JQL/external_id и применяйте transitions только по разрешённым правилам.
Проблема: почему простая интеграция создаёт дубли и ручной хаос ¶
Jira часто принимает события из мониторинга, поддержки, релизов и клиентских форм. Но простой HTTP Request к create issue не решает главную задачу: инженеру нужен воспроизводимый контекст, severity, environment, owner, ссылка на исходное событие и история повторов.
Без JQL-поиска и external_id один инцидент может создать десятки issues. Без контроля transitions автоматизация переводит задачу в статус, который недоступен для текущего workflow. Поэтому integration layer должен быть строгим и предсказуемым.
Архитектура workflow для n8n ¶
| Блок | Задача | Production-проверка |
|---|---|---|
| Webhook issue event | принимает incident, bug report или support escalation | source, entity_id, severity |
| Validate Jira mapping | проверяет project key, issue type и fields | нет случайного project |
| Build issue payload | собирает summary, description и labels | ADF/plain text, environment, source_url |
| Find duplicate via JQL | ищет issue по external_id/labels | до create issue |
| Create/update issue | создаёт issue или добавляет comment | allowed transitions |
| Respond and alert | возвращает статус и ссылку | issue_key, DLQ, owner |
Для инцидентов лучше обновлять existing issue и добавлять комментарий с новым событием, чем создавать отдельный issue на каждый alert.
Контракт входных данных ¶
{
"source": "monitoring",
"event_type": "api_error_rate_high",
"entity_id": "incident-2026-05-30-1042",
"project_key": "OPS",
"issue_type": "Bug",
"summary": "Высокий процент ошибок API оплаты",
"description": "5xx > 8% за 10 минут на payment API",
"severity": "critical",
"environment": "production",
"service": "payment-api",
"source_url": "https://monitoring.example.ru/incidents/1042"
}project_key и issue_type должны приходить из allowlist, а не из произвольной формы. Это защищает Jira от задач в неправильном проекте.
Code Node: нормализация, mapping и guard-условия ¶
const src = $json.body ?? $json;
const allowedProjects = ['OPS', 'WEB', 'CRM'];
const projectKey = String(src.project_key ?? 'OPS').trim().toUpperCase();
if (!allowedProjects.includes(projectKey)) throw new Error(`Project is not allowed: ${projectKey}`);
const issueType = String(src.issue_type ?? 'Task').trim();
const allowedTypes = ['Bug', 'Task', 'Incident'];
if (!allowedTypes.includes(issueType)) throw new Error(`Issue type is not allowed: ${issueType}`);
const entityId = String(src.entity_id ?? '').trim();
if (!entityId) throw new Error('No entity_id for Jira issue');
const severity = String(src.severity ?? 'medium').toLowerCase();
const externalId = `jira-router:${src.source ?? 'external'}:${entityId}`;
const summary = String(src.summary ?? src.title ?? 'External event').trim().slice(0, 180);
const description = [String(src.description ?? '').trim(), '', `Source: ${src.source ?? 'external'}`, `Entity: ${entityId}`, `Service: ${src.service ?? 'n/a'}`, `Environment: ${src.environment ?? 'n/a'}`, `URL: ${src.source_url ?? ''}`].join('\n');
const jql = `project = ${projectKey} AND labels = "external-sync" AND text ~ "${externalId}" ORDER BY created DESC`;
return [{ json: { external_id: externalId, jql, issue: { fields: { project: { key: projectKey }, issuetype: { name: issueType }, summary, description, labels: ['external-sync', `severity-${severity}`] } }, comment: `Repeated event for ${externalId}`, allowed_transition: severity === 'critical' ? 'Escalate' : 'Triage' }}];
Почему JQL-поиск нужен до create issue
Jira не знает ваш внешний incident_id. Если не искать существующий issue по external_id, повтор webhook создаст новый ticket и размажет историю инцидента по нескольким задачам.
Готовый workflow JSON: скачать и импортировать ¶
Скачать готовый workflow JSON Скачать тестовый payload
{
"name": "Nodbot - Jira issue router with JQL dedupe",
"nodes": [
{
"name": "Webhook issue input",
"type": "n8n-nodes-base.webhook",
"purpose": "Принять событие"
},
{
"name": "Validate and build Jira issue",
"type": "n8n-nodes-base.code",
"purpose": "Проверить mapping и собрать payload"
},
{
"name": "Find duplicate via JQL",
"type": "n8n-nodes-base.httpRequest",
"purpose": "Найти существующий issue"
},
{
"name": "Create or update issue",
"type": "n8n-nodes-base.httpRequest",
"purpose": "Создать issue или comment"
},
{
"name": "Apply safe transition",
"type": "n8n-nodes-base.httpRequest",
"purpose": "Выполнить разрешённый transition"
},
{
"name": "Respond",
"type": "n8n-nodes-base.respondToWebhook",
"purpose": "Вернуть issue key"
}
],
"connections": "Webhook issue input → Validate and build Jira issue → Find duplicate via JQL → Create or update issue → Apply safe transition → Respond"
}
Пошаговая настройка связки ¶
- Опишите allowlist project_key и issue_type.
- Создайте labels/custom fields для external_id, severity и source.
- Импортируйте workflow JSON и замените Jira base URL, email/API token или OAuth.
- Настройте JQL-поиск дублей до create issue.
- Проверьте transitions на тестовом project workflow.
Тесты перед production ¶
curl -X POST "https://YOUR-N8N-DOMAIN/webhook/integration-jira-n8n-issue-router" \
-H "Content-Type: application/json" \
--data @integration-jira-n8n-issue-router-payload.json- Повтор entity_id добавляет комментарий к existing issue.
- Недопустимый project_key останавливается до API-запроса.
- Critical severity попадает в правильный label/transition.
- JQL не ломается на специальных символах во внешнем ID.
- Ошибка Jira API уходит в DLQ с payload без токенов.
Production-риски ¶
- Project key приходит из формы. Пользователь может создать issue не в том проекте.
- Нет JQL-дедупликации. Один инцидент создаёт много tickets.
- Transitions вызываются без проверки. Jira вернёт ошибку или переведёт задачу не туда.
- Описание без контекста. Инженер не видит service, environment и source_url.
- Секреты в comment. Stack trace может содержать токены.
Полезные ссылки и смежные материалы ¶
- Jira Cloud REST API
- Jira Cloud Webhooks
- n8n Jira node
- Slack incident routing
- Webhook signature validation
Критерии готовности ¶
- Project key и issue type проходят allowlist.
- JQL-поиск дублей выполняется до create issue.
- Summary короткий, а description содержит source_url, service и environment.
- Transitions выполняются только по разрешённым правилам.
- Ошибки Jira API логируются и попадают в alert/DLQ.
Nodbot настроит Jira + n8n: issue router, JQL-дедупликацию, transitions, labels/custom fields, Slack-алерты и безопасный DLQ.
Обсудить Jira-интеграцию