{
  "name": "Jira issue → Vouli IQ incident",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "jira-to-vouli-incident",
        "authentication": "headerAuth",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "b2c3d4e5-0001-4000-8000-000000000001",
      "name": "Jira issue webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        300
      ],
      "webhookId": "b2c3d4e5-0001-4000-8000-0000000000aa",
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_WITH_INBOUND_HEADER_AUTH_CREDENTIAL",
          "name": "Jira → n8n shared header"
        }
      }
    },
    {
      "parameters": {
        "mode": "runOnceForAllItems",
        "jsCode": "// Jira issue → Vouli IQ incident (POST /api/v1/incidents).\n//\n// Input: the Webhook node's item, { headers, body } where body is a Jira\n// \"issue created\" webhook (Jira system webhook or an Automation rule's\n// \"Send web request\" with the issue payload).\n// Output: { skip, body, idempotencyKey }.\n//   body           — only fields the API's createIncident accepts (strict:\n//                    any other field is refused with 400 unknown_field).\n//   idempotencyKey — stable across Jira's retries of the SAME delivery\n//                    (X-Atlassian-Webhook-Identifier), so a retry is answered\n//                    with the first response instead of a second incident.\nconst item = $input.first().json;\nconst headers = item.headers || {};\nconst payload = item.body || {};\nconst issue = payload.issue || {};\nconst fields = issue.fields || {};\n\nif (payload.webhookEvent !== 'jira:issue_created' || !issue.key) {\n  return [{ json: { skip: true, reason: `ignored event ${payload.webhookEvent || 'unknown'}` } }];\n}\n\n// Jira Cloud may send the description as text or as an Atlassian Document.\nfunction adfText(node) {\n  if (!node) return '';\n  if (typeof node === 'string') return node;\n  if (node.type === 'text') return node.text || '';\n  const inner = (node.content || []).map(adfText).join(node.type === 'doc' ? '\\n' : '');\n  return inner;\n}\n\nconst SEVERITY = { highest: 'critical', blocker: 'critical', critical: 'critical', high: 'high', major: 'high', medium: 'medium', low: 'low', lowest: 'low', minor: 'low', trivial: 'low' };\nconst priority = String((fields.priority && fields.priority.name) || '').toLowerCase();\nconst clip = (s, n) => (s.length > n ? s.slice(0, n - 1) + '…' : s);\n\nconst body = {\n  title: clip(`${issue.key}: ${fields.summary || 'Jira issue'}`, 300),\n  incident_type: 'other',\n  severity: SEVERITY[priority] || 'medium',\n};\nconst description = adfText(fields.description).trim();\nif (description) body.description = clip(description, 8000);\nconst components = (fields.components || []).map((c) => c && c.name).filter(Boolean).join(', ');\nif (components) body.affected_systems = clip(components, 2000);\nif (fields.assignee && fields.assignee.displayName) body.owner = clip(fields.assignee.displayName, 120);\n\nconst delivery = headers['x-atlassian-webhook-identifier'] || [issue.id, payload.timestamp].filter(Boolean).join('-');\nreturn [{ json: { skip: false, body, idempotencyKey: clip(`n8n-jira-${delivery}`, 255) } }];\n"
      },
      "id": "b2c3d4e5-0002-4000-8000-000000000002",
      "name": "Map Jira issue to incident",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        240,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "d0000000-0000-4000-8000-000000000001",
              "leftValue": "={{ $json.skip }}",
              "rightValue": false,
              "operator": {
                "type": "boolean",
                "operation": "false",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "b2c3d4e5-0003-4000-8000-000000000003",
      "name": "Issue created?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        480,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://www.vouliiq.com/api/v1/incidents",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Idempotency-Key",
              "value": "={{ $json.idempotencyKey }}"
            },
            {
              "name": "Vouli-Version",
              "value": "2026-09-12"
            },
            {
              "name": "Accept",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "contentType": "json",
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}",
        "options": {
          "response": {
            "response": {
              "fullResponse": true,
              "neverError": true
            }
          }
        }
      },
      "id": "b2c3d4e5-0004-4000-8000-000000000004",
      "name": "Create incident in Vouli IQ",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        720,
        200
      ],
      "credentials": {
        "httpHeaderAuth": {
          "id": "REPLACE_WITH_VOULI_API_KEY_CREDENTIAL",
          "name": "Vouli IQ API key (Authorization: Bearer vk_live_…)"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ $json.body }}",
        "options": {
          "responseCode": "={{ $json.statusCode }}"
        }
      },
      "id": "b2c3d4e5-0005-4000-8000-000000000005",
      "name": "Answer with Vouli IQ's response",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        960,
        200
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{ { \"skipped\": true, \"reason\": $json.reason } }}",
        "options": {
          "responseCode": 200
        }
      },
      "id": "b2c3d4e5-0006-4000-8000-000000000006",
      "name": "Ignore other events",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        720,
        420
      ]
    }
  ],
  "connections": {
    "Jira issue webhook": {
      "main": [
        [
          {
            "node": "Map Jira issue to incident",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Jira issue to incident": {
      "main": [
        [
          {
            "node": "Issue created?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Issue created?": {
      "main": [
        [
          {
            "node": "Create incident in Vouli IQ",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Ignore other events",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create incident in Vouli IQ": {
      "main": [
        [
          {
            "node": "Answer with Vouli IQ's response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
