{
  "name": "Jsonpage - Monitoring alert to Slack or Teams and a HubSpot task",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "jsonpage-alert",
        "responseMode": "onReceived",
        "options": {
          "rawBody": true
        }
      },
      "id": "26c2db1a-900d-5791-aaed-41da9e89df6e",
      "name": "Jsonpage webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        300
      ],
      "webhookId": "66c23d43-76af-5e4a-adb8-6603e5de132a"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a6c617e0-d0cc-5308-bc2a-23fd4720911a",
              "name": "signingSecret",
              "value": "PASTE_YOUR_WHSEC_SECRET",
              "type": "string"
            },
            {
              "id": "828b69e5-fbf4-5bc0-8758-cf685ab2b35a",
              "name": "apiKey",
              "value": "PASTE_YOUR_JSONPAGE_API_KEY",
              "type": "string"
            },
            {
              "id": "64ce9908-c5f7-58f1-8936-09ef0522c598",
              "name": "baseUrl",
              "value": "https://api.jsonpage.com/v2",
              "type": "string"
            },
            {
              "id": "05faa5b4-79d7-51e3-bcc2-85321edc7f05",
              "name": "chat",
              "value": "slack",
              "type": "string"
            },
            {
              "id": "50a4bd8c-77ed-5791-9e47-510235d60350",
              "name": "chatWebhookUrl",
              "value": "PASTE_YOUR_SLACK_OR_TEAMS_WEBHOOK_URL",
              "type": "string"
            },
            {
              "id": "97df778c-1f11-59e0-92aa-a8bd05630785",
              "name": "hubspotToken",
              "value": "PASTE_YOUR_HUBSPOT_PRIVATE_APP_TOKEN",
              "type": "string"
            }
          ]
        },
        "includeOtherFields": true,
        "options": {
          "includeBinary": true
        }
      },
      "id": "ebcc5125-baff-579a-926a-4056654b4235",
      "name": "Config",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        220,
        300
      ],
      "notes": "Edit the values of this node only: nothing else needs to change.",
      "notesInFlow": true
    },
    {
      "parameters": {
        "jsCode": "// Checks the Jsonpage-Signature header (HMAC-SHA256 of \"<t>.<raw body>\" with the whsec_ secret).\nconst crypto = require('crypto'); // self-hosted n8n: set NODE_FUNCTION_ALLOW_BUILTIN=crypto\nconst item = $input.first();\nconst secret = $('Config').first().json.signingSecret;\nif (!secret || secret.indexOf('PASTE_') === 0) throw new Error('Set signingSecret in the Config node (whsec_ secret of the Monitoring section).');\nconst header = String((item.json.headers || {})['jsonpage-signature'] || '');\nconst parts = Object.fromEntries(header.split(',').map((p) => p.trim().split('=')).filter((p) => p.length === 2));\nconst t = Number(parts.t);\nif (!t || Math.abs(Date.now() / 1000 - t) > 300) throw new Error('Signature timestamp missing or too old');\nconst raw = await this.helpers.getBinaryDataBuffer(0, 'data');\nconst expected = crypto.createHmac('sha256', secret).update(parts.t + '.').update(raw).digest('hex');\nconst given = Buffer.from(String(parts.v1 || ''), 'hex');\nconst wanted = Buffer.from(expected, 'hex');\nif (given.length !== wanted.length || !crypto.timingSafeEqual(given, wanted)) throw new Error('Invalid signature');\nconst event = JSON.parse(raw.toString('utf8'));\nreturn [{ json: { event } }];"
      },
      "id": "d66034f7-7d8a-5cdb-976d-f2bc40e59820",
      "name": "Check the signature",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "b03c0ffe-e246-5bcb-a006-7fa51b9a6774",
              "leftValue": "={{ $json.event.company_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "b03c0ffe-e246-5bcb-a006-7fa51b9a6774",
      "name": "Company known?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        660,
        300
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $('Config').first().json.baseUrl }}/companies/{{ $json.event.company_id }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-API-Key",
              "value": "={{ $('Config').first().json.apiKey }}"
            }
          ]
        },
        "options": {}
      },
      "id": "1bcdfc18-63e8-5a21-8a2e-83ec5edf17f2",
      "name": "Company",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        880,
        220
      ],
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// Builds the alert text and the payloads for the chat message (Slack or Teams) and the CRM task.\nconst cfg = $('Config').first().json;\nconst event = $('Check the signature').first().json.event;\nlet name = event.company_id;\ntry { name = $('Company').first().json.data.name || name; } catch (e) { /* test event or lookup failed */ }\nconst d = event.data || {};\nconst labels = {\n  'company.status_changed': 'status changed', 'company.name_changed': 'name changed', 'company.address_changed': 'address changed',\n  'company.activity_changed': 'activity changed', 'company.legal_form_changed': 'legal form changed',\n  'company.removed_from_register': 'removed from the register', 'signal.added': 'warning signal added', 'signal.removed': 'warning signal removed',\n  'legal_event.published': 'legal announcement published', 'sanctions.changed': 'sanctions status changed',\n  'owner.added': 'owner added', 'owner.removed': 'owner removed', test: 'test event'\n};\nlet detail = '';\nif (d.before !== undefined || d.after !== undefined) detail = ' (' + (d.before ?? '-') + ' -> ' + (d.after ?? '-') + ')';\nelse if (d.code) detail = ' (' + d.code + (d.detail ? ': ' + d.detail : '') + ')';\nelse if (d.event && d.event.type) detail = ' (' + d.event.type + ')';\nelse if (d.name) detail = ' (' + d.name + ')';\nconst label = labels[event.type] || event.type;\nconst text = 'Jsonpage: ' + (event.company_id ? name + ' (' + event.company_id + ') ' : '') + label + detail + ' - ' + event.detected_at;\nconst chat = String(cfg.chat || 'slack').toLowerCase() === 'teams'\n  ? { type: 'message', attachments: [{ contentType: 'application/vnd.microsoft.card.adaptive', content: { $schema: 'http://adaptivecards.io/schemas/adaptive-card.json', type: 'AdaptiveCard', version: '1.4', body: [{ type: 'TextBlock', text, wrap: true }] } }] }\n  : { text };\nconst task = { properties: { hs_timestamp: new Date().toISOString(), hs_task_subject: 'Check ' + name + ': ' + label, hs_task_body: text, hs_task_status: 'NOT_STARTED', hs_task_priority: 'HIGH' } };\nreturn [{ json: { text, chat, task, taskNeeded: event.type === 'test' ? '' : 'yes' } }];"
      },
      "id": "1ce88be8-33b1-51fe-8d7e-8d9ae48a1553",
      "name": "Build the message",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1100,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "={{ $('Config').first().json.chatWebhookUrl }}",
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($('Build the message').first().json.chat) }}",
        "options": {}
      },
      "id": "75c41669-ee3d-533e-831d-503ed70d0320",
      "name": "Chat message (Slack or Teams)",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1320,
        300
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "conditions": [
            {
              "id": "55b73191-ebf6-5875-9dda-94690dd728f9",
              "leftValue": "={{ $('Build the message').first().json.taskNeeded }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "55b73191-ebf6-5875-9dda-94690dd728f9",
      "name": "Real event?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1540,
        300
      ]
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://api.hubapi.com/crm/v3/objects/tasks",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "=Bearer {{ $('Config').first().json.hubspotToken }}"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($('Build the message').first().json.task) }}",
        "options": {}
      },
      "id": "f5b19983-ab19-52fb-9d57-ce4b2c242ea2",
      "name": "Task in HubSpot",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1760,
        220
      ],
      "retryOnFail": true,
      "maxTries": 3,
      "waitBetweenTries": 5000
    }
  ],
  "connections": {
    "Jsonpage webhook": {
      "main": [
        [
          {
            "node": "Config",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config": {
      "main": [
        [
          {
            "node": "Check the signature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check the signature": {
      "main": [
        [
          {
            "node": "Company known?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Company known?": {
      "main": [
        [
          {
            "node": "Company",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Build the message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Company": {
      "main": [
        [
          {
            "node": "Build the message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build the message": {
      "main": [
        [
          {
            "node": "Chat message (Slack or Teams)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Chat message (Slack or Teams)": {
      "main": [
        [
          {
            "node": "Real event?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Real event?": {
      "main": [
        [
          {
            "node": "Task in HubSpot",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  },
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "pinData": {},
  "meta": {
    "templateCredsSetupCompleted": false
  },
  "tags": []
}
