DEV Community

Alex Kane
Alex Kane

Posted on

n8n for US InsurTech SaaS Vendors: 5 Automations for NAIC MDL-668, SOC 2, and State DOI Third-Party Compliance (Free Workflow JSON)

If you sell software to insurance companies — policy admin systems, claims management platforms, actuarial data tools, carrier API integration layers, surplus lines technology — your carrier customers will put you through a compliance gauntlet.

SOC 2 Type II report. NAIC MDL-668 (Insurance Data Security Model Law) third-party service provider attestation. State Department of Insurance vendor registration in certain states. GLBA NPI data handling agreements. Annual vendor risk assessments — sometimes quarterly for Tier 1 carriers. And when something goes wrong at your end, your carrier customer has to notify their state DOI — often within 72 hours of your disclosure to them.

This is the compliance stack every US InsurTech SaaS vendor deals with, whether or not they've automated it yet. Note the distinction: these workflows are for technology vendors selling INTO insurance carriers — not for carriers themselves. The obligations are different: you're subject to carrier vendor assessments, GLBA as a service provider, NAIC MDL-668 as a third-party, and state DOI vendor registration requirements.

Here are 5 n8n workflows that handle the operational burden — keeping your team ahead of deadlines, monitoring carrier integrations, and responding correctly when incidents hit.

All workflows are self-hostable. For insurance vendors, that matters: when a carrier puts your n8n instance in scope for their MDL-668 third-party assessment, a self-hosted deployment means carrier NPI data stays in your own enclave — not a cloud iPaaS you have to justify in the questionnaire.


Why Self-Hosted n8n for InsurTech Vendor Compliance

Cloud iPaaS tools (Zapier, Make.com) route carrier data through their infrastructure. Every carrier NPI field, every policy record, every claims data element that passes through a third-party workflow engine becomes a data residency and MDL-668 scope problem — and a new sub-processor you have to justify in your SOC 2 Type II vendor risk section.

Self-hosted n8n keeps data in your enclave. Git-versioned workflows satisfy SOC 2 Change Management (CC8.1) audits. Your incident response audit trail is yours — not a Zapier activity log you have to request from a vendor and then explain to a carrier's CISO.


Workflow 1: Carrier Customer Onboarding Drip (Segmented by Carrier Type + MDL-668 Profile)

Problem: A new P&C carrier signs up. They immediately need your SOC 2 Type II report, your completed vendor questionnaire (often CAIQ or a bespoke carrier security assessment), and your GLBA Data Processing Agreement. If that's a manual process — a Slack message to someone, a follow-up email three days later — you're already failing the carrier's onboarding experience and their compliance team's timeline.

What it does: Triggered when a new carrier is added to your CRM/spreadsheet. Segments by carrier type (P&C_CARRIER, LIFE_ANNUITY_CARRIER, HEALTH_PLAN_SPONSOR, SURPLUS_LINES_MGA, CAPTIVE_MANAGER) and compliance profile (NAIC_MDL668_SCOPE, GLBA_NPI_HANDLER, STATE_DOI_APPROVED_VENDOR, SOC2_REQUIRED, ISO27001_REQUIRED, HIPAA_IF_HEALTH, PCI_DSS_IF_BILLING). Day 0 sends a carrier-type-specific welcome with MDL-668 vendor note. Day 3 delivers the pre-filled vendor questionnaire, SOC 2 report link, and GLBA DPA. Day 7 books the QBR.

