{
  "updatedAt": "2026-05-22T21:51:06.493Z",
  "createdAt": "2026-05-10T02:25:40.618Z",
  "id": "BLJVcnMRNMdswJQN",
  "name": "n8n Self-Health Monitor",
  "description": null,
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 15
            }
          ]
        }
      },
      "id": "53bd1074-cb61-4c5e-80ec-625ef9310ea2",
      "name": "Every 15 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "http://10.5.30.6:5678/api/v1/executions",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "X-N8N-API-KEY",
              "value": "={{ $env.N8N_API_KEY }}"
            }
          ]
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "status",
              "value": "error"
            },
            {
              "name": "includeData",
              "value": "false"
            },
            {
              "name": "limit",
              "value": "50"
            }
          ]
        },
        "options": {}
      },
      "id": "ce33dd4c-6a76-4a65-9f61-55e2d2b64148",
      "name": "Fetch Failed Executions",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        224,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const data = $input.first().json;\nconst executions = data.data || [];\nconst oneHourAgo = Date.now() - (60 * 60 * 1000);\n\n// Filter to failures in the past hour\nconst recent = executions.filter(e => {\n  const ts = new Date(e.startedAt || e.stoppedAt || 0).getTime();\n  return ts >= oneHourAgo;\n});\n\n// Group by workflow name + error message for dedup key\nconst failures = recent.map(e => ({\n  executionId: e.id,\n  workflowId: e.workflowId,\n  workflowName: e.workflowData?.name || `Workflow ${e.workflowId}`,\n  startedAt: e.startedAt,\n  stoppedAt: e.stoppedAt,\n  errorMessage: e.data?.resultData?.error?.message || 'Unknown error'\n}));\n\n// Deduplicate by workflowName (report once per workflow per check)\nconst seen = new Set();\nconst unique = failures.filter(f => {\n  if (seen.has(f.workflowName)) return false;\n  seen.add(f.workflowName);\n  return true;\n});\n\nreturn [{ json: { hasFailures: unique.length > 0, count: unique.length, failures: unique } }];"
      },
      "id": "83b9a030-b10c-4a59-a8d0-a632b4cfe5d2",
      "name": "Filter Recent Failures",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        448,
        0
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "a76d10a7-1313-467e-9648-471b296229a3",
              "leftValue": "={{ $json.hasFailures }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "fea1e46a-e3af-4d60-9f21-a79593fdef71",
      "name": "Has Failures?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        672,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const d = $input.first().json;\n// Fingerprint = sorted workflow names joined — stable across retriggers\nconst fingerprint = (d.failures || [])\n  .map(f => f.workflowName)\n  .sort()\n  .join('|') || 'unknown';\nreturn [{ json: { ...d, fingerprint } }];"
      },
      "id": "cf9ad5c7-163c-4f06-8300-48499e70072c",
      "name": "Build Fingerprint",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        896,
        -120
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT fingerprint, last_seen FROM n8n_health_dedup WHERE fingerprint = '{{ $json.fingerprint }}' AND last_seen > NOW() - INTERVAL '1 hour' LIMIT 1;",
        "options": {}
      },
      "id": "faef0ff7-e592-463d-9f98-460591038799",
      "name": "Lookup Dedup",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1120,
        -120
      ],
      "credentials": {
        "postgres": {
          "id": "n9svoXemqSZoNNUB",
          "name": "Postgres account"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "jsCode": "const alertData = $('Build Fingerprint').first().json;\nconst rows = $input.all().filter(r => r.json && r.json.fingerprint);\nconst alreadyNotified = rows.length > 0;\nreturn [{ json: { ...alertData, alreadyNotified, shouldNotify: !alreadyNotified } }];"
      },
      "id": "1fdb0262-7d45-4f30-8dd4-2445ab569df1",
      "name": "Check Already Notified",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1344,
        -120
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "b1e77af5-6875-47dd-97af-8e13958a7217",
              "leftValue": "={{ $json.shouldNotify }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equal"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "258f7606-5252-4e78-8398-89970d5cea74",
      "name": "Should Notify?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        1568,
        -120
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO n8n_health_dedup (fingerprint, last_seen, workflow_names) VALUES ('{{ $json.fingerprint }}', NOW(), '{{ $json.failures.map(f => f.workflowName).join(\", \") }}') ON CONFLICT (fingerprint) DO UPDATE SET last_seen = NOW(), workflow_names = EXCLUDED.workflow_names;",
        "options": {}
      },
      "id": "dc7c3c90-1cb0-4b3f-b462-58401411e976",
      "name": "Upsert Dedup Record",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1792,
        -120
      ],
      "credentials": {
        "postgres": {
          "id": "n9svoXemqSZoNNUB",
          "name": "Postgres account"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const d = $('Build Fingerprint').first().json;\nconst lines = (d.failures || []).map(f =>\n  `  • ${f.workflowName}\\n    ${f.errorMessage.substring(0, 120)}`\n);\nconst body = `${d.count} workflow${d.count !== 1 ? 's' : ''} failed in the past hour:\\n\\n${lines.join('\\n')}\\n\\nhttps://n8n.paccoco.com`;\nreturn [{ json: { title: `⚠️ n8n: ${d.count} Workflow Failure${d.count !== 1 ? 's' : ''}`, message: body, priority: 7 } }];"
      },
      "id": "7d040998-67c2-4888-937c-6d82e41056d1",
      "name": "Format Notification",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2016,
        -120
      ]
    },
    {
      "parameters": {
        "message": "={{ $json.message }}",
        "additionalFields": {
          "priority": "={{ $json.priority }}",
          "title": "={{ $json.title }}"
        },
        "options": {
          "contentType": "text/plain"
        }
      },
      "id": "2569776a-c0a8-48cb-8615-af95daf53292",
      "name": "Push to Gotify",
      "type": "n8n-nodes-base.gotify",
      "typeVersion": 1,
      "position": [
        2240,
        -120
      ],
      "credentials": {
        "gotifyApi": {
          "id": "mMegDxfmMUfbOrnF",
          "name": "n8n Health"
        }
      }
    }
  ],
  "connections": {
    "Every 15 Minutes": {
      "main": [
        [
          {
            "node": "Fetch Failed Executions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Failed Executions": {
      "main": [
        [
          {
            "node": "Filter Recent Failures",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Recent Failures": {
      "main": [
        [
          {
            "node": "Has Failures?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Failures?": {
      "main": [
        [
          {
            "node": "Build Fingerprint",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Build Fingerprint": {
      "main": [
        [
          {
            "node": "Lookup Dedup",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Lookup Dedup": {
      "main": [
        [
          {
            "node": "Check Already Notified",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Already Notified": {
      "main": [
        [
          {
            "node": "Should Notify?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Should Notify?": {
      "main": [
        [
          {
            "node": "Upsert Dedup Record",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    },
    "Upsert Dedup Record": {
      "main": [
        [
          {
            "node": "Format Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Notification": {
      "main": [
        [
          {
            "node": "Push to Gotify",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  },
  "staticData": {
    "node:Every 15 Minutes": {
      "recurrenceRules": []
    }
  },
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "pinData": {},
  "versionId": "8cf46654-a773-4921-8745-3169eb7709f3",
  "activeVersionId": "8cf46654-a773-4921-8745-3169eb7709f3",
  "versionCounter": 31,
  "triggerCount": 1,
  "shared": [
    {
      "updatedAt": "2026-05-10T02:25:40.618Z",
      "createdAt": "2026-05-10T02:25:40.618Z",
      "role": "workflow:owner",
      "workflowId": "BLJVcnMRNMdswJQN",
      "projectId": "dxCRnBdX5uJizCGa",
      "project": {
        "updatedAt": "2026-05-06T01:10:37.484Z",
        "createdAt": "2026-05-06T01:08:07.721Z",
        "id": "dxCRnBdX5uJizCGa",
        "name": "Wilfred Fizzlepoof <admin@paccoco.com>",
        "type": "personal",
        "icon": null,
        "description": null,
        "creatorId": "47b2227f-2fc2-4a08-bd35-ea157b92df0d"
      }
    }
  ],
  "tags": [
    {
      "updatedAt": "2026-05-06T22:38:51.660Z",
      "createdAt": "2026-05-06T22:38:51.660Z",
      "id": "0ETpkL5jJ5wwgt8k",
      "name": "monitoring"
    },
    {
      "updatedAt": "2026-05-09T18:01:37.295Z",
      "createdAt": "2026-05-09T18:01:37.295Z",
      "id": "PYzt74cSdu6cC6P1",
      "name": "scheduled"
    },
    {
      "updatedAt": "2026-05-09T18:02:26.263Z",
      "createdAt": "2026-05-09T18:02:26.263Z",
      "id": "t3Vz8xsWhwxAXMRx",
      "name": "n8n"
    }
  ],
  "activeVersion": {
    "updatedAt": "2026-05-22T21:51:06.496Z",
    "createdAt": "2026-05-22T21:51:06.496Z",
    "versionId": "8cf46654-a773-4921-8745-3169eb7709f3",
    "workflowId": "BLJVcnMRNMdswJQN",
    "nodes": [
      {
        "parameters": {
          "rule": {
            "interval": [
              {
                "field": "minutes",
                "minutesInterval": 15
              }
            ]
          }
        },
        "id": "53bd1074-cb61-4c5e-80ec-625ef9310ea2",
        "name": "Every 15 Minutes",
        "type": "n8n-nodes-base.scheduleTrigger",
        "typeVersion": 1.2,
        "position": [
          0,
          0
        ]
      },
      {
        "parameters": {
          "method": "GET",
          "url": "http://10.5.30.6:5678/api/v1/executions",
          "sendHeaders": true,
          "headerParameters": {
            "parameters": [
              {
                "name": "X-N8N-API-KEY",
                "value": "={{ $env.N8N_API_KEY }}"
              }
            ]
          },
          "sendQuery": true,
          "queryParameters": {
            "parameters": [
              {
                "name": "status",
                "value": "error"
              },
              {
                "name": "includeData",
                "value": "false"
              },
              {
                "name": "limit",
                "value": "50"
              }
            ]
          },
          "options": {}
        },
        "id": "ce33dd4c-6a76-4a65-9f61-55e2d2b64148",
        "name": "Fetch Failed Executions",
        "type": "n8n-nodes-base.httpRequest",
        "typeVersion": 4.2,
        "position": [
          224,
          0
        ]
      },
      {
        "parameters": {
          "jsCode": "const data = $input.first().json;\nconst executions = data.data || [];\nconst oneHourAgo = Date.now() - (60 * 60 * 1000);\n\n// Filter to failures in the past hour\nconst recent = executions.filter(e => {\n  const ts = new Date(e.startedAt || e.stoppedAt || 0).getTime();\n  return ts >= oneHourAgo;\n});\n\n// Group by workflow name + error message for dedup key\nconst failures = recent.map(e => ({\n  executionId: e.id,\n  workflowId: e.workflowId,\n  workflowName: e.workflowData?.name || `Workflow ${e.workflowId}`,\n  startedAt: e.startedAt,\n  stoppedAt: e.stoppedAt,\n  errorMessage: e.data?.resultData?.error?.message || 'Unknown error'\n}));\n\n// Deduplicate by workflowName (report once per workflow per check)\nconst seen = new Set();\nconst unique = failures.filter(f => {\n  if (seen.has(f.workflowName)) return false;\n  seen.add(f.workflowName);\n  return true;\n});\n\nreturn [{ json: { hasFailures: unique.length > 0, count: unique.length, failures: unique } }];"
        },
        "id": "83b9a030-b10c-4a59-a8d0-a632b4cfe5d2",
        "name": "Filter Recent Failures",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          448,
          0
        ]
      },
      {
        "parameters": {
          "conditions": {
            "options": {
              "caseSensitive": true,
              "leftValue": "",
              "typeValidation": "strict"
            },
            "conditions": [
              {
                "id": "a76d10a7-1313-467e-9648-471b296229a3",
                "leftValue": "={{ $json.hasFailures }}",
                "rightValue": true,
                "operator": {
                  "type": "boolean",
                  "operation": "equal"
                }
              }
            ],
            "combinator": "and"
          }
        },
        "id": "fea1e46a-e3af-4d60-9f21-a79593fdef71",
        "name": "Has Failures?",
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.2,
        "position": [
          672,
          0
        ]
      },
      {
        "parameters": {
          "jsCode": "const d = $input.first().json;\n// Fingerprint = sorted workflow names joined — stable across retriggers\nconst fingerprint = (d.failures || [])\n  .map(f => f.workflowName)\n  .sort()\n  .join('|') || 'unknown';\nreturn [{ json: { ...d, fingerprint } }];"
        },
        "id": "cf9ad5c7-163c-4f06-8300-48499e70072c",
        "name": "Build Fingerprint",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          896,
          -120
        ]
      },
      {
        "parameters": {
          "operation": "executeQuery",
          "query": "SELECT fingerprint, last_seen FROM n8n_health_dedup WHERE fingerprint = '{{ $json.fingerprint }}' AND last_seen > NOW() - INTERVAL '1 hour' LIMIT 1;",
          "options": {}
        },
        "id": "faef0ff7-e592-463d-9f98-460591038799",
        "name": "Lookup Dedup",
        "type": "n8n-nodes-base.postgres",
        "typeVersion": 2.5,
        "position": [
          1120,
          -120
        ],
        "credentials": {
          "postgres": {
            "id": "n9svoXemqSZoNNUB",
            "name": "Postgres account"
          }
        },
        "continueOnFail": true
      },
      {
        "parameters": {
          "jsCode": "const alertData = $('Build Fingerprint').first().json;\nconst rows = $input.all().filter(r => r.json && r.json.fingerprint);\nconst alreadyNotified = rows.length > 0;\nreturn [{ json: { ...alertData, alreadyNotified, shouldNotify: !alreadyNotified } }];"
        },
        "id": "1fdb0262-7d45-4f30-8dd4-2445ab569df1",
        "name": "Check Already Notified",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          1344,
          -120
        ]
      },
      {
        "parameters": {
          "conditions": {
            "options": {
              "caseSensitive": true,
              "leftValue": "",
              "typeValidation": "strict"
            },
            "conditions": [
              {
                "id": "b1e77af5-6875-47dd-97af-8e13958a7217",
                "leftValue": "={{ $json.shouldNotify }}",
                "rightValue": true,
                "operator": {
                  "type": "boolean",
                  "operation": "equal"
                }
              }
            ],
            "combinator": "and"
          }
        },
        "id": "258f7606-5252-4e78-8398-89970d5cea74",
        "name": "Should Notify?",
        "type": "n8n-nodes-base.if",
        "typeVersion": 2.2,
        "position": [
          1568,
          -120
        ]
      },
      {
        "parameters": {
          "operation": "executeQuery",
          "query": "INSERT INTO n8n_health_dedup (fingerprint, last_seen, workflow_names) VALUES ('{{ $json.fingerprint }}', NOW(), '{{ $json.failures.map(f => f.workflowName).join(\", \") }}') ON CONFLICT (fingerprint) DO UPDATE SET last_seen = NOW(), workflow_names = EXCLUDED.workflow_names;",
          "options": {}
        },
        "id": "dc7c3c90-1cb0-4b3f-b462-58401411e976",
        "name": "Upsert Dedup Record",
        "type": "n8n-nodes-base.postgres",
        "typeVersion": 2.5,
        "position": [
          1792,
          -120
        ],
        "credentials": {
          "postgres": {
            "id": "n9svoXemqSZoNNUB",
            "name": "Postgres account"
          }
        }
      },
      {
        "parameters": {
          "jsCode": "const d = $('Build Fingerprint').first().json;\nconst lines = (d.failures || []).map(f =>\n  `  • ${f.workflowName}\\n    ${f.errorMessage.substring(0, 120)}`\n);\nconst body = `${d.count} workflow${d.count !== 1 ? 's' : ''} failed in the past hour:\\n\\n${lines.join('\\n')}\\n\\nhttps://n8n.paccoco.com`;\nreturn [{ json: { title: `⚠️ n8n: ${d.count} Workflow Failure${d.count !== 1 ? 's' : ''}`, message: body, priority: 7 } }];"
        },
        "id": "7d040998-67c2-4888-937c-6d82e41056d1",
        "name": "Format Notification",
        "type": "n8n-nodes-base.code",
        "typeVersion": 2,
        "position": [
          2016,
          -120
        ]
      },
      {
        "parameters": {
          "message": "={{ $json.message }}",
          "additionalFields": {
            "priority": "={{ $json.priority }}",
            "title": "={{ $json.title }}"
          },
          "options": {
            "contentType": "text/plain"
          }
        },
        "id": "2569776a-c0a8-48cb-8615-af95daf53292",
        "name": "Push to Gotify",
        "type": "n8n-nodes-base.gotify",
        "typeVersion": 1,
        "position": [
          2240,
          -120
        ],
        "credentials": {
          "gotifyApi": {
            "id": "mMegDxfmMUfbOrnF",
            "name": "n8n Health"
          }
        }
      }
    ],
    "connections": {
      "Every 15 Minutes": {
        "main": [
          [
            {
              "node": "Fetch Failed Executions",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Fetch Failed Executions": {
        "main": [
          [
            {
              "node": "Filter Recent Failures",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Filter Recent Failures": {
        "main": [
          [
            {
              "node": "Has Failures?",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Has Failures?": {
        "main": [
          [
            {
              "node": "Build Fingerprint",
              "type": "main",
              "index": 0
            }
          ],
          []
        ]
      },
      "Build Fingerprint": {
        "main": [
          [
            {
              "node": "Lookup Dedup",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Lookup Dedup": {
        "main": [
          [
            {
              "node": "Check Already Notified",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Check Already Notified": {
        "main": [
          [
            {
              "node": "Should Notify?",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Should Notify?": {
        "main": [
          [
            {
              "node": "Upsert Dedup Record",
              "type": "main",
              "index": 0
            }
          ],
          []
        ]
      },
      "Upsert Dedup Record": {
        "main": [
          [
            {
              "node": "Format Notification",
              "type": "main",
              "index": 0
            }
          ]
        ]
      },
      "Format Notification": {
        "main": [
          [
            {
              "node": "Push to Gotify",
              "type": "main",
              "index": 0
            }
          ]
        ]
      }
    },
    "authors": "Wilfred Fizzlepoof",
    "name": null,
    "description": null,
    "autosaved": false,
    "workflowPublishHistory": [
      {
        "createdAt": "2026-05-22T21:51:07.244Z",
        "id": 317,
        "workflowId": "BLJVcnMRNMdswJQN",
        "versionId": "8cf46654-a773-4921-8745-3169eb7709f3",
        "event": "deactivated",
        "userId": "47b2227f-2fc2-4a08-bd35-ea157b92df0d"
      },
      {
        "createdAt": "2026-05-22T21:51:07.263Z",
        "id": 318,
        "workflowId": "BLJVcnMRNMdswJQN",
        "versionId": "8cf46654-a773-4921-8745-3169eb7709f3",
        "event": "activated",
        "userId": "47b2227f-2fc2-4a08-bd35-ea157b92df0d"
      }
    ]
  }
}
