DEV Community

Alex Kane
Alex Kane

Posted on

n8n for InsurTech/Insurance SaaS Vendors: 5 Automations for NAIC, GLBA, TCPA, and Solvency II Compliance (Free Workflow JSON)

Every insurance SaaS vendor processes policyholder PII, claims data, and pricing logic that touches at least three independent regulatory frameworks simultaneously. Here are five production-ready n8n workflows that keep your platform compliant — full import-ready JSON included.

The compliance stack for InsurTech SaaS

Regulation Effective Key Clock
NAIC Model Data Security Law #668 Varies by state (adopted 22+ states) 3-day investigation + 10-day policyholder notification
GLBA Safeguards Rule 16 CFR Part 314 June 9, 2023 (amended) Annual risk assessment + vendor oversight program
TCPA FCC 23-107 one-to-one consent January 27, 2025 Per-lead consent required — no batch consent chains
HIPAA 45 CFR §164 (group health plans) Ongoing 60-day individual + HHS notification on breach
NY DFS 23 NYCRR 500 (Nov 2023) Nov 1, 2023 72-hour material cybersecurity event notification
EU Solvency II 2009/138/EC Ongoing Annual SFCR + quarterly QRT reporting
FCRA 15 USC §1681m adverse action Ongoing 5-day adverse action notice to consumer
NY Ins Law §3420 Ongoing 15-day proof-of-loss acknowledgment

The GLBA Safeguards Rule (June 2023 amendments) explicitly requires a written service provider oversight program — your iPaaS vendor (Zapier, Make) is a covered service provider under §314.4(f). That means a contract, an annual review, and documented controls. Self-hosted n8n eliminates the vendor from scope entirely.

The TCPA FCC 23-107 one-to-one consent rule (effective January 27, 2025) ended the batch-consent model: each consumer must give consent to each seller individually before receiving automated calls or texts. Insurance SaaS platforms that batch SMS through shared cloud automation tools cannot demonstrate per-lead consent chain traceability to the FCC.

Workflow 1: Insurance SaaS New Customer Onboarding Drip

Seven customer tiers with per-tier compliance flags at Day 0, Day 3, and Day 8:

{
  "name": "Insurance SaaS New Customer Onboarding Drip",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "insurance-customer-onboarding",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "n1",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst customer = $json;\nconst tier = customer.tier || 'INSURTECH_STARTUP';\nconst flags = {\n  PROPERTY_CASUALTY_SAAS: ['NAIC_DATA_SECURITY_MODEL_LAW','GLBA_SAFEGUARDS_16_CFR_314','NY_DFS_500_NOV2023','TCPA_FCC_23107_ONE_TO_ONE','FCRA_ADVERSE_ACTION_15USC1681M','CCPA_CPRA'],\n  LIFE_HEALTH_SAAS: ['NAIC_DATA_SECURITY_MODEL_LAW','HIPAA_45CFR164','GLBA_SAFEGUARDS_16_CFR_314','FCRA_ADVERSE_ACTION_15USC1681M','NY_DFS_500_NOV2023','TCPA_FCC_23107_ONE_TO_ONE'],\n  COMMERCIAL_LINES_SAAS: ['NAIC_DATA_SECURITY_MODEL_LAW','GLBA_SAFEGUARDS_16_CFR_314','GDPR_ART9_INSURANCE_DATA','SOX_ICFR_IF_PUBLIC','TCPA_FCC_23107_ONE_TO_ONE'],\n  REINSURANCE_SAAS: ['EU_SOLVENCY_II_2009_138_EC','NAIC_DATA_SECURITY_MODEL_LAW','GDPR_ART9_INSURANCE_DATA','SOX_ICFR_IF_PUBLIC','GLBA_SAFEGUARDS_16_CFR_314'],\n  INSURTECH_MGA_SAAS: ['NAIC_DATA_SECURITY_MODEL_LAW','GLBA_SAFEGUARDS_16_CFR_314','TCPA_FCC_23107_ONE_TO_ONE','FCRA_ADVERSE_ACTION_15USC1681M','STATE_SURPLUS_LINES_LICENSE'],\n  CLAIMS_MANAGEMENT_SAAS: ['NAIC_DATA_SECURITY_MODEL_LAW','HIPAA_45CFR164','TCPA_FCC_23107_ONE_TO_ONE','FCRA_ADVERSE_ACTION_15USC1681M','NY_INS_LAW_3420_PROOF_OF_LOSS'],\n  INSURTECH_STARTUP: ['NAIC_DATA_SECURITY_MODEL_LAW','GLBA_SAFEGUARDS_16_CFR_314','TCPA_FCC_23107_ONE_TO_ONE']\n};\nconst tierFlags = flags[tier] || flags['INSURTECH_STARTUP'];\nconst naic = tierFlags.includes('NAIC_DATA_SECURITY_MODEL_LAW') ? 'NAIC Model Data Security Law #668 investigation coordination required.' : '';\nconst hipaa = tierFlags.includes('HIPAA_45CFR164') ? 'HIPAA 45 CFR \u00a7164: PHI processing in automation vendor = Business Associate Agreement required before go-live.' : '';\nconst solvency = tierFlags.includes('EU_SOLVENCY_II_2009_138_EC') ? 'EU Solvency II 2009/138/EC Pillar 3 SFCR: ORSA data through Zapier/Make = regulatory reporting data out of EU perimeter.' : '';\nconst glba = tierFlags.includes('GLBA_SAFEGUARDS_16_CFR_314') ? 'GLBA Safeguards Rule 16 CFR Part 314 (June 2023): service provider oversight program required; Zapier/Make = covered service provider.' : '';\nconst tcpa = tierFlags.includes('TCPA_FCC_23107_ONE_TO_ONE') ? 'TCPA FCC 23-107 (Jan 27 2025): one-to-one consent required per lead; batch SMS/email through shared iPaaS = consent chain traceability risk.' : '';\nconst ny3420 = tierFlags.includes('NY_INS_LAW_3420_PROOF_OF_LOSS') ? 'NY Ins Law \u00a73420: 30-day proof-of-loss clock + 15-day acknowledgment. Claims automation in third-party cloud creates audit gap.' : '';\nreturn [{\n  json: {\n    ...customer,\n    tier,\n    compliance_flags: tierFlags,\n    naic_note: naic,\n    hipaa_note: hipaa,\n    solvency_note: solvency,\n    glba_note: glba,\n    tcpa_note: tcpa,\n    ny3420_note: ny3420,\n    day0_subject: `Welcome to FlowKit, ${customer.company_name} \u2014 Your Insurance SaaS Automation Is Live`,\n    day0_body: `Hi ${customer.contact_name},\\n\\nYour n8n automation platform is live. As a ${tier.replace(/_/g,' ')} vendor, your key compliance obligations are:\\n${naic}\\n${hipaa || glba}\\n${tcpa}\\n\\nAll workflow data stays in your VPC \u2014 no policyholder PII leaves your perimeter.\\n\\nYour onboarding specialist: compliance@flowkit.io\\n\\nFlowKit`,\n    onboarded_at: new Date().toISOString()\n  }\n}];\n",
        "mode": "runOnceForAllItems"
      },
      "id": "n2",
      "name": "Tier & Compliance Classifier",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        320,
        300
      ]
    },
    {
      "parameters": {
        "fromEmail": "onboarding@flowkit.io",
        "toEmail": "={{ $json.contact_email }}",
        "subject": "={{ $json.day0_subject }}",
        "text": "={{ $json.day0_body }}",
        "options": {}
      },
      "id": "n3",
      "name": "Day 0 Welcome Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        540,
        300
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SHEETS_ID"
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Onboarding"
        },
        "columns": {
          "mappingMode": "autoMapInputData",
          "value": {},
          "matchingColumns": []
        },
        "options": {}
      },
      "id": "n4",
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        760,
        300
      ]
    },
    {
      "parameters": {
        "amount": 3,
        "unit": "days"
      },
      "id": "n5",
      "name": "Wait 3 Days",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        540,
        460
      ]
    },
    {
      "parameters": {
        "fromEmail": "onboarding@flowkit.io",
        "toEmail": "={{ $json.contact_email }}",
        "subject": "Day 3: Connect Your First Insurance API to n8n",
        "text": "Hi {{ $json.contact_name }},\n\nDay 3 check-in: have you connected your rating API or policy admin system yet?\n\nFor PROPERTY_CASUALTY and LIFE_HEALTH tiers, HIPAA/GLBA requires all API credentials stored in n8n credential vault \u2014 not hard-coded.\n\nFlowKit",
        "options": {}
      },
      "id": "n6",
      "name": "Day 3 Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        760,
        460
      ]
    },
    {
      "parameters": {
        "amount": 4,
        "unit": "days"
      },
      "id": "n7",
      "name": "Wait 4 Days",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        540,
        620
      ]
    },
    {
      "parameters": {
        "fromEmail": "onboarding@flowkit.io",
        "toEmail": "={{ $json.contact_email }}",
        "subject": "Day 8: Your NAIC Data Security Incident Response Workflow Is Ready",
        "text": "Hi {{ $json.contact_name }},\n\nWeek 1 complete. Your NAIC Model Data Security Law #668 incident notification pipeline is pre-configured \u2014 3-day investigation report and 10-day policyholder notification clocks start automatically on webhook trigger.\n\nSelf-hosted n8n = you control the audit trail your state DOI will request during examination.\n\nFlowKit",
        "options": {}
      },
      "id": "n8",
      "name": "Day 8 Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        760,
        620
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"onboarding_started\"}",
        "options": {}
      },
      "id": "n9",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        320,
        460
      ]
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Tier & Compliance Classifier",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tier & Compliance Classifier": {
      "main": [
        [
          {
            "node": "Day 0 Welcome Email",
            "type": "main",
            "index": 0
          },
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Day 0 Welcome Email": {
      "main": [
        [
          {
            "node": "Log to Sheets",
            "type": "main",
            "index": 0
          },
          {
            "node": "Wait 3 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 3 Days": {
      "main": [
        [
          {
            "node": "Day 3 Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Day 3 Email": {
      "main": [
        [
          {
            "node": "Wait 4 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 4 Days": {
      "main": [
        [
          {
            "node": "Day 8 Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Tier flags: PROPERTY_CASUALTY_SAAS gets NAIC + GLBA + NY DFS + TCPA + FCRA + CCPA. LIFE_HEALTH_SAAS adds HIPAA (group health plans are covered entities under 45 CFR §160.103). REINSURANCE_SAAS gets EU Solvency II instead of TCPA (reinsurers don't contact consumers directly). CLAIMS_MANAGEMENT_SAAS gets NY Ins Law §3420 proof-of-loss clock annotation.

Workflow 2: Insurance API & Pricing Engine Health Monitor

Five endpoint types, each annotated with the regulation that makes downtime legally material:

{
  "name": "Insurance SaaS API & Pricing Engine Health Monitor",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 5
            }
          ]
        }
      },
      "id": "h1",
      "name": "Every 5 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nreturn [\n  { json: { endpoint_name: 'Rating Engine API', url: 'https://rating-api.internal/health', regulation: 'GLBA 16 CFR \u00a7314.4(f) \u2014 vendor API failure = safeguards gap', tier: 'PROPERTY_CASUALTY_SAAS' } },\n  { json: { endpoint_name: 'Policy Admin System', url: 'https://pas.internal/api/health', regulation: 'NAIC Data Security Model Law #668 \u00a74(F) \u2014 PAS outage = policyholder data access failure', tier: 'LIFE_HEALTH_SAAS' } },\n  { json: { endpoint_name: 'Claims Processing API', url: 'https://claims-api.internal/health', regulation: 'NY Ins Law \u00a73420 \u2014 15-day acknowledgment clock cannot pause for API downtime', tier: 'CLAIMS_MANAGEMENT_SAAS' } },\n  { json: { endpoint_name: 'HIPAA Eligibility Verification API', url: 'https://eligibility-api.internal/health', regulation: 'HIPAA 45 CFR \u00a7164.312(a)(2)(ii) \u2014 emergency access procedure required on HIPAA API failure', tier: 'LIFE_HEALTH_SAAS' } },\n  { json: { endpoint_name: 'Solvency II ORSA Reporting API', url: 'https://orsa-api.internal/health', regulation: 'EU Solvency II Art.45 ORSA \u2014 regulatory reporting API failure = Pillar 2 ORSA submission risk', tier: 'REINSURANCE_SAAS' } }\n];\n",
        "mode": "runOnceForAllItems"
      },
      "id": "h2",
      "name": "Build Endpoint List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "method": "GET",
        "url": "={{ $json.url }}",
        "options": {
          "timeout": 8000,
          "response": {
            "response": {
              "neverError": true
            }
          }
        }
      },
      "id": "h3",
      "name": "Ping Each Endpoint",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst result = $json;\nconst statusCode = result.statusCode || 0;\nconst endpoint = $('Build Endpoint List').item.json;\nlet status = 'UP';\nlet severity = 'OK';\nif (statusCode === 0 || statusCode >= 500) { status = 'DOWN'; severity = 'CRITICAL'; }\nelse if (statusCode >= 400) { status = 'DEGRADED'; severity = 'WARNING'; }\nelse if (result.responseTime > 5000) { status = 'SLOW'; severity = 'WARNING'; }\nreturn [{ json: { ...endpoint, status, severity, statusCode, checked_at: new Date().toISOString(), alert_required: severity !== 'OK' } }];\n",
        "mode": "runOnceForEachItem"
      },
      "id": "h4",
      "name": "Evaluate Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.alert_required }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "h5",
      "name": "Alert Required?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        900,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "predefinedCredentialType",
        "resource": "channel",
        "operation": "post",
        "channel": "#insurtech-ops-alerts",
        "text": "={{ $json.severity }}: {{ $json.endpoint_name }} is {{ $json.status }} (HTTP {{ $json.statusCode }}) \u2014 Regulatory risk: {{ $json.regulation }}",
        "otherOptions": {}
      },
      "id": "h6",
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        1100,
        200
      ]
    }
  ],
  "connections": {
    "Every 5 Minutes": {
      "main": [
        [
          {
            "node": "Build Endpoint List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Endpoint List": {
      "main": [
        [
          {
            "node": "Ping Each Endpoint",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Ping Each Endpoint": {
      "main": [
        [
          {
            "node": "Evaluate Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Status": {
      "main": [
        [
          {
            "node": "Alert Required?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert Required?": {
      "main": [
        [
          {
            "node": "Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The NAIC Model Data Security Law §4(F) requires covered entities to implement access controls and monitoring — 'the API went down' is not an acceptable response to an examiner asking why policyholder records were inaccessible. The NY Ins Law §3420 15-day acknowledgment clock does not pause for API downtime.

Workflow 3: NAIC/GLBA/TCPA/HIPAA Compliance Deadline Tracker

Fourteen deadline types covering the full InsurTech regulatory stack:

{
  "name": "NAIC/GLBA/TCPA/HIPAA Compliance Deadline Tracker",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1-5"
            }
          ]
        }
      },
      "id": "d1",
      "name": "Weekdays 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "operation": "read",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_SHEETS_ID"
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "InsuranceDeadlines"
        },
        "options": {}
      },
      "id": "d2",
      "name": "Read Deadlines Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst now = new Date();\nconst deadlines = $input.all().map(item => item.json);\nconst DEADLINE_TYPES = [\n  'NAIC_DATA_SECURITY_INVESTIGATION_3DAY',\n  'NAIC_POLICYHOLDER_NOTIFICATION_10DAY',\n  'GLBA_SAFEGUARDS_ANNUAL_RISK_ASSESSMENT',\n  'GLBA_SAFEGUARDS_VENDOR_OVERSIGHT_REVIEW',\n  'NY_DFS_500_ANNUAL_CERT_FEB15',\n  'NY_DFS_500_72H_INCIDENT_NOTIFICATION',\n  'TCPA_ONE_TO_ONE_CONSENT_AUDIT',\n  'HIPAA_BAA_ANNUAL_REVIEW',\n  'HIPAA_BREACH_60DAY_HHS_NOTIFICATION',\n  'FCRA_ADVERSE_ACTION_NOTICE_5DAY',\n  'EU_SOLVENCY_II_SFCR_ANNUAL',\n  'EU_SOLVENCY_II_QRT_QUARTERLY',\n  'NY_INS_LAW_3420_15DAY_ACK',\n  'STATE_LICENSE_RENEWAL',\n];\nconst alerts = [];\nfor (const dl of deadlines) {\n  const due = new Date(dl.due_date);\n  const daysLeft = Math.floor((due - now) / 86400000);\n  let urgency = null;\n  if (daysLeft < 0) urgency = 'OVERDUE';\n  else if (daysLeft <= 1) urgency = 'CRITICAL';\n  else if (daysLeft <= 7) urgency = 'URGENT';\n  else if (daysLeft <= 21) urgency = 'WARNING';\n  else if (daysLeft <= 30) urgency = 'NOTICE';\n  if (urgency) alerts.push({ ...dl, urgency, days_left: daysLeft });\n}\nif (alerts.length === 0) return [{ json: { no_alerts: true } }];\nreturn alerts.map(a => ({ json: a }));\n",
        "mode": "runOnceForAllItems"
      },
      "id": "d3",
      "name": "Calculate Urgency",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.no_alerts }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "d4",
      "name": "Any Alerts?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "predefinedCredentialType",
        "resource": "channel",
        "operation": "post",
        "channel": "#insurance-compliance",
        "text": "={{ $json.urgency }}: {{ $json.deadline_type }} \u2014 {{ $json.days_left }} days left. Owner: {{ $json.owner }}. Regulation: {{ $json.regulation_cite }}.",
        "otherOptions": {}
      },
      "id": "d5",
      "name": "Slack Compliance Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        900,
        200
      ]
    }
  ],
  "connections": {
    "Weekdays 8AM": {
      "main": [
        [
          {
            "node": "Read Deadlines Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Deadlines Sheet": {
      "main": [
        [
          {
            "node": "Calculate Urgency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Urgency": {
      "main": [
        [
          {
            "node": "Any Alerts?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Alerts?": {
      "main": [
        [
          {
            "node": "Slack Compliance Alert",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The NY DFS 500.17 February 15 annual certification is the most commonly missed: it covers the prior calendar year, it is a Superintendent of Financial Services submission, and it requires documented attestation from a senior officer. Late filing = examination finding. The TCPA one-to-one consent audit (quarterly) reflects the FCC's enforcement posture post-FCC 23-107: carriers are checking whether platforms can demonstrate per-lead consent logs, not just policy acknowledgments.

Workflow 4: Insurance Regulatory Incident & Breach Pipeline

Eight incident types, each mapped to the specific regulatory clock that starts on detection:

{
  "name": "Insurance Regulatory Incident & Breach Pipeline",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "insurance-incident",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "i1",
      "name": "Incident Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst incident = $json;\nconst INCIDENT_CLOCKS = {\n  NAIC_DATA_SECURITY_BREACH: { immediateSlack: true, investigationDays: 3, policyholderDays: 10, label: 'NAIC Model Law #668: 3-day investigation + 10-day policyholder notification' },\n  NY_DFS_500_MATERIAL_CYBERSECURITY_EVENT: { immediateSlack: true, notificationHours: 72, label: 'NY DFS 23 NYCRR 500.17: 72-hour notification to NYDFS Superintendent' },\n  HIPAA_PHI_BREACH: { immediateSlack: true, individualDays: 60, hhs_days: 60, label: 'HIPAA 45 CFR \u00a7164.408: 60-day individual + HHS notification' },\n  GLBA_SAFEGUARDS_BREACH: { immediateSlack: true, label: 'GLBA Safeguards 16 CFR \u00a7314.4(h): notification to affected customers ASAP' },\n  TCPA_CONSENT_VIOLATION: { immediateSlack: false, auditRequired: true, label: 'TCPA FCC 23-107: one-to-one consent violation \u2014 $500/call statutory damages' },\n  FCRA_ADVERSE_ACTION: { immediateSlack: false, noticeDays: 5, label: 'FCRA 15 USC \u00a71681m: 5-day adverse action notice to consumer' },\n  SOLVENCY_II_BREACH: { immediateSlack: true, label: 'EU Solvency II Art.136: immediately notify EIOPA supervisory authority' },\n  NY_INS_LAW_3420_CLAIM_DELAY: { immediateSlack: false, ackDays: 15, label: 'NY Ins Law \u00a73420: 15-day proof-of-loss acknowledgment clock' },\n};\nconst clock = INCIDENT_CLOCKS[incident.incident_type] || { label: 'Unknown incident type', immediateSlack: true };\nconst now = new Date();\nconst deadline = {};\nif (clock.investigationDays) deadline.investigation = new Date(now.getTime() + clock.investigationDays * 86400000).toISOString();\nif (clock.policyholderDays) deadline.policyholder_notification = new Date(now.getTime() + clock.policyholderDays * 86400000).toISOString();\nif (clock.notificationHours) deadline.regulator_notification = new Date(now.getTime() + clock.notificationHours * 3600000).toISOString();\nif (clock.hhs_days) deadline.hhs_notification = new Date(now.getTime() + clock.hhs_days * 86400000).toISOString();\nif (clock.ackDays) deadline.ack_deadline = new Date(now.getTime() + clock.ackDays * 86400000).toISOString();\nreturn [{ json: { ...incident, clock_label: clock.label, immediate_slack: clock.immediateSlack, deadlines: deadline, detected_at: now.toISOString() } }];\n",
        "mode": "runOnceForAllItems"
      },
      "id": "i2",
      "name": "Map Regulatory Clocks",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        300,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "leftValue": "={{ $json.immediate_slack }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "i3",
      "name": "Immediate Alert?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "authentication": "predefinedCredentialType",
        "resource": "channel",
        "operation": "post",
        "channel": "#insurance-incidents-critical",
        "text": "INSURANCE INCIDENT: {{ $json.incident_type }} \u2014 {{ $json.clock_label }}. Deadlines: {{ JSON.stringify($json.deadlines) }}",
        "otherOptions": {}
      },
      "id": "i4",
      "name": "Slack Critical",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.2,
      "position": [
        700,
        200
      ]
    },
    {
      "parameters": {
        "operation": "insert",
        "table": "insurance_incidents",
        "columns": "incident_type,clock_label,deadlines,detected_at,company_name",
        "options": {}
      },
      "id": "i5",
      "name": "Postgres Audit Log",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        700,
        460
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "{\"status\": \"incident_logged\", \"deadlines\": \"{{ JSON.stringify($json.deadlines) }}\"}",
        "options": {}
      },
      "id": "i6",
      "name": "Respond 200",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        900,
        300
      ]
    }
  ],
  "connections": {
    "Incident Webhook": {
      "main": [
        [
          {
            "node": "Map Regulatory Clocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Regulatory Clocks": {
      "main": [
        [
          {
            "node": "Immediate Alert?",
            "type": "main",
            "index": 0
          },
          {
            "node": "Postgres Audit Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Immediate Alert?": {
      "main": [
        [
          {
            "node": "Slack Critical",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Respond 200",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Critical": {
      "main": [
        [
          {
            "node": "Respond 200",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The HIPAA 60-day breach notification clock (45 CFR §164.408) runs from the date the covered entity discovers the breach, not from the date it determines the breach was reportable. Group health plans often misread this as 60 days from determination — OCR enforcement actions have consistently held that discovery starts the clock. For NAIC states: the 3-day investigation report goes to the DOI Commissioner, and the 10-day policyholder notification is a separate obligation — missing either is an independent violation.

Workflow 5: Weekly Insurance SaaS Compliance KPI Dashboard

RAG-rated weekly report to CCO, BCC'd to CISO:

{
  "name": "Weekly Insurance SaaS Compliance KPI Dashboard",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1"
            }
          ]
        }
      },
      "id": "k1",
      "name": "Monday 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        100,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT incident_type, COUNT(*) as count, MAX(detected_at) as latest FROM insurance_incidents WHERE detected_at > NOW() - INTERVAL '7 days' GROUP BY incident_type ORDER BY count DESC;",
        "options": {}
      },
      "id": "k2",
      "name": "Query Incidents",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        300,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT deadline_type, COUNT(*) as overdue_count FROM insurance_deadlines WHERE due_date < NOW() AND resolved = false GROUP BY deadline_type;",
        "options": {}
      },
      "id": "k3",
      "name": "Query Overdue",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        300,
        400
      ]
    },
    {
      "parameters": {
        "mode": "combine",
        "combinationMode": "mergeByPosition",
        "options": {}
      },
      "id": "k4",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3,
      "position": [
        500,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "\nconst incidents = $('Query Incidents').all().map(i => i.json);\nconst overdue = $('Query Overdue').all().map(o => o.json);\nconst overdueCount = overdue.reduce((s, o) => s + parseInt(o.overdue_count || 0), 0);\nconst naic_breach = incidents.filter(i => i.incident_type === 'NAIC_DATA_SECURITY_BREACH');\nconst hipaa_breach = incidents.filter(i => i.incident_type === 'HIPAA_PHI_BREACH');\nconst nydfs_event = incidents.filter(i => i.incident_type === 'NY_DFS_500_MATERIAL_CYBERSECURITY_EVENT');\nconst rag = (overdueCount > 3 || naic_breach.length > 0 || hipaa_breach.length > 0) ? 'RED' : (overdueCount > 0 || nydfs_event.length > 0) ? 'AMBER' : 'GREEN';\nconst html = `<html><body style=\"font-family:sans-serif;max-width:700px;\">\n<h2>Insurance SaaS Compliance KPI \u2014 Week of ${new Date().toISOString().split('T')[0]}</h2>\n<p><strong>Overall Status:</strong> <span style=\"color:${rag==='RED'?'red':rag==='AMBER'?'orange':'green'}\">${rag}</span></p>\n<h3>Incidents (Last 7 Days)</h3>\n<ul>\n${incidents.map(i => `<li>${i.incident_type}: ${i.count} (latest: ${i.latest})</li>`).join('')}\n${incidents.length === 0 ? '<li>No incidents \u2014 all clear</li>' : ''}\n</ul>\n<h3>Overdue Compliance Items (${overdueCount})</h3>\n<ul>\n${overdue.map(o => `<li>${o.deadline_type}: ${o.overdue_count} overdue</li>`).join('')}\n${overdue.length === 0 ? '<li>No overdue items</li>' : ''}\n</ul>\n<p style=\"font-size:12px;color:#666;\">Self-hosted n8n \u2014 policyholder PII never leaves your VPC. NAIC DOI examinations can request audit trail directly from your instance.</p>\n</body></html>`;\nreturn [{ json: { html, rag, incident_count: incidents.length, overdue_count: overdueCount } }];\n",
        "mode": "runOnceForAllItems"
      },
      "id": "k5",
      "name": "Build KPI Report",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        700,
        300
      ]
    },
    {
      "parameters": {
        "fromEmail": "reports@flowkit.io",
        "toEmail": "cco@yourcompany.com",
        "subject": "Weekly Insurance SaaS Compliance KPI",
        "emailType": "html",
        "html": "={{ $json.html }}",
        "options": {
          "bcc": "ciso@yourcompany.com"
        }
      },
      "id": "k6",
      "name": "Email KPI to CCO",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2.1,
      "position": [
        900,
        300
      ]
    }
  ],
  "connections": {
    "Monday 8AM": {
      "main": [
        [
          {
            "node": "Query Incidents",
            "type": "main",
            "index": 0
          },
          {
            "node": "Query Overdue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Incidents": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Overdue": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Build KPI Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build KPI Report": {
      "main": [
        [
          {
            "node": "Email KPI to CCO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Why BCC the CISO? The GLBA Safeguards Rule §314.4(h) requires the Board (or senior officer equivalent) to receive a written report on the information security program at least annually. Weekly KPIs create the audit trail that satisfies both the GLBA report requirement and the NY DFS 500.4(b) annual report to board obligation.

Self-hosting: why InsurTech SaaS vendors choose on-premise n8n

Scenario Zapier/Make (cloud) Self-hosted n8n
GLBA service provider oversight Zapier/Make = covered service provider requiring §314.4(f) oversight n8n on your VPC = no third-party in scope
NAIC DOI examination Examiner requests workflow execution logs Logs in your Postgres — produced directly
TCPA consent chain Batch automation breaks per-lead traceability Per-lead webhook, per-lead log in your DB
HIPAA BAA BAA with Zapier/Make; data transits their servers No BAA needed; PHI never leaves your cluster
Solvency II ORSA data ORSA inputs transit third-party cloud ORSA data stays in EU VPC
SOX ICFR (if public) Automation vendor = IT general control scope Self-hosted = git-versioned workflow = audit trail

Get the full 15-template FlowKit bundle

These five workflows are part of the FlowKit n8n Automation Bundle — 15 production-ready templates at stripeai.gumroad.com.

Individual templates: $12–$29. Full bundle: $97.

Top comments (0)