{
  "name": "Izini requests and breaches to Jira",
  "nodes": [
    {
      "id": "1b65fc0b-e16e-4806-8cd6-6647f5046366",
      "name": "Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -60
      ],
      "parameters": {
        "color": 4,
        "width": 760,
        "height": 300,
        "content": "## Izini requests and breaches to Jira\n1. Paste your webhook secret (Izini: Developers > Webhooks) into **Sign with your webhook secret**.\n2. Connect Jira and choose the project and issue type in **Open a Jira issue**.\n3. Activate the workflow, copy the production URL of **Izini webhook**, and add it in Izini as a webhook with the events you want. Choose at least dsar.received and incident.created; add dsar.due_soon, dsar.overdue, dsar.closed, incident.breach_clock and incident.ndpc_notified to have them added as comments.\n\nRequests not signed by Izini, or older than 5 minutes, get 401. A retried delivery is handled once. Guide: https://app.izini.ng/developers/guides/events-to-your-tools"
      }
    },
    {
      "id": "3db840a3-944f-417d-8998-1057c91a6904",
      "name": "Izini webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        0,
        300
      ],
      "parameters": {
        "httpMethod": "POST",
        "path": "izini-events",
        "responseMode": "responseNode",
        "options": {
          "rawBody": true
        }
      }
    },
    {
      "id": "89cd13a3-0213-44f0-8d7d-f5fb66c1189b",
      "name": "Read raw body",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        220,
        300
      ],
      "parameters": {
        "operation": "text",
        "destinationKey": "rawBody"
      }
    },
    {
      "id": "ed6e46db-7997-4f47-855f-aaf54a7108e1",
      "name": "Sign with your webhook secret",
      "type": "n8n-nodes-base.crypto",
      "typeVersion": 1,
      "position": [
        440,
        300
      ],
      "parameters": {
        "action": "hmac",
        "type": "SHA256",
        "value": "={{ $('Izini webhook').item.json.headers['x-izini-timestamp'] }}.{{ $json.rawBody }}",
        "dataPropertyName": "expectedSignature",
        "secret": "PASTE_YOUR_IZINI_WEBHOOK_SECRET",
        "encoding": "hex"
      }
    },
    {
      "id": "1f4d5a31-b7a6-4334-8179-57978b51995f",
      "name": "Signed by Izini, sent in the last 5 minutes?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        660,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.expectedSignature }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "={{ $('Izini webhook').item.json.headers['x-izini-signature-v2'] }}"
            },
            {
              "leftValue": "={{ Math.abs($now.toSeconds() - Number($('Izini webhook').item.json.headers['x-izini-timestamp'])) }}",
              "operator": {
                "type": "number",
                "operation": "lt"
              },
              "rightValue": 300
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "4344aea7-5f7c-4e5b-832b-b39dbe2f1ead",
      "name": "Answer 200",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        880,
        200
      ],
      "parameters": {
        "respondWith": "noData",
        "options": {
          "responseCode": 200
        }
      }
    },
    {
      "id": "e12e4a1d-06fa-49f0-8815-02b7d208fe37",
      "name": "Answer 401",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        880,
        420
      ],
      "parameters": {
        "respondWith": "noData",
        "options": {
          "responseCode": 401
        }
      }
    },
    {
      "id": "191651e5-dd0e-4b03-8982-eadf55241ce1",
      "name": "Parse event",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1100,
        200
      ],
      "parameters": {
        "mode": "raw",
        "jsonOutput": "={{ $('Read raw body').item.json.rawBody }}",
        "includeOtherFields": false
      }
    },
    {
      "id": "3cafc3a3-af27-4b63-8515-f4b009a0b647",
      "name": "Skip repeats",
      "type": "n8n-nodes-base.removeDuplicates",
      "typeVersion": 2,
      "position": [
        1320,
        200
      ],
      "parameters": {
        "operation": "removeItemsSeenInPreviousExecutions",
        "logic": "removeItemsWithAlreadySeenKeyValues",
        "dedupeValue": "={{ $json.id }}"
      }
    },
    {
      "id": "10ce3134-3296-4768-8047-84faf14184ce",
      "name": "Describe event",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        1540,
        200
      ],
      "parameters": {
        "mode": "manual",
        "includeOtherFields": true,
        "assignments": {
          "assignments": [
            {
              "id": "headline",
              "name": "headline",
              "type": "string",
              "value": "={{ ({\"consent.updated\":\"Consent recorded\",\"dsar.received\":\"New data subject request\",\"dsar.due_soon\":\"Data subject request due within 7 days\",\"dsar.overdue\":\"Data subject request past its target\",\"dsar.closed\":\"Data subject request closed\",\"incident.created\":\"Incident logged\",\"incident.breach_clock\":\"72-hour NDPC clock\",\"incident.ndpc_notified\":\"Breach reported to the NDPC\",\"dpia.completed\":\"DPIA completed\",\"policy.published\":\"Privacy policy published\",\"vendor.dpa_review_due\":\"Vendor DPA due for review\",\"training.overdue\":\"Staff training overdue\",\"car.due\":\"Annual audit return due 31 March\"})[$json.event] ?? $json.event }}{{ $json.event === 'incident.breach_clock' ? ': ' + (({\"started\":\"clock started\",\"48h\":\"48 hours left\",\"24h\":\"24 hours left\",\"6h\":\"6 hours left\",\"overdue\":\"deadline passed\"})[$json.payload.milestone] ?? $json.payload.milestone) : '' }}"
            },
            {
              "id": "reference",
              "name": "reference",
              "type": "string",
              "value": "={{ $json.payload.reference ?? $json.payload.agreement_name ?? \"\" }}"
            },
            {
              "id": "when",
              "name": "when",
              "type": "string",
              "value": "={{ $json.payload.due_at ?? $json.payload.notification_deadline ?? $json.payload.review_due_date ?? $json.payload.due_date ?? $json.timestamp }}"
            },
            {
              "id": "link",
              "name": "link",
              "type": "string",
              "value": "={{ $json.payload.dashboard_url ?? \"https://app.izini.ng/dashboard\" }}"
            }
          ]
        }
      }
    },
    {
      "id": "de0c0e43-c319-4dff-8b31-13b169a3c75d",
      "name": "New record or update?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1760,
        200
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose"
          },
          "conditions": [
            {
              "leftValue": "={{ [\"dsar.received\", \"incident.created\"].includes($json.event) }}",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        }
      }
    },
    {
      "id": "0466b7e3-ca41-4164-86ea-a42ac7482d6f",
      "name": "Open a Jira issue",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        1980,
        100
      ],
      "parameters": {
        "resource": "issue",
        "operation": "create",
        "jiraVersion": "cloud",
        "project": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "issueType": {
          "__rl": true,
          "mode": "list",
          "value": ""
        },
        "summary": "={{ $json.headline }}{{ $json.reference ? \" \" + $json.reference : \"\" }} [iz{{ ($json.payload.request_id ?? $json.payload.incident_id ?? \"\").replaceAll(\"-\", \"\").slice(0, 12) }}]",
        "additionalFields": {
          "labels": [
            "izini"
          ],
          "description": "={{ $json.headline }}\nReference: {{ $json.reference || \"none yet\" }}\nDue: {{ $json.when }}\nOpen in Izini: {{ $json.link }}\n\nThe record and the people in it stay in Izini."
        }
      }
    },
    {
      "id": "bc349ae6-aa63-4c30-8687-f0617e8b4bd6",
      "name": "Find the Jira issue",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        1980,
        320
      ],
      "parameters": {
        "resource": "issue",
        "operation": "getAll",
        "jiraVersion": "cloud",
        "returnAll": false,
        "limit": 1,
        "options": {
          "jql": "=labels = izini AND summary ~ \"iz{{ ($json.payload.request_id ?? $json.payload.incident_id ?? \"\").replaceAll(\"-\", \"\").slice(0, 12) }}\" ORDER BY created DESC",
          "fields": "summary"
        }
      }
    },
    {
      "id": "cd011a47-875c-4666-819f-138972de46ec",
      "name": "Add a comment",
      "type": "n8n-nodes-base.jira",
      "typeVersion": 1,
      "position": [
        2200,
        320
      ],
      "parameters": {
        "resource": "issueComment",
        "operation": "add",
        "jiraVersion": "cloud",
        "issueKey": "={{ $json.key }}",
        "jsonParameters": false,
        "comment": "={{ $('Describe event').item.json.headline }}. Date: {{ $('Describe event').item.json.when }}. {{ $('Describe event').item.json.link }}"
      }
    }
  ],
  "connections": {
    "Izini webhook": {
      "main": [
        [
          {
            "node": "Read raw body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read raw body": {
      "main": [
        [
          {
            "node": "Sign with your webhook secret",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sign with your webhook secret": {
      "main": [
        [
          {
            "node": "Signed by Izini, sent in the last 5 minutes?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Signed by Izini, sent in the last 5 minutes?": {
      "main": [
        [
          {
            "node": "Answer 200",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Answer 401",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Answer 200": {
      "main": [
        [
          {
            "node": "Parse event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse event": {
      "main": [
        [
          {
            "node": "Skip repeats",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Skip repeats": {
      "main": [
        [
          {
            "node": "Describe event",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Describe event": {
      "main": [
        [
          {
            "node": "New record or update?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New record or update?": {
      "main": [
        [
          {
            "node": "Open a Jira issue",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Find the Jira issue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Find the Jira issue": {
      "main": [
        [
          {
            "node": "Add a comment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false,
    "source": "https://app.izini.ng/developers/guides/events-to-your-tools"
  }
}