{
  "id": "insurtech-vendor-onboarding-drip-001",
  "name": "InsurTech SaaS Vendor \u2014 Carrier Customer Onboarding Drip",
  "nodes": [
    {
      "id": "n1",
      "name": "GoogleSheets Trigger",
      "type": "n8n-nodes-base.googleSheetsTrigger",
      "typeVersion": 4,
      "position": [
        200,
        300
      ],
      "parameters": {
        "sheetId": "YOUR_SHEET_ID",
        "range": "Carriers!A:Z",
        "event": "rowAdded"
      }
    },
    {
      "id": "n2",
      "name": "Segment Carrier Customer",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "jsCode": "\nconst carrier_type = $json.carrier_type?.toUpperCase() || 'PC_CARRIER';\nconst flags = [];\nif ($json.naic_mdl668_in_scope === 'true') flags.push('NAIC_MDL668_SCOPE');\nif ($json.handles_npi === 'true') flags.push('GLBA_NPI_HANDLER');\nif ($json.state_doi_vendor_registration === 'true') flags.push('STATE_DOI_APPROVED_VENDOR');\nif ($json.soc2_required === 'true') flags.push('SOC2_REQUIRED');\nif ($json.iso27001_required === 'true') flags.push('ISO27001_REQUIRED');\nif ($json.handles_phi === 'true') flags.push('HIPAA_IF_HEALTH');\nif ($json.billing_card_data === 'true') flags.push('PCI_DSS_IF_BILLING');\n\nconst segment_map = {\n  PC_CARRIER: { tier: 'enterprise', csm: true, welcome_subject: 'Your n8n onboarding \u2014 P&C carrier integration ready', mdl668_note: true },\n  LIFE_ANNUITY_CARRIER: { tier: 'enterprise', csm: true, welcome_subject: 'Your n8n onboarding \u2014 Life & annuity compliance workflows', mdl668_note: true },\n  HEALTH_PLAN_SPONSOR: { tier: 'enterprise', csm: true, welcome_subject: 'Your FlowKit onboarding \u2014 Health plan + HIPAA-aware workflows', mdl668_note: true },\n  SURPLUS_LINES_MGA: { tier: 'mid', csm: false, welcome_subject: 'FlowKit onboarding \u2014 MGA & surplus lines automations', mdl668_note: false },\n  CAPTIVE_MANAGER: { tier: 'mid', csm: false, welcome_subject: 'FlowKit onboarding \u2014 Captive management workflows', mdl668_note: false }\n};\n\nconst seg = segment_map[carrier_type] || segment_map['PC_CARRIER'];\nreturn { ...$json, ...seg, compliance_flags: flags.join(','), carrier_type };\n"
      }
    },
    {
      "id": "n3",
      "name": "Gmail Day0 Welcome",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "sendTo": "={{ $json.contact_email }}",
        "subject": "={{ $json.welcome_subject }}",
        "emailType": "html",
        "message": "={{ '<h2>Welcome to FlowKit, ' + $json.company_name + '</h2>' + ($json.mdl668_note ? '<p><strong>NAIC MDL-668 note:</strong> As your automation vendor, we are in scope for your annual third-party service provider assessment under your state MDL-668 implementation. Our SOC 2 Type II report and vendor questionnaire are available on request.</p>' : '') + ($json.compliance_flags.includes('GLBA_NPI_HANDLER') ? '<p><strong>GLBA NPI note:</strong> Your NPI data handling workflows are pre-configured with access controls and audit logging per 16 CFR Part 314.</p>' : '') + '<p>Book your onboarding call: <a href=\"https://cal.flowkitai.com\">Schedule here</a></p>' }}"
      }
    },
    {
      "id": "n4",
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        860,
        300
      ],
      "parameters": {
        "operation": "append",
        "sheetId": "YOUR_SHEET_ID",
        "range": "OnboardingLog!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "company": "={{ $json.company_name }}",
            "email": "={{ $json.contact_email }}",
            "carrier_type": "={{ $json.carrier_type }}",
            "tier": "={{ $json.tier }}",
            "flags": "={{ $json.compliance_flags }}",
            "day0_sent": "={{ new Date().toISOString() }}",
            "status": "ONBOARDING"
          }
        }
      }
    },
    {
      "id": "n5",
      "name": "Wait 3 Days",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        1080,
        300
      ],
      "parameters": {
        "amount": 3,
        "unit": "days"
      }
    },
    {
      "id": "n6",
      "name": "Gmail Day3 Vendor Questionnaire",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1300,
        300
      ],
      "parameters": {
        "sendTo": "={{ $json.contact_email }}",
        "subject": "Day 3: Your vendor questionnaire + SOC 2 report",
        "emailType": "html",
        "message": "={{ '<p>Hi ' + $json.contact_name + ',</p><p>As required for your NAIC MDL-668 third-party assessment:</p><ul><li><strong>SOC 2 Type II report:</strong> Available at trust.flowkitai.com</li><li><strong>Vendor security questionnaire:</strong> Pre-filled CAIQ attached</li>' + ($json.compliance_flags.includes('GLBA_NPI_HANDLER') ? '<li><strong>GLBA Data Processing Agreement:</strong> docs.flowkitai.com/glba-dpa</li>' : '') + ($json.compliance_flags.includes('STATE_DOI_APPROVED_VENDOR') ? '<li><strong>State DOI registration:</strong> Your state registration certificate is at docs.flowkitai.com/doi-certs</li>' : '') + '</ul><p>Integration guide: docs.flowkitai.com/insurtech</p>' }}"
      }
    },
    {
      "id": "n7",
      "name": "Wait 4 Days",
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1,
      "position": [
        1520,
        300
      ],
      "parameters": {
        "amount": 4,
        "unit": "days"
      }
    },
    {
      "id": "n8",
      "name": "Gmail Day7 QBR Invite",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1740,
        300
      ],
      "parameters": {
        "sendTo": "={{ $json.contact_email }}",
        "subject": "Week 1 check-in: Are your carrier compliance workflows running?",
        "emailType": "html",
        "message": "={{ '<p>Hi ' + $json.contact_name + ',</p><p>Book your week 1 QBR: <a href=\"https://cal.flowkitai.com/qbr\">Schedule</a></p><p>We will review: MDL-668 third-party assessment status, GLBA NPI data flows, carrier API integration health, SOC 2 evidence collection setup.</p>' }}"
      }
    }
  ],
  "connections": {
    "GoogleSheets Trigger": {
      "main": [
        [
          {
            "node": "Segment Carrier Customer",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Segment Carrier Customer": {
      "main": [
        [
          {
            "node": "Gmail Day0 Welcome",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Day0 Welcome": {
      "main": [
        [
          {
            "node": "Log to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Sheets": {
      "main": [
        [
          {
            "node": "Wait 3 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 3 Days": {
      "main": [
        [
          {
            "node": "Gmail Day3 Vendor Questionnaire",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail Day3 Vendor Questionnaire": {
      "main": [
        [
          {
            "node": "Wait 4 Days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 4 Days": {
      "main": [
        [
          {
            "node": "Gmail Day7 QBR Invite",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 2: Carrier Integration Health Monitor (NAIC MDL-668 §6 Third-Party Context)

Problem: Your Policy Admin System connector goes down at 2am. Your SERFF filing API times out. Nobody knows until a carrier compliance team calls asking why their state rate filing is missing — and now you have a state DOI disapproval-by-default situation on your hands.

What it does: Runs every 5 minutes. Pings each carrier integration endpoint (Policy Admin System, Claims Management System, Billing API, Actuarial Data Feed, SERFF State Filings API, Reinsurance Treaty Data API). Each endpoint is mapped to its specific regulatory risk and citation — so when the on-call engineer sees the alert, they understand not just 'service down' but 'SERFF connector offline = state filing deadline risk, NAIC UCAA.' Routes DOWN/DEGRADED status to #carrier-ops Slack with full regulatory context.

{
  "id": "insurtech-vendor-api-monitor-002",
  "name": "InsurTech SaaS Vendor \u2014 Carrier Integration Health Monitor",
  "nodes": [
    {
      "id": "n1",
      "name": "Every 5 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        200,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 5
            }
          ]
        }
      }
    },
    {
      "id": "n2",
      "name": "Load Carrier Endpoints",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "jsCode": "\nreturn [\n  { name: 'Policy Admin System API', url: 'https://pas-api.internal/health', regulatory_risk: 'PAS offline = policy issuance pipeline broken, carrier SOX ITGC risk if billing affected', reg_citation: 'NAIC MDL-668 \u00a76 third-party service provider obligations' },\n  { name: 'Claims Management System', url: 'https://cms-api.internal/health', regulatory_risk: 'Claims system degraded = prompt payment law violation risk (most states 30-45 day clock)', reg_citation: 'State prompt payment statutes (e.g. NY Ins Law \u00a73224-a, CA Ins Code \u00a7790.03)' },\n  { name: 'Billing & Premium Collection API', url: 'https://billing-api.internal/health', regulatory_risk: 'Billing pipeline down = grace period and lapse notification risk under state insurance codes', reg_citation: 'State insurance premium billing regulations, NAIC UCAA' },\n  { name: 'Actuarial Data Feed', url: 'https://actuarial-feed.internal/health', regulatory_risk: 'Actuarial data stale = rate filing accuracy risk, state DOI actuarial certification exposure', reg_citation: 'State DOI rate filing requirements, NAIC Actuarial Guideline LI' },\n  { name: 'State Filings API (SERFF)', url: 'https://serff-api.internal/health', regulatory_risk: 'SERFF connector offline = form/rate filing deadlines at risk, state DOI disapproval by default', reg_citation: 'NAIC SERFF state filing requirements by state' },\n  { name: 'Reinsurance Treaty Data API', url: 'https://reinsurance-api.internal/health', regulatory_risk: 'Treaty data sync failure = RBC Schedule F reporting accuracy risk', reg_citation: 'NAIC Risk-Based Capital (RBC) Schedule F, SSAP No. 62R' }\n];\n"
      }
    },
    {
      "id": "n3",
      "name": "Ping Each Endpoint",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        640,
        300
      ],
      "parameters": {
        "url": "={{ $json.url }}",
        "method": "GET",
        "timeout": 8000,
        "options": {
          "response": {
            "response": {
              "responseFormat": "text"
            }
          }
        }
      }
    },
    {
      "id": "n4",
      "name": "Evaluate Status",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        860,
        300
      ],
      "parameters": {
        "jsCode": "\nconst endpoint = $('Load Carrier Endpoints').item.json;\nconst statusCode = $json.statusCode || 0;\nlet severity = 'OK';\nlet alert_needed = false;\nif (statusCode === 0 || statusCode >= 500) { severity = 'DOWN'; alert_needed = true; }\nelse if (statusCode >= 400) { severity = 'DEGRADED'; alert_needed = true; }\nreturn { ...endpoint, statusCode, severity, alert_needed, checked_at: new Date().toISOString() };\n"
      }
    },
    {
      "id": "n5",
      "name": "Alert Needed?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        1080,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false
          },
          "conditions": [
            {
              "leftValue": "={{ $json.alert_needed }}",
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        }
      }
    },
    {
      "id": "n6",
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        1300,
        200
      ],
      "parameters": {
        "channel": "#carrier-ops",
        "text": "={{ ':red_circle: [' + $json.severity + '] ' + $json.name + '\\nRegulatory risk: ' + $json.regulatory_risk + '\\nCitation: ' + $json.reg_citation + '\\nChecked: ' + $json.checked_at }}"
      }
    },
    {
      "id": "n7",
      "name": "Log to Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1300,
        400
      ],
      "parameters": {
        "operation": "append",
        "sheetId": "YOUR_SHEET_ID",
        "range": "IntegrationHealth!A:G",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "endpoint": "={{ $json.name }}",
            "status": "={{ $json.severity }}",
            "http_code": "={{ $json.statusCode }}",
            "regulatory_risk": "={{ $json.regulatory_risk }}",
            "checked_at": "={{ $json.checked_at }}"
          }
        }
      }
    }
  ],
  "connections": {
    "Every 5 Minutes": {
      "main": [
        [
          {
            "node": "Load Carrier Endpoints",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Carrier Endpoints": {
      "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 Needed?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert Needed?": {
      "main": [
        [
          {
            "node": "Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log to Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 3: InsurTech Vendor Compliance Deadline Tracker (12 Deadline Types)

Problem: Your NAIC MDL-668 annual third-party review is due in 3 weeks. Your SOC 2 Type II renewal window opens next month. Your state DOI vendor registration lapses in 45 days in two states — and nobody in your company knows which states you're registered in or when they expire.

What it does: Reads compliance deadlines from a Google Sheet. Runs every weekday at 8 AM. Calculates OVERDUE/CRITICAL (≤14d)/URGENT (≤30d)/WARNING (≤60d)/NOTICE (≤90d) tiers. Deduplicates (no repeat alert on the same day). Routes to #compliance-ops Slack and emails the deadline owner with the regulatory citation and required action.

The 12 deadline types this tracker covers:

  • NAIC_MDL668_ANNUAL_THIRD_PARTY_REVIEW — carrier annual vendor security assessment
  • SOC2_TYPE2_RENEWAL — annual recertification window
  • ISO27001_SURVEILLANCE_AUDIT — for ISO-certified vendors
  • GLBA_PRIVACY_NOTICE_UPDATE — 16 CFR Part 314
  • STATE_DOI_VENDOR_REGISTRATION_RENEWAL — varies by state (some require annual renewal)
  • CARRIER_ANNUAL_VENDOR_REVIEW — contractual obligation in most carrier MSAs
  • NIST_CSF_ASSESSMENT — often required by larger carriers
  • ANNUAL_PENETRATION_TEST — required for SOC 2 + most carrier vendor policies
  • BUSINESS_CONTINUITY_TEST — MDL-668 §6 and carrier BCM requirements
  • INSURANCE_DORA_EU_CONTRACTUAL_REVIEW — for vendors with EU insurance carrier customers (DORA Art. 28 ICT contract obligations, effective Jan 17 2025)
  • CCPA_NPI_DATA_MAPPING_REVIEW — if you handle California policyholder NPI
  • CYBER_LIABILITY_INSURANCE_RENEWAL — required in most carrier vendor contracts
{
  "id": "insurtech-vendor-deadline-tracker-003",
  "name": "InsurTech SaaS Vendor \u2014 Compliance Deadline Tracker (12 Types)",
  "nodes": [
    {
      "id": "n1",
      "name": "Weekdays 8 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        200,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1-5"
            }
          ]
        }
      }
    },
    {
      "id": "n2",
      "name": "Load Deadlines from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        420,
        300
      ],
      "parameters": {
        "operation": "getAll",
        "sheetId": "YOUR_SHEET_ID",
        "range": "ComplianceDeadlines!A:H"
      }
    },
    {
      "id": "n3",
      "name": "Calculate Urgency",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "jsCode": "\nconst deadlines = $input.all().map(item => {\n  const d = item.json;\n  const deadline_date = new Date(d.deadline_date);\n  const today = new Date();\n  const days_left = Math.ceil((deadline_date - today) / (1000 * 60 * 60 * 24));\n  let urgency = 'OK';\n  if (days_left < 0) urgency = 'OVERDUE';\n  else if (days_left <= 14) urgency = 'CRITICAL';\n  else if (days_left <= 30) urgency = 'URGENT';\n  else if (days_left <= 60) urgency = 'WARNING';\n  else if (days_left <= 90) urgency = 'NOTICE';\n\n  const today_str = today.toISOString().split('T')[0];\n  const already_alerted = d.alert_sent_date === today_str;\n  return { ...d, days_left, urgency, already_alerted, today_str };\n});\n\n// Deadline types tracked:\n// NAIC_MDL668_ANNUAL_THIRD_PARTY_REVIEW\n// SOC2_TYPE2_RENEWAL\n// ISO27001_SURVEILLANCE_AUDIT\n// GLBA_PRIVACY_NOTICE_UPDATE\n// STATE_DOI_VENDOR_REGISTRATION_RENEWAL\n// CARRIER_ANNUAL_VENDOR_REVIEW\n// NIST_CSF_ASSESSMENT\n// ANNUAL_PENETRATION_TEST\n// BUSINESS_CONTINUITY_TEST\n// INSURANCE_DORA_EU_CONTRACTUAL_REVIEW\n// CCPA_NPI_DATA_MAPPING_REVIEW\n// CYBER_LIABILITY_INSURANCE_RENEWAL\n\nreturn deadlines.filter(d => d.urgency !== 'OK' && !d.already_alerted);\n"
      }
    },
    {
      "id": "n4",
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        860,
        200
      ],
      "parameters": {
        "channel": "#compliance-ops",
        "text": "={{ ':warning: [' + $json.urgency + '] ' + $json.deadline_type + ' \u2014 ' + $json.days_left + ' days\\nOwner: ' + $json.owner_email + '\\nAction: ' + $json.action_required + '\\nCitation: ' + $json.regulatory_citation }}"
      }
    },
    {
      "id": "n5",
      "name": "Email Owner",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        860,
        400
      ],
      "parameters": {
        "sendTo": "={{ $json.owner_email }}",
        "subject": "={{ '[' + $json.urgency + '] ' + $json.deadline_type + ' \u2014 ' + $json.days_left + ' days remaining' }}",
        "emailType": "html",
        "message": "={{ '<h3>' + $json.deadline_type + '</h3><p><strong>Status:</strong> ' + $json.urgency + ' (' + $json.days_left + ' days)</p><p><strong>Action required:</strong> ' + $json.action_required + '</p><p><strong>Regulatory citation:</strong> ' + $json.regulatory_citation + '</p>' }}"
      }
    },
    {
      "id": "n6",
      "name": "Mark Alert Sent",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4,
      "position": [
        1080,
        300
      ],
      "parameters": {
        "operation": "update",
        "sheetId": "YOUR_SHEET_ID",
        "range": "ComplianceDeadlines!A:H",
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "alert_sent_date": "={{ $json.today_str }}"
          }
        }
      }
    }
  ],
  "connections": {
    "Weekdays 8 AM": {
      "main": [
        [
          {
            "node": "Load Deadlines from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Load Deadlines from Sheets": {
      "main": [
        [
          {
            "node": "Calculate Urgency",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Calculate Urgency": {
      "main": [
        [
          {
            "node": "Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Alert": {
      "main": [
        [
          {
            "node": "Email Owner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Owner": {
      "main": [
        [
          {
            "node": "Mark Alert Sent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 4: Carrier Data Incident Notification Pipeline (8 Incident Types, MDL-668 Clock)

Problem: Your systems detect unauthorized access to carrier policyholder data. Your CISO needs to know. Your carrier's CISO needs to know within 72 hours. Their state DOI needs to know within 72 hours of the carrier's notification. That chain — vendor to carrier to regulator — has to move fast and be documented precisely.

What it does: Receives webhook events for 8 incident types: CARRIER_NPI_BREACH, CLAIMS_DATA_EXFILTRATION, ACTUARIAL_DATA_EXPOSURE, POLICY_HOLDER_PII_BREACH, STATE_DOI_REGULATORY_INQUIRY, NAIC_MDL668_INCIDENT_NOTIFICATION, SOC2_CONTROL_FAILURE, GLBA_NPI_UNAUTHORIZED_DISCLOSURE. Each type maps to the applicable regulation, regulatory body, and response clock. CRITICAL incidents (carrier NPI breach, policyholder PII, GLBA NPI disclosure) route to #legal-compliance with legal team CC and CISO BCC. All incidents write to a Postgres audit trail.

Key regulatory clocks this workflow documents:

  • CARRIER_NPI_BREACH: 72 hours — vendor notifies carrier; carrier then notifies state DOI
  • GLBA_NPI_UNAUTHORIZED_DISCLOSURE: 30 days FTC notification clock (16 CFR Part 314, most-restrictive state AG rule may be 3 days)
  • STATE_DOI_REGULATORY_INQUIRY: 30 days typical response window — verify with counsel by state
  • NAIC_MDL668_INCIDENT_NOTIFICATION: 72 hours — vendor to carrier; carrier clock runs from receipt
  • SOC2_CONTROL_FAILURE: 4 hours for evidence preservation; notify CSO immediately
{
  "id": "insurtech-vendor-incident-pipeline-004",
  "name": "InsurTech SaaS Vendor \u2014 Carrier Data Incident Pipeline (8 Types)",
  "nodes": [
    {
      "id": "n1",
      "name": "Incident Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        200,
        300
      ],
      "parameters": {
        "path": "carrier-incident",
        "httpMethod": "POST"
      }
    },
    {
      "id": "n2",
      "name": "Map Incident Type",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "jsCode": "\nconst incident_type = $json.incident_type?.toUpperCase();\nconst incident_map = {\n  CARRIER_NPI_BREACH: {\n    severity: 'CRITICAL',\n    regulation: 'GLBA 16 CFR Part 314 + NAIC MDL-668',\n    response_clock: '72h: notify affected carrier. Carrier has 72h to notify state DOI.',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  },\n  CLAIMS_DATA_EXFILTRATION: {\n    severity: 'CRITICAL',\n    regulation: 'NAIC MDL-668 \u00a78 + State insurance data security laws',\n    response_clock: '72h: notify carrier CISO. Document scope \u2014 claims data is NPI under GLBA.',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  },\n  ACTUARIAL_DATA_EXPOSURE: {\n    severity: 'HIGH',\n    regulation: 'NAIC MDL-668 \u00a76 + State DOI rate filing confidentiality rules',\n    response_clock: 'Preserve audit trail. Notify carrier within 24h.',\n    legal_cc: false,\n    channel: '#security-ops'\n  },\n  POLICY_HOLDER_PII_BREACH: {\n    severity: 'CRITICAL',\n    regulation: 'GLBA FTC Safeguards Rule + NAIC MDL-668 + State breach notification (avg 30-60 days to individuals)',\n    response_clock: '72h: notify carrier. State AG notification window varies (CA 72h, NY 30d).',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  },\n  STATE_DOI_REGULATORY_INQUIRY: {\n    severity: 'HIGH',\n    regulation: 'State DOI market conduct examination authority',\n    response_clock: '30 days typical response window \u2014 verify with counsel.',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  },\n  NAIC_MDL668_INCIDENT_NOTIFICATION: {\n    severity: 'HIGH',\n    regulation: 'NAIC MDL-668 \u00a78 mandatory notification',\n    response_clock: '72h: vendor must notify carrier. Carrier then notifies state DOI per state law.',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  },\n  SOC2_CONTROL_FAILURE: {\n    severity: 'MEDIUM',\n    regulation: 'SOC 2 Type II \u2014 CC7.2 incident response, CC9.2 vendor risk',\n    response_clock: 'Document within 4h. Evidence preservation for auditor. Notify CSO.',\n    legal_cc: false,\n    channel: '#security-ops'\n  },\n  GLBA_NPI_UNAUTHORIZED_DISCLOSURE: {\n    severity: 'CRITICAL',\n    regulation: 'GLBA 15 USC \u00a76801 + 16 CFR Part 314 Safeguards Rule 2023',\n    response_clock: '30-day FTC notification clock starts at discovery. State AG 3-day most-restrictive rule.',\n    legal_cc: true,\n    channel: '#legal-compliance'\n  }\n};\n\nconst meta = incident_map[incident_type] || { severity: 'UNKNOWN', regulation: 'Unknown', response_clock: 'Review manually', legal_cc: false, channel: '#security-ops' };\nreturn { ...$json, ...meta, incident_type, detected_at: new Date().toISOString() };\n"
      }
    },
    {
      "id": "n3",
      "name": "Route by Severity",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true
          },
          "conditions": [
            {
              "leftValue": "={{ $json.legal_cc }}",
              "operator": {
                "type": "boolean",
                "operation": "true"
              }
            }
          ]
        }
      }
    },
    {
      "id": "n4",
      "name": "Slack Legal + CISO Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        860,
        200
      ],
      "parameters": {
        "channel": "={{ $json.channel }}",
        "text": "={{ ':rotating_light: [' + $json.severity + '] CARRIER DATA INCIDENT: ' + $json.incident_type + '\\nRegulation: ' + $json.regulation + '\\nResponse clock: ' + $json.response_clock + '\\nAffected carrier: ' + ($json.carrier_name || 'UNKNOWN') + '\\nDetected: ' + $json.detected_at }}"
      }
    },
    {
      "id": "n5",
      "name": "Email Legal + CISO",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1080,
        200
      ],
      "parameters": {
        "sendTo": "legal@yourcompany.com",
        "cc": "ciso@yourcompany.com",
        "subject": "={{ '[' + $json.severity + '] Carrier Incident: ' + $json.incident_type }}",
        "emailType": "html",
        "message": "={{ '<h2>Carrier Data Incident Alert</h2><table><tr><td><strong>Type:</strong></td><td>' + $json.incident_type + '</td></tr><tr><td><strong>Severity:</strong></td><td>' + $json.severity + '</td></tr><tr><td><strong>Carrier:</strong></td><td>' + ($json.carrier_name || 'Unknown') + '</td></tr><tr><td><strong>Regulation:</strong></td><td>' + $json.regulation + '</td></tr><tr><td><strong>Response clock:</strong></td><td>' + $json.response_clock + '</td></tr><tr><td><strong>Detected:</strong></td><td>' + $json.detected_at + '</td></tr></table>' }}"
      }
    },
    {
      "id": "n6",
      "name": "Slack Security Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        860,
        400
      ],
      "parameters": {
        "channel": "#security-ops",
        "text": "={{ ':warning: [' + $json.severity + '] ' + $json.incident_type + '\\nRegulation: ' + $json.regulation + '\\nResponse clock: ' + $json.response_clock }}"
      }
    },
    {
      "id": "n7",
      "name": "Log to Postgres",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        1300,
        300
      ],
      "parameters": {
        "operation": "insert",
        "schema": "public",
        "table": "carrier_incidents",
        "columns": "incident_type,severity,regulation,response_clock,carrier_name,affected_records,detected_at,legal_notified",
        "columnData": "={{ $json.incident_type }},={{ $json.severity }},={{ $json.regulation }},={{ $json.response_clock }},={{ $json.carrier_name }},={{ $json.affected_records }},={{ $json.detected_at }},={{ $json.legal_cc }}"
      }
    }
  ],
  "connections": {
    "Incident Webhook": {
      "main": [
        [
          {
            "node": "Map Incident Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Map Incident Type": {
      "main": [
        [
          {
            "node": "Route by Severity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Severity": {
      "main": [
        [
          {
            "node": "Slack Legal + CISO Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Slack Security Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Legal + CISO Alert": {
      "main": [
        [
          {
            "node": "Email Legal + CISO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Legal + CISO": {
      "main": [
        [
          {
            "node": "Log to Postgres",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack Security Alert": {
      "main": [
        [
          {
            "node": "Log to Postgres",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 5: Weekly InsurTech Vendor KPI Dashboard (CEO + CISO)

Problem: Your CEO sees MRR. Your CISO should also see the compliance posture — open MDL-668 incidents, state DOI inquiries, SOC2 control failures, upcoming MDL-668 reviews due — in the same Monday briefing. When both are together, the conversation happens before it becomes a $2M enforcement action against your carrier customer that traces back to your systems.

What it does: Runs every Monday at 8 AM. Queries Postgres for carrier account metrics (active carriers, MRR, churn, new trials) and compliance events (NAIC MDL-668 incidents open, state DOI inquiries, SOC2 control failures, MDL-668 reviews due in 30 days). Builds an HTML report with colored flags: [NAIC INCIDENT OPEN], [STATE DOI INQUIRY OPEN], [SOC2 CONTROL FAILURE THIS WEEK], [MDL-668 REVIEW DUE <30 DAYS]. Emails CEO with CISO BCC so the CISO always sees the compliance section.

{
  "id": "insurtech-vendor-weekly-kpi-005",
  "name": "InsurTech SaaS Vendor \u2014 Weekly KPI Dashboard (CEO + CISO)",
  "nodes": [
    {
      "id": "n1",
      "name": "Every Monday 8 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        200,
        300
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1"
            }
          ]
        }
      }
    },
    {
      "id": "n2",
      "name": "Query Business Metrics",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        420,
        300
      ],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as active_carriers, SUM(mrr_usd) as total_mrr, COUNT(CASE WHEN churned_at > NOW() - INTERVAL '7 days' THEN 1 END) as churned_7d, COUNT(CASE WHEN trial = true AND created_at > NOW() - INTERVAL '7 days' THEN 1 END) as new_trials FROM carrier_accounts WHERE active = true;"
      }
    },
    {
      "id": "n3",
      "name": "Query Compliance Events",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        640,
        300
      ],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(CASE WHEN incident_type IN ('CARRIER_NPI_BREACH','POLICY_HOLDER_PII_BREACH','GLBA_NPI_UNAUTHORIZED_DISCLOSURE','NAIC_MDL668_INCIDENT_NOTIFICATION') AND resolved_at IS NULL THEN 1 END) as naic_incidents_open, COUNT(CASE WHEN incident_type = 'STATE_DOI_REGULATORY_INQUIRY' AND resolved_at IS NULL THEN 1 END) as doi_inquiries_open, COUNT(CASE WHEN incident_type = 'SOC2_CONTROL_FAILURE' AND created_at > NOW() - INTERVAL '7 days' THEN 1 END) as soc2_failures_7d, COUNT(CASE WHEN deadline_type = 'NAIC_MDL668_ANNUAL_THIRD_PARTY_REVIEW' AND EXTRACT(DAY FROM deadline_date - NOW()) < 30 AND resolved_at IS NULL THEN 1 END) as mdl668_reviews_due_30d FROM carrier_incidents;"
      }
    },
    {
      "id": "n4",
      "name": "Build KPI Report",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        860,
        300
      ],
      "parameters": {
        "jsCode": "\nconst biz = $('Query Business Metrics').item.json;\nconst comp = $('Query Compliance Events').item.json;\n\nconst flags = [];\nif (comp.naic_incidents_open > 0) flags.push('[NAIC INCIDENT OPEN]');\nif (comp.doi_inquiries_open > 0) flags.push('[STATE DOI INQUIRY OPEN]');\nif (comp.soc2_failures_7d > 0) flags.push('[SOC2 CONTROL FAILURE THIS WEEK]');\nif (comp.mdl668_reviews_due_30d > 0) flags.push('[MDL-668 REVIEW DUE <30 DAYS]');\n\nconst subject = flags.length > 0\n  ? `Weekly InsurTech Vendor KPI ${flags.join(' ')} \u2014 Action Required`\n  : 'Weekly InsurTech Vendor KPI \u2014 All Clear';\n\nconst body = `\n<h2>FlowKit Weekly KPI \u2014 ${new Date().toISOString().split('T')[0]}</h2>\n<h3>Business</h3>\n<ul>\n  <li>Active carriers: ${biz.active_carriers}</li>\n  <li>MRR: $${Number(biz.total_mrr || 0).toLocaleString()}</li>\n  <li>Churned last 7d: ${biz.churned_7d}</li>\n  <li>New trials: ${biz.new_trials}</li>\n</ul>\n<h3>Compliance</h3>\n<ul>\n  <li>NAIC MDL-668 incidents open: ${comp.naic_incidents_open}</li>\n  <li>State DOI inquiries open: ${comp.doi_inquiries_open}</li>\n  <li>SOC2 control failures (7d): ${comp.soc2_failures_7d}</li>\n  <li>MDL-668 reviews due \u226430 days: ${comp.mdl668_reviews_due_30d}</li>\n</ul>\n${flags.length > 0 ? '<p><strong>ACTION REQUIRED: ' + flags.join(', ') + '</strong></p>' : '<p>No open compliance flags.</p>'}\n`;\n\nreturn { subject, body, flags: flags.join(', '), has_flags: flags.length > 0 };\n"
      }
    },
    {
      "id": "n5",
      "name": "Email CEO + CISO",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2,
      "position": [
        1080,
        300
      ],
      "parameters": {
        "sendTo": "ceo@yourcompany.com",
        "bcc": "ciso@yourcompany.com",
        "subject": "={{ $json.subject }}",
        "emailType": "html",
        "message": "={{ $json.body }}"
      }
    }
  ],
  "connections": {
    "Every Monday 8 AM": {
      "main": [
        [
          {
            "node": "Query Business Metrics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Business Metrics": {
      "main": [
        [
          {
            "node": "Query Compliance Events",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Compliance Events": {
      "main": [
        [
          {
            "node": "Build KPI Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build KPI Report": {
      "main": [
        [
          {
            "node": "Email CEO + CISO",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

The InsurTech vendor compliance case for self-hosted n8n

When a carrier's CISO asks 'which third-party services process our policyholder data and what is the data residency?' — the answer 'we use Zapier/Make for our automation workflows' opens a sub-processor review, a data transfer agreement, and a GLBA vendor management file that someone has to maintain.

Risk Zapier/Make Self-hosted n8n
Carrier NPI flows through cloud iPaaS GLBA data sharing question in every carrier vendor review NPI stays in your VPC
Claims data through cloud workflow engine MDL-668 third-party scope expansion for the carrier Data stays in your enclave
SOC 2 CC9.2 vendor risk Zapier = new sub-processor to justify in your SOC 2 Self-hosted = no external vendor for workflow layer
Carrier vendor questionnaire Must disclose cloud iPaaS as sub-processor Single-tenant self-hosted — no sub-processor
Audit trail for carrier's MDL-668 review Zapier log you request from a third party Git-versioned JSON you own and produce

Self-hosted n8n keeps carrier NPI, claims data, policyholder PII, and actuarial feeds inside your infrastructure. Your compliance audit trail is git-versioned JSON — not a vendor-controlled log you have to request under a data processing agreement.


Get these workflows + 10 more for insurance, FinTech, and compliance-heavy SaaS

All 5 workflows are at stripeai.gumroad.com — copy the JSON, import into n8n, configure your connections.

The FlowKit Complete Bundle also includes carrier onboarding drips, incident pipelines, and KPI dashboards for EU InsurTech (Solvency II/EIOPA), RegTech (MiFID II/AMLD6/Basel IV/DORA), FinTech (PCI DSS/SOX/GLBA), HealthTech (HIPAA/HITECH), and 15+ other compliance-heavy verticals.

Questions or variations? Drop them in the comments — I respond to every one.

Top comments (0)