{
  "name": "Auto-create Jira tickets from n8n workflow failures",
  "nodes": [
    {
      "parameters": {
        "content": "## Overview\n\nEvery **Org21-Observer** POST arrives here. If the payload carries an `errors` array, the workflow opens a **Jira** issue with the workflow name, failing node, timing, and the full error object as context \u2014 then pings Slack so on-call knows a ticket was filed.\n\n## How to use\n\n1. Install `n8n-nodes-org21`, create a **Jira Cloud credential** and a **Slack credential** in n8n.\n2. **Activate** this workflow so the Webhook listens.\n3. In any workflow you want to monitor: drop an Org21-Observer, set `triggerMode = Webhook POST`, paste this workflow's Webhook URL.\n4. Pick your Jira project + issue type in the *Create Jira Issue* node (leave the dropdowns empty on import so n8n prompts you).\n\n## Customize\n\n- **Severity routing** \u2014 branch on `metadata.workflowName` to send different workflows to different projects.\n- **PII redaction** \u2014 strip or hash `payload` fields before they land in Jira (see sticky note below).\n- **Dedupe** \u2014 today, every failed execution opens a new ticket. For higher-volume workflows add a lookup + update instead of create (see sticky note).\n",
        "height": 400,
        "width": 520
      },
      "id": "note-overview",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        60,
        60
      ]
    },
    {
      "parameters": {
        "content": "## PII & payload warning\n\n`Include Item Data = true` on the Observer means the literal items passing through the node land in the Jira ticket description. If those items can contain PII, secrets, or customer data, either:\n\n- turn off `Include Item Data` on the Observer, **or**\n- insert a **Set** / **Code** node between the IF and the Jira node that redacts / hashes the sensitive fields.\n\nJira tickets are usually readable by a broader audience than Observer events.",
        "height": 320,
        "width": 360
      },
      "id": "note-pii",
      "name": "PII warning",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        60,
        480
      ]
    },
    {
      "parameters": {
        "content": "## Dedupe\n\nThis template opens one Jira per failed execution. For a workflow that fails 50\u00d7 per hour, that's 50 tickets.\n\nQuick dedupe patterns (not in this template, but easy adds):\n\n1. Before creating, search Jira for an open ticket whose summary matches `workflow_name + node_name`. If found, **comment** instead of **create**.\n2. Maintain a Redis key `observer:ticket:{workflow}:{node}:{yyyymmdd}`. Skip create if key exists.\n3. Rate-limit via n8n's `Wait` node keyed by `{workflow}/{node}`.\n\nPick whichever matches your Jira etiquette.",
        "height": 360,
        "width": 360
      },
      "id": "note-dedupe",
      "name": "Dedupe",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        440,
        480
      ]
    },
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "org21-observer-jira",
        "options": {}
      },
      "id": "webhook",
      "name": "Observer Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        260,
        260
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ ($json.body?.errors ?? []).length }}",
              "rightValue": 0,
              "operator": {
                "type": "number",
                "operation": "gt"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "if-has-errors",
      "name": "Has errors?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        480,
        260
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "s1",
              "name": "summary",
              "value": "=[n8n] {{ $json.body.metadata.workflowName }} \u2014 {{ $json.body.metadata.nodeName }} failed",
              "type": "string"
            },
            {
              "id": "s2",
              "name": "description",
              "value": "=*Workflow:* {{ $json.body.metadata.workflowName }} (`{{ $json.body.metadata.workflowId }}`)\n*Execution:* `{{ $json.body.metadata.executionId }}`\n*Failing node:* {{ $json.body.metadata.nodeName }}\n*Duration:* {{ $json.body.timing?.durationMs }} ms \u2014 *items:* {{ $json.body.timing?.itemCount }}\n*Timestamp:* {{ $json.body.metadata.timestamp }}\n\n*Errors:*\n{code}\n{{ JSON.stringify($json.body.errors, null, 2) }}\n{code}\n\n*Upstream items (redact PII before sharing):*\n{code}\n{{ JSON.stringify(($json.body.items ?? []).slice(0, 3), null, 2) }}\n{code}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "id": "set-format",
      "name": "Format Jira Fields",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        700,
        260
      ]
    },
    {
      "parameters": {
        "resource": "issue",
        "operation": "create",
        "project": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "issueType": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "summary": "={{ $json.summary }}",
        "additionalFields": {
          "description": "={{ $json.description }}",
          "labels": [
            "n8n",
            "org21-observer",
            "auto-filed"
          ]
        }
      },
      "id": "jira-create",
      "name": "Create Jira Issue",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        920,
        260
      ]
    },
    {
      "parameters": {
        "resource": "message",
        "operation": "post",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "",
          "mode": "list",
          "cachedResultName": ""
        },
        "text": "=:ticket: *Jira filed:* <{{ $json.self?.replace('/rest/api/3/issue/','/browse/') ?? $json.key }}|{{ $json.key }}> \u2014 {{ $json.fields?.summary ?? $('Format Jira Fields').item.json.summary }}",
        "otherOptions": {}
      },
      "id": "slack-notify",
      "name": "Notify Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1140,
        260
      ]
    }
  ],
  "connections": {
    "Observer Webhook": {
      "main": [
        [
          {
            "node": "Has errors?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has errors?": {
      "main": [
        [
          {
            "node": "Format Jira Fields",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Format Jira Fields": {
      "main": [
        [
          {
            "node": "Create Jira Issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Jira Issue": {
      "main": [
        [
          {
            "node": "Notify Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "staticData": null,
  "tags": [
    {
      "name": "observability"
    },
    {
      "name": "alerting"
    },
    {
      "name": "jira"
    },
    {
      "name": "incident-management"
    }
  ],
  "triggerCount": 0,
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "versionId": ""
}