{
  "name": "Izini events to Slack",
  "nodes": [
    {
      "id": "38c7bbe8-ff29-4d78-833b-dd868c034868",
      "name": "Instructions",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -60,
        -60
      ],
      "parameters": {
        "color": 4,
        "width": 760,
        "height": 300,
        "content": "## Izini events to Slack\n1. Paste your webhook secret (Izini: Developers > Webhooks) into **Sign with your webhook secret**.\n2. Connect Slack and pick the channel in **Post to Slack**.\n3. Activate the workflow, copy the production URL of **Izini webhook**, and add it in Izini as a webhook with the events you want.\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": "6070c73d-ff67-472f-89a3-1f86af9cd189",
      "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": "567656f9-5237-46c7-87cc-7b2f3b9bb3f6",
      "name": "Read raw body",
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1.1,
      "position": [
        220,
        300
      ],
      "parameters": {
        "operation": "text",
        "destinationKey": "rawBody"
      }
    },
    {
      "id": "57d8ccad-3c8d-42ba-8e7b-f32b14c40dbd",
      "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": "9f240cea-99c7-4fe6-896c-d8fd4ad11f41",
      "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": "7e5f89cd-4701-4f81-83b1-a87406ea1c48",
      "name": "Answer 200",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        880,
        200
      ],
      "parameters": {
        "respondWith": "noData",
        "options": {
          "responseCode": 200
        }
      }
    },
    {
      "id": "dc842e06-75c7-45e0-8373-b7951c45773e",
      "name": "Answer 401",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.5,
      "position": [
        880,
        420
      ],
      "parameters": {
        "respondWith": "noData",
        "options": {
          "responseCode": 401
        }
      }
    },
    {
      "id": "c1cf274b-b2fc-4aef-8b65-256e09358635",
      "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": "23071171-b16e-4132-8d71-59a5a1bd8a24",
      "name": "Skip repeats",
      "type": "n8n-nodes-base.removeDuplicates",
      "typeVersion": 2,
      "position": [
        1320,
        200
      ],
      "parameters": {
        "operation": "removeItemsSeenInPreviousExecutions",
        "logic": "removeItemsWithAlreadySeenKeyValues",
        "dedupeValue": "={{ $json.id }}"
      }
    },
    {
      "id": "2d751988-b978-4872-8b90-1c78bd2ea6ca",
      "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": "9ee4364d-3675-4394-819f-7b1ff0907cae",
      "name": "Post to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1760,
        200
      ],
      "parameters": {
        "resource": "message",
        "operation": "post",
        "authentication": "oAuth2",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "#compliance"
        },
        "messageType": "text",
        "text": "=*{{ $json.headline }}*{{ $json.reference ? \" · \" + $json.reference : \"\" }}\nDate: {{ $json.when }}\n<{{ $json.link }}|Open in Izini>",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "unfurl_links": false
        }
      }
    }
  ],
  "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": "Post to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  },
  "meta": {
    "templateCredsSetupCompleted": false,
    "source": "https://app.izini.ng/developers/guides/events-to-your-tools"
  }
}
