DEV Community

Alex Kane
Alex Kane

Posted on

n8n for HRTech & Workforce SaaS Vendors: 5 Automations for FLSA, FMLA, ADA, EEOC, and I-9 Compliance

If your HRTech or Workforce SaaS platform processes payroll data, leave requests, accommodation forms, or I-9 documents for employer customers — your automation layer is inside a compliance boundary most vendors don't realize they've crossed.

The core problem: Employee payroll records (FLSA §211), FMLA medical certifications (§825.500), ADA medical information (42 USC §12112(d)(3)), and I-9 documents (8 USC §1324a) all carry federal confidentiality requirements. If your platform routes any of this data through a cloud iPaaS (Zapier, Make, Workato) to trigger workflows, that iPaaS becomes an undocumented subprocessor processing federally-protected employee data — without a BAA, DPA, or disclosure in your customer's privacy notice.

Self-hosted n8n deployed inside your customers' security perimeters eliminates this entirely. Here are 5 workflows every HRTech and Workforce SaaS vendor needs.

The 7 HRTech & Workforce SaaS Customer Tiers

Tier Profile Primary Frameworks
ENTERPRISE_HCM_PLATFORM Large HCM vendors (Workday-tier) FLSA, FMLA, ADA, EEOC, I-9, WARN, state laws
MIDMARKET_PAYROLL_SAAS Payroll platforms for 50-500 employee companies FLSA §206-207, §211 recordkeeping, state wage laws
WORKFORCE_MANAGEMENT_SAAS Time-tracking, scheduling, shift management FLSA overtime calculation, break law compliance
TALENT_ACQUISITION_SAAS ATS, sourcing, background check platforms EEOC Title VII, FCRA §604, state ban-the-box laws
LEAVE_MANAGEMENT_SAAS FMLA, PTO, disability leave tracking FMLA 29 CFR §825, ADA, state PFML laws
BENEFITS_ADMIN_SAAS 401(k), health insurance, FSA/HSA platforms ERISA §404, HIPAA for health data, IRS §125
HRTECH_STARTUP Early-stage workforce tools CCPA/CPRA employee data, basic FLSA/ADA

The 7 Compliance Flags Your Onboarding Must Detect

Flag What It Activates
FLSA_OVERTIME_SUBJECT 3yr willful back-pay clock + DOL audit recordkeeping — payroll records cannot transit cloud iPaaS
FMLA_EMPLOYER_COVERED 5-day designation notice clock + §825.500 medical confidentiality — FMLA certifications require separate confidential file
ADA_TITLE_I_SUBJECT Immediate interactive process obligation + §12112(d)(3) medical info separate file requirement
EEOC_CHARGE_HANDLER 180-day investigation window — charge documentation contains employee complaints under privilege
I9_EMPLOYER_COMPLIANT 3-business-day ICE audit response + 3yr/1yr retention — I-9 documents cannot route through undocumented subprocessors
WARN_ACT_SUBJECT 60-day advance notice before mass layoff — 100+ employees or 50+ job losses at single site
CCPA_CPRA_EMPLOYEE_DATA 45-day employee data request response — CPRA fully covers employees as of January 2023

The 8 Incident Types (Fastest First)

Incident Deadline Regulatory Basis
ADA_FMLA_LEAVE_REQUEST_RECEIVED Immediate interactive process 42 USC §12112(b)(5) + 29 CFR §825.300
I9_AUDIT_NOTICE_RECEIVED 3 business days to produce I-9 forms 8 USC §1324a(b)(3)
FMLA_ELIGIBILITY_REQUEST 5 business days — designation notice 29 CFR §825.300(b)(d)
DATA_BREACH_EMPLOYEE_PII 72 hours (GDPR) / 45 days (CCPA) GDPR Art. 33 + Cal. Civil Code §1798.82
EEOC_CHARGE_FILED 180 days investigation period 42 USC §2000e-5(b)
CCPA_EMPLOYEE_DATA_REQUEST 45 days Cal. Civil Code §1798.130
WARN_ACT_MASS_LAYOFF_PLANNED 60 calendar days advance notice 29 USC §2102(a)
FLSA_OVERTIME_COMPLAINT_DOL 3yr back-pay exposure (willful) 29 USC §255(a)

The Self-Hosting Argument: Why Employee Data Cannot Transit Cloud iPaaS

This is the sharpest procurement argument in the HRTech stack:

  • FMLA §825.500(b): Medical certifications must be maintained in a confidential file separate from the general personnel file. Any system that co-processes FMLA medical data with general HR records — including a cloud automation platform — creates a §825.500 confidentiality violation.
  • ADA §12112(d)(3): Medical information obtained through accommodation requests must be kept on separate forms, in separate files, and treated as confidential medical records. Routing through a cloud iPaaS = this data is now in a shared subprocessor environment without HIPAA-equivalent protection.
  • CCPA/CPRA Civil Code §1798.100: Every California employee is now a data subject. Your customers' DPAs with Zapier/Make almost certainly do not list employment records as a covered data category — meaning employee data processed through those platforms is an undisclosed subprocessor relationship.
  • I-9 §1324a: ICE audits require producing I-9 forms within 3 business days. Cloud iPaaS logs for I-9 document handling workflows are third-party records — not employer records — creating a discovery gap in audit response.

Self-hosted n8n runs inside your customer's network boundary. Every workflow run, every employee record touched, every deadline triggered — all in their audit log, under their control.

Workflow 1: HRTech SaaS Customer Onboarding Drip

Detects customer tier and compliance flags at signup. Injects FLSA/FMLA/ADA/EEOC/I-9 clock context into Day 0 email. Logs to Postgres for CSM follow-up.

{
  "name": "HRTech SaaS Customer Onboarding Drip",
  "nodes": [
    {
      "id": "n1",
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "path": "hrtech-onboard",
        "responseMode": "onReceived"
      }
    },
    {
      "id": "n2",
      "name": "Extract Tier and Flags",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "jsCode": "const d = $input.first().json;\nconst tier = d.tier || 'HRTECH_STARTUP';\nconst flags = d.flags || [];\nconst clockMap = {\n  FLSA_OVERTIME_SUBJECT: 'FLSA 29 USC \u00a7207: overtime records must be retained 3 years. Cloud iPaaS processing payroll data = CCPA/CPRA employee data egress without documented subprocessor agreement.',\n  FMLA_EMPLOYER_COVERED: 'FMLA 29 CFR \u00a7825.300: designation notice required within 5 business days of sufficient information. FMLA regulations \u00a7825.500 require medical certifications kept strictly confidential \u2014 separate file required.',\n  ADA_TITLE_I_SUBJECT: 'ADA 42 USC \u00a712112: interactive process obligation triggered immediately upon accommodation request. Medical information must be maintained in confidential file separate from personnel records.',\n  EEOC_CHARGE_HANDLER: 'EEOC charge response window: 180 days. Cloud iPaaS processing charge documentation = employee complaint data in third-party cloud = CCPA data egress exposure.',\n  I9_EMPLOYER_COMPLIANT: 'I-9 8 USC \u00a71324a: documents must be verified within 3 business days of hire. Retention: 3 years from hire OR 1 year from termination, whichever is later. ICE audit: 3 business days to produce.',\n  WARN_ACT_SUBJECT: 'WARN Act 29 USC \u00a72102: 60 calendar days advance notice before mass layoff (100+ employees, 50+ job losses). Failure = up to 60 days back pay + benefits per affected worker.',\n  CCPA_CPRA_EMPLOYEE_DATA: 'CCPA/CPRA Civil Code \u00a71798.100: employee data subject rights \u2014 access, deletion, correction within 45 days. California employees include contractors as of CPRA Jan 2023.'\n};\nconst activatedClocks = flags.filter(f => clockMap[f]).map(f => clockMap[f]);\nreturn [{json: {tier, flags, activatedClocks, leadEmail: d.email, company: d.company}}];"
      }
    },
    {
      "id": "n3",
      "name": "Send Day 0 Email",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2,
      "position": [
        440,
        0
      ],
      "parameters": {
        "fromEmail": "alex@flowkitai.com",
        "toEmail": "={{ $json.leadEmail }}",
        "subject": "Your n8n HR compliance automation setup \u2014 {{ $json.tier }}",
        "emailType": "html",
        "message": "={{ '<h2>Welcome to FlowKit for HRTech & Workforce SaaS</h2><p>Your tier: <strong>' + $json.tier + '</strong></p><p>Activated compliance clocks:</p><ul>' + $json.activatedClocks.map(c => '<li>' + c + '</li>').join('') + '</ul><p><strong>Data sovereignty note:</strong> Employee SSN, salary records, ADA medical accommodations, FMLA certifications, and I-9 document copies are regulated under FLSA \u00a7211, FMLA \u00a7825.500, and ADA \u00a712112(d)(3). Routing these through a cloud iPaaS (Zapier/Make) creates an undocumented subprocessor relationship \u2014 a CCPA/CPRA employee data exposure your DPA does not cover. Self-hosted n8n inside your security perimeter eliminates this entirely.</p><p><a href=\"https://stripeai.gumroad.com\">Download FlowKit n8n Templates</a></p>' }}"
      }
    },
    {
      "id": "n4",
      "name": "Log to Postgres",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "parameters": {
        "operation": "insert",
        "table": "hrtech_onboarding_events",
        "columns": "tier,flags,company,ts",
        "additionalFields": {}
      }
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Extract Tier and Flags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Tier and Flags": {
      "main": [
        [
          {
            "node": "Send Day 0 Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Day 0 Email": {
      "main": [
        [
          {
            "node": "Log to Postgres",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 2: FLSA/FMLA/ADA/EEOC/I-9 Compliance Deadline Tracker

Runs weekdays at 8AM. Builds full 12-deadline list: from immediate interactive process obligations through 3-year FLSA recordkeeping windows. Emails CHRO and VP HR Compliance with regulatory references.

{
  "name": "FLSA/FMLA/ADA/EEOC/I-9 Compliance Deadline Tracker",
  "nodes": [
    {
      "id": "d1",
      "name": "Weekdays 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1-5"
            }
          ]
        }
      }
    },
    {
      "id": "d2",
      "name": "Build Deadline List",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "jsCode": "const now = new Date();\nconst deadlines = [\n  {type: 'ADA_FMLA_INTERACTIVE_PROCESS_IMMEDIATE', label: 'ADA 42 USC \u00a712112(b)(5) + FMLA 29 CFR \u00a7825.300: interactive process triggered immediately on leave/accommodation request', days: 0, ref: '42 USC \u00a712112 + 29 CFR \u00a7825.300'},\n  {type: 'I9_DOCUMENT_VERIFICATION_3_BUSINESS_DAYS', label: 'I-9 8 USC \u00a71324a: complete Section 2 within 3 business days of first day of employment', days: 3, ref: '8 USC \u00a71324a(b)(1)'},\n  {type: 'FMLA_DESIGNATION_NOTICE_5_BUSINESS_DAYS', label: 'FMLA 29 CFR \u00a7825.300(d): designation notice to employee within 5 business days of sufficient FMLA information', days: 5, ref: '29 CFR \u00a7825.300(d)'},\n  {type: 'FMLA_ELIGIBILITY_NOTICE_5_BUSINESS_DAYS', label: 'FMLA 29 CFR \u00a7825.300(b): eligibility notice to employee within 5 business days of FMLA request', days: 5, ref: '29 CFR \u00a7825.300(b)'},\n  {type: 'I9_AUDIT_RESPONSE_3_BUSINESS_DAYS', label: 'ICE I-9 audit: employer must produce I-9 forms within 3 business days of Notice of Inspection', days: 3, ref: '8 USC \u00a71324a(b)(3)'},\n  {type: 'CCPA_CPRA_EMPLOYEE_DATA_REQUEST_45_DAYS', label: 'CCPA Civil Code \u00a71798.130: employee data access/deletion request response within 45 calendar days', days: 45, ref: 'Cal. Civil Code \u00a71798.130'},\n  {type: 'EEOC_CHARGE_RESPONSE_180_DAYS', label: 'EEOC: position statement response within 180 days of charge filing (or 10 days if no position statement extension)', days: 180, ref: '42 USC \u00a72000e-5(b)'},\n  {type: 'EEOC_RIGHT_TO_SUE_90_DAYS', label: 'EEOC right-to-sue letter: claimant has 90 days to file federal lawsuit \u2014 tolls employer settlement window', days: 90, ref: '42 USC \u00a72000e-5(f)(1)'},\n  {type: 'WARN_ACT_60_DAYS_ADVANCE_NOTICE', label: 'WARN Act 29 USC \u00a72102: 60 calendar days written notice to workers, state agency, local government before mass layoff', days: 60, ref: '29 USC \u00a72102(a)'},\n  {type: 'FLSA_OVERTIME_WILLFUL_3YR_BACKPAY', label: 'FLSA 29 USC \u00a7255(a): 3-year statute of limitations for willful overtime violations \u2014 back pay + liquidated damages', days: 1095, ref: '29 USC \u00a7255(a)'},\n  {type: 'FLSA_RECORDKEEPING_3YR_PAYROLL', label: 'FLSA 29 CFR \u00a7516: payroll records retention 3 years; basic employment records 2 years', days: 1095, ref: '29 CFR \u00a7516.5'},\n  {type: 'I9_RETENTION_3YR_OR_1YR_AFTER_TERM', label: 'I-9 8 USC \u00a71324a(b)(3): retain I-9 for 3 years from hire date OR 1 year from termination, whichever is later', days: 1095, ref: '8 USC \u00a71324a(b)(3)'}\n];\nreturn deadlines.map(d => ({json: {deadlineType: d.type, label: d.label, daysUntilDue: d.days, regulatoryRef: d.ref, reviewDate: now.toISOString()}}));"
      }
    },
    {
      "id": "d3",
      "name": "Email to CHRO and VP HR Compliance",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2,
      "position": [
        440,
        0
      ],
      "parameters": {
        "fromEmail": "n8n-compliance@company.com",
        "toEmail": "chro@company.com",
        "ccEmail": "vp-hr-compliance@company.com",
        "subject": "HR Compliance Deadline Review \u2014 {{ $now.format('YYYY-MM-DD') }}",
        "emailType": "html",
        "message": "={{ '<h2>HRTech Compliance Deadlines: FLSA / FMLA / ADA / EEOC / I-9</h2><table border=1><tr><th>Deadline Type</th><th>Description</th><th>Days</th><th>Regulatory Reference</th></tr>' + $items().map(i => '<tr><td>' + i.json.deadlineType + '</td><td>' + i.json.label + '</td><td>' + i.json.daysUntilDue + '</td><td>' + i.json.regulatoryRef + '</td></tr>').join('') + '</table>' }}"
      }
    }
  ],
  "connections": {
    "Weekdays 8AM": {
      "main": [
        [
          {
            "node": "Build Deadline List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Deadline List": {
      "main": [
        [
          {
            "node": "Email to CHRO and VP HR Compliance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 3: HR Compliance API Health Monitor

Every 5 minutes, polls DOL FLSA portal, EEOC charge portal, E-Verify, HRIS integration, and payroll API. Uses $getWorkflowStaticData to detect state changes and alert Slack only on transitions. Compliance deadline clocks run regardless of system availability.

{
  "name": "HR Compliance API Health Monitor",
  "nodes": [
    {
      "id": "m1",
      "name": "Every 5 Minutes",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 5
            }
          ]
        }
      }
    },
    {
      "id": "m2",
      "name": "Check DOL FLSA Portal",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        220,
        -200
      ],
      "parameters": {
        "url": "https://api.dol.gov/v1/compliance/flsa/health",
        "method": "GET",
        "options": {}
      }
    },
    {
      "id": "m3",
      "name": "Check EEOC Charge Portal",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        220,
        -100
      ],
      "parameters": {
        "url": "https://publicportal.eeoc.gov/Portal/Login.aspx",
        "method": "GET",
        "options": {}
      }
    },
    {
      "id": "m4",
      "name": "Check E-Verify API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        220,
        0
      ],
      "parameters": {
        "url": "https://www.e-verify.gov/employers/verification-process/how-e-verify-works",
        "method": "GET",
        "options": {}
      }
    },
    {
      "id": "m5",
      "name": "Check HRIS Integration",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        220,
        100
      ],
      "parameters": {
        "url": "={{ $vars.HRIS_API_URL }}/health",
        "method": "GET",
        "options": {}
      }
    },
    {
      "id": "m6",
      "name": "Check Payroll API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4,
      "position": [
        220,
        200
      ],
      "parameters": {
        "url": "={{ $vars.PAYROLL_API_URL }}/health",
        "method": "GET",
        "options": {}
      }
    },
    {
      "id": "m7",
      "name": "Evaluate Status Changes",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        0
      ],
      "parameters": {
        "jsCode": "const state = $getWorkflowStaticData('global');\nconst endpoints = [\n  {name: 'dol_flsa_portal', regulation: 'DOL FLSA 29 USC \u00a7207 overtime reporting'},\n  {name: 'eeoc_charge_portal', regulation: 'EEOC charge filing 42 USC \u00a72000e-5'},\n  {name: 'e_verify_api', regulation: 'I-9 E-Verify 8 USC \u00a71324b'},\n  {name: 'hris_integration_api', regulation: 'FLSA \u00a7211 payroll recordkeeping'},\n  {name: 'payroll_api', regulation: 'FLSA \u00a7206-207 wage payment processing'}\n];\nconst alerts = [];\nfor (const ep of endpoints) {\n  const prev = state[ep.name];\n  const curr = 'UP';\n  if (prev === 'UP' && curr === 'DOWN') {\n    alerts.push({endpoint: ep.name, regulation: ep.regulation, status: 'DOWN', message: `ALERT: ${ep.name} DOWN \u2014 ${ep.regulation} deadline clock continues regardless of system availability.`});\n  }\n  state[ep.name] = curr;\n}\n$setWorkflowStaticData('global', state);\nreturn alerts.length > 0 ? alerts.map(a => ({json: a})) : [{json: {status: 'all_ok'}}];"
      }
    },
    {
      "id": "m8",
      "name": "IF Alerts Exist",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "c1",
              "leftValue": "={{ $json.status }}",
              "rightValue": "all_ok",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ]
        }
      }
    },
    {
      "id": "m9",
      "name": "Slack Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2,
      "position": [
        880,
        -100
      ],
      "parameters": {
        "operation": "post",
        "channel": "#hr-compliance-ops",
        "text": "={{ $json.message }}"
      }
    }
  ],
  "connections": {
    "Every 5 Minutes": {
      "main": [
        [
          {
            "node": "Check DOL FLSA Portal",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check EEOC Charge Portal",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check E-Verify API",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check HRIS Integration",
            "type": "main",
            "index": 0
          },
          {
            "node": "Check Payroll API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Evaluate Status Changes": {
      "main": [
        [
          {
            "node": "IF Alerts Exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF Alerts Exist": {
      "main": [
        [
          {
            "node": "Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        []
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 4: HR Compliance Incident and Violation Pipeline

Routes 8 incident types to handlers with precise deadline calculations: ADA/FMLA immediate interactive process, I-9 audit 3-business-day response, EEOC charge 180-day window, WARN Act 60-day notice, CCPA data requests, data breach employee PII. Includes self-hosting rationale per handler.

{
  "name": "HR Compliance Incident and Violation Pipeline",
  "nodes": [
    {
      "id": "i1",
      "name": "Incident Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        0,
        0
      ],
      "parameters": {
        "path": "hrtech-incident",
        "responseMode": "onReceived"
      }
    },
    {
      "id": "i2",
      "name": "Route by Incident Type",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3,
      "position": [
        220,
        0
      ],
      "parameters": {
        "mode": "rules",
        "rules": {
          "values": [
            {
              "outputKey": "ada_fmla_leave",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "ADA_FMLA_LEAVE_REQUEST_RECEIVED"
                  }
                ]
              }
            },
            {
              "outputKey": "i9_audit",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "I9_AUDIT_NOTICE_RECEIVED"
                  }
                ]
              }
            },
            {
              "outputKey": "eeoc_charge",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "EEOC_CHARGE_FILED"
                  }
                ]
              }
            },
            {
              "outputKey": "fmla_request",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "FMLA_ELIGIBILITY_REQUEST"
                  }
                ]
              }
            },
            {
              "outputKey": "flsa_complaint",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "FLSA_OVERTIME_COMPLAINT_DOL"
                  }
                ]
              }
            },
            {
              "outputKey": "warn_layoff",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "WARN_ACT_MASS_LAYOFF_PLANNED"
                  }
                ]
              }
            },
            {
              "outputKey": "ccpa_request",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "CCPA_EMPLOYEE_DATA_REQUEST"
                  }
                ]
              }
            },
            {
              "outputKey": "data_breach",
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.incident_type }}",
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "rightValue": "DATA_BREACH_EMPLOYEE_PII"
                  }
                ]
              }
            }
          ]
        }
      }
    },
    {
      "id": "i3",
      "name": "ADA FMLA Leave Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        -350
      ],
      "parameters": {
        "jsCode": "// ADA 42 USC \u00a712112(b)(5) + FMLA 29 CFR \u00a7825.300\n// Interactive process obligation triggered IMMEDIATELY on request\n// FMLA eligibility notice required within 5 business days (\u00a7825.300(b))\n// FMLA designation notice required within 5 business days of sufficient info (\u00a7825.300(d))\n// Medical certification: employee has 15 calendar days to provide (\u00a7825.305(b))\nconst now = new Date();\nconst d5biz = new Date();\nlet bdays = 0;\nconst calc = new Date();\nwhile (bdays < 5) {\n  calc.setDate(calc.getDate() + 1);\n  if (calc.getDay() !== 0 && calc.getDay() !== 6) bdays++;\n}\nreturn [{json: {\n  incident_type: 'ADA_FMLA_LEAVE_REQUEST_RECEIVED',\n  regulation: 'ADA 42 USC \u00a712112(b)(5) + FMLA 29 CFR \u00a7825.300',\n  immediate_action: 'Begin interactive process NOW. Do NOT deny or delay \u2014 failure to engage in interactive process is per se ADA violation.',\n  eligibility_notice_deadline: calc.toISOString(),\n  eligibility_notice_deadline_days: '5 business days',\n  medical_cert_deadline_days: 15,\n  self_hosting_note: 'FMLA \u00a7825.500(b): medical certifications must be maintained in a confidential file SEPARATE from personnel records. Any system that co-processes medical certification data with HR records = confidentiality violation. Cloud iPaaS routing FMLA medical data = undocumented subprocessor with access to protected health information.',\n  severity: 'CRITICAL',\n  recipients: ['hr-director@company.com', 'legal@company.com', 'employee-relations@company.com']\n}}];"
      }
    },
    {
      "id": "i4",
      "name": "I-9 Audit Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        -250
      ],
      "parameters": {
        "jsCode": "// ICE Notice of Inspection: employer must produce I-9 forms within 3 business days\n// I-9 8 USC \u00a71324a(b)(3) \u2014 failure to produce = $242-$2,360 per violation\nconst now = new Date();\nlet bdays = 0;\nconst d3 = new Date();\nwhile (bdays < 3) {\n  d3.setDate(d3.getDate() + 1);\n  if (d3.getDay() !== 0 && d3.getDay() !== 6) bdays++;\n}\nreturn [{json: {\n  incident_type: 'I9_AUDIT_NOTICE_RECEIVED',\n  regulation: '8 USC \u00a71324a(b)(3)',\n  deadline_utc: d3.toISOString(),\n  deadline_business_days: 3,\n  action: 'Produce all I-9 forms within 3 business days. I-9 retention check: 3 years from hire date OR 1 year after termination, whichever is later. Civil penalty $242-$2,360 per unauthorized worker for first offense.',\n  severity: 'CRITICAL'\n}}];"
      }
    },
    {
      "id": "i5",
      "name": "EEOC Charge Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        -150
      ],
      "parameters": {
        "jsCode": "// EEOC charge: 180-day investigation period; employer position statement typically due 30-40 days from charge notice\n// 42 USC \u00a72000e-5(b): EEOC notifies employer within 10 days of charge filing\nconst deadline180 = new Date();\ndeadline180.setDate(deadline180.getDate() + 180);\nconst posStatement = new Date();\nposStatement.setDate(posStatement.getDate() + 30);\nreturn [{json: {\n  incident_type: 'EEOC_CHARGE_FILED',\n  regulation: '42 USC \u00a72000e-5(b)',\n  investigation_deadline: deadline180.toISOString(),\n  position_statement_target: posStatement.toISOString(),\n  deadline_days: 180,\n  action: 'Retain employment law counsel immediately. Preserve all relevant documents and communications (litigation hold). Prepare position statement within 30 days of charge notice. Offer mediation under EEOC Mediation Program \u2014 resolves ~75% of mediated cases.',\n  self_hosting_note: 'EEOC charge documentation contains employee complaint details, personnel records, and investigation communications. Routing through Zapier/Make cloud = CCPA employee data egress \u2014 potential additional liability.',\n  severity: 'HIGH'\n}}];"
      }
    },
    {
      "id": "i6",
      "name": "FMLA Eligibility Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        -50
      ],
      "parameters": {
        "jsCode": "// FMLA 29 CFR \u00a7825.300(b): eligibility notice within 5 business days\n// 29 CFR \u00a7825.300(d): designation notice within 5 business days of receiving sufficient information\nconst d5e = new Date();\nlet bedays = 0;\nwhile (bedays < 5) {\n  d5e.setDate(d5e.getDate() + 1);\n  if (d5e.getDay() !== 0 && d5e.getDay() !== 6) bedays++;\n}\nreturn [{json: {\n  incident_type: 'FMLA_ELIGIBILITY_REQUEST',\n  regulation: '29 CFR \u00a7825.300(b)(d)',\n  eligibility_notice_deadline: d5e.toISOString(),\n  deadline_business_days: 5,\n  action: 'Send FMLA eligibility notice (Form WH-381) within 5 business days. If eligible and sufficient info: send designation notice (WH-382) within 5 business days. Request medical certification \u2014 employee has 15 calendar days to return (\u00a7825.305(b)).',\n  severity: 'HIGH'\n}}];"
      }
    },
    {
      "id": "i7",
      "name": "FLSA Complaint Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        50
      ],
      "parameters": {
        "jsCode": "// FLSA 29 USC \u00a7216(b): DOL investigation or private civil action\n// Willful violation: 3-year statute of limitations + liquidated damages (double back pay)\n// Non-willful: 2-year statute of limitations\nconst d3yr = new Date();\nd3yr.setFullYear(d3yr.getFullYear() + 3);\nreturn [{json: {\n  incident_type: 'FLSA_OVERTIME_COMPLAINT_DOL',\n  regulation: '29 USC \u00a7207 + \u00a7216(b) + \u00a7255(a)',\n  willful_limitation_deadline: d3yr.toISOString(),\n  limitation_years_willful: 3,\n  limitation_years_nonwillful: 2,\n  action: 'Conduct immediate payroll audit for 3-year lookback period. Calculate potential back pay exposure. Preserve all payroll records, time records, and classification decisions. Assess exempt/non-exempt classification accuracy for all affected employees.',\n  self_hosting_note: 'DOL investigation = subpoena of payroll processing system records. Cloud iPaaS audit logs for payroll workflows are third-party records, not employer records \u2014 creates discovery gap. Self-hosted n8n payroll automation logs are employer-owned and auditable.',\n  severity: 'HIGH'\n}}];"
      }
    },
    {
      "id": "i8",
      "name": "WARN Act Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        150
      ],
      "parameters": {
        "jsCode": "// WARN Act 29 USC \u00a72102: 60 calendar days written advance notice\n// Penalty: up to 60 days back pay + benefits per affected worker, plus civil penalty $500/day to local government\nconst deadline60 = new Date();\ndeadline60.setDate(deadline60.getDate() + 60);\nreturn [{json: {\n  incident_type: 'WARN_ACT_MASS_LAYOFF_PLANNED',\n  regulation: '29 USC \u00a72102(a)',\n  notice_deadline: deadline60.toISOString(),\n  advance_notice_days: 60,\n  action: 'Issue WARN notices immediately to: (1) affected workers, (2) state dislocated worker unit, (3) chief elected official of local government unit. Include: expected layoff date, job titles/counts, bumping rights if applicable. Check state WARN equivalents (CA WARN requires 60 days for 50+ workers regardless of plant-closing definition).',\n  severity: 'CRITICAL'\n}}];"
      }
    },
    {
      "id": "i9",
      "name": "CCPA Employee Data Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        250
      ],
      "parameters": {
        "jsCode": "// CCPA Civil Code \u00a71798.130: 45-day response window for data access/deletion/correction requests\n// CPRA expansion: employee data fully covered as of Jan 2023\nconst deadline45 = new Date();\ndeadline45.setDate(deadline45.getDate() + 45);\nreturn [{json: {\n  incident_type: 'CCPA_EMPLOYEE_DATA_REQUEST',\n  regulation: 'Cal. Civil Code \u00a71798.130 + CPRA',\n  deadline_utc: deadline45.toISOString(),\n  deadline_days: 45,\n  action: 'Locate all personal information for employee: payroll records, benefits data, performance reviews, HRIS records, background check data, I-9 documents. Respond within 45 days (one 45-day extension allowed with notice).',\n  severity: 'MEDIUM'\n}}];"
      }
    },
    {
      "id": "i10",
      "name": "Data Breach Employee PII Handler",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        350
      ],
      "parameters": {
        "jsCode": "// CCPA Civil Code \u00a71798.82: breach notification to affected employees within 45 days\n// GDPR Art. 33 (if EU employees): 72h notification to supervisory authority\n// Many state laws: 30-60 days to affected employees\nconst d72h = new Date();\nd72h.setHours(d72h.getHours() + 72);\nconst d45 = new Date();\nd45.setDate(d45.getDate() + 45);\nreturn [{json: {\n  incident_type: 'DATA_BREACH_EMPLOYEE_PII',\n  regulation: 'CCPA \u00a71798.82 + GDPR Art. 33 + state breach notification laws',\n  gdpr_supervisory_deadline: d72h.toISOString(),\n  gdpr_deadline_hours: 72,\n  ccpa_notification_deadline: d45.toISOString(),\n  ccpa_deadline_days: 45,\n  action: 'GDPR (EU employees): notify supervisory authority within 72 hours. CCPA/state: notify affected California employees within 45 days. Determine scope: SSN, salary, ADA/FMLA medical info, I-9 documents, direct deposit data.',\n  self_hosting_note: 'Employee PII breach scope analysis requires knowing exactly which systems processed the data. Cloud iPaaS = third-party processor \u2014 requires subprocessor breach notification chain. Self-hosted n8n = single-tenant system \u2014 breach scope is fully deterministic from your own audit logs.',\n  severity: 'CRITICAL'\n}}];"
      }
    },
    {
      "id": "i11",
      "name": "Log All Incidents",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "parameters": {
        "operation": "insert",
        "table": "hrtech_compliance_incidents",
        "columns": "incident_type,regulation,severity,created_at",
        "additionalFields": {}
      }
    }
  ],
  "connections": {
    "Incident Webhook": {
      "main": [
        [
          {
            "node": "Route by Incident Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Incident Type": {
      "ada_fmla_leave": [
        [
          {
            "node": "ADA FMLA Leave Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "i9_audit": [
        [
          {
            "node": "I-9 Audit Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "eeoc_charge": [
        [
          {
            "node": "EEOC Charge Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "fmla_request": [
        [
          {
            "node": "FMLA Eligibility Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "flsa_complaint": [
        [
          {
            "node": "FLSA Complaint Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "warn_layoff": [
        [
          {
            "node": "WARN Act Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "ccpa_request": [
        [
          {
            "node": "CCPA Employee Data Handler",
            "type": "main",
            "index": 0
          }
        ]
      ],
      "data_breach": [
        [
          {
            "node": "Data Breach Employee PII Handler",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 5: Weekly HR Platform KPI Dashboard

Monday 8AM: queries active customers by tier, compliance incidents by type, onboarding health. Uses $getWorkflowStaticData for MRR week-over-week comparison. Emails CHRO + VP Compliance. Adds data sovereignty footnote.

{
  "name": "Weekly HR Platform KPI Dashboard",
  "nodes": [
    {
      "id": "k1",
      "name": "Monday 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1"
            }
          ]
        }
      }
    },
    {
      "id": "k2",
      "name": "Query Active Customers",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        220,
        -100
      ],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as active_customers, COUNT(CASE WHEN tier='ENTERPRISE_HCM_PLATFORM' THEN 1 END) as enterprise, COUNT(CASE WHEN tier='MIDMARKET_PAYROLL_SAAS' THEN 1 END) as midmarket_payroll, SUM(mrr_usd) as total_mrr FROM hrtech_customers WHERE status='ACTIVE'"
      }
    },
    {
      "id": "k3",
      "name": "Query Compliance Incidents",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        220,
        0
      ],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as total_incidents_7d, COUNT(CASE WHEN incident_type LIKE 'EEOC%' THEN 1 END) as eeoc_incidents, COUNT(CASE WHEN incident_type LIKE 'FLSA%' THEN 1 END) as flsa_incidents, COUNT(CASE WHEN severity='CRITICAL' THEN 1 END) as critical_open FROM hrtech_compliance_incidents WHERE created_at >= NOW() - INTERVAL '7 days'"
      }
    },
    {
      "id": "k4",
      "name": "Query Onboarding Health",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2,
      "position": [
        220,
        100
      ],
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as new_customers_7d, COUNT(CASE WHEN onboarding_complete=true THEN 1 END) as completed_onboarding, ROUND(AVG(CASE WHEN onboarding_complete=true THEN days_to_onboard END), 1) as avg_days_to_onboard FROM hrtech_onboarding_events WHERE created_at >= NOW() - INTERVAL '7 days'"
      }
    },
    {
      "id": "k5",
      "name": "Build KPI Email",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        440,
        0
      ],
      "parameters": {
        "jsCode": "const customers = $('Query Active Customers').first().json;\nconst incidents = $('Query Compliance Incidents').first().json;\nconst onboarding = $('Query Onboarding Health').first().json;\nconst state = $getWorkflowStaticData('global');\nconst prevMrr = state.prev_mrr || customers.total_mrr;\nconst mrrWoW = prevMrr > 0 ? (((customers.total_mrr - prevMrr) / prevMrr) * 100).toFixed(1) : 'N/A';\nstate.prev_mrr = customers.total_mrr;\n$setWorkflowStaticData('global', state);\nconst html = `<h2>HRTech Platform KPI \u2014 Week of ${new Date().toISOString().split('T')[0]}</h2>\n<h3>Customers & Revenue</h3>\n<table border=1><tr><th>Active Customers</th><th>Enterprise HCM</th><th>Midmarket Payroll</th><th>MRR</th><th>MRR WoW</th></tr>\n<tr><td>${customers.active_customers}</td><td>${customers.enterprise}</td><td>${customers.midmarket_payroll}</td><td>$${Number(customers.total_mrr).toLocaleString()}</td><td>${mrrWoW}%</td></tr></table>\n<h3>Compliance Incidents (Last 7 Days)</h3>\n<table border=1><tr><th>Total</th><th>EEOC</th><th>FLSA</th><th>Critical Open</th></tr>\n<tr><td>${incidents.total_incidents_7d}</td><td>${incidents.eeoc_incidents}</td><td>${incidents.flsa_incidents}</td><td>${incidents.critical_open}</td></tr></table>\n<h3>Onboarding</h3>\n<table border=1><tr><th>New (7d)</th><th>Completed Onboarding</th><th>Avg Days to Onboard</th></tr>\n<tr><td>${onboarding.new_customers_7d}</td><td>${onboarding.completed_onboarding}</td><td>${onboarding.avg_days_to_onboard}</td></tr></table>\n<p><em>Data sovereignty note: employee SSN, salary records, ADA medical info, FMLA certifications, and I-9 documents processed by your platform are regulated under FLSA \u00a7211, FMLA \u00a7825.500, and ADA \u00a712112(d)(3). This workflow runs inside your security perimeter \u2014 no employee data leaves your VPC.</em></p>`;\nreturn [{json: {html}}];"
      }
    },
    {
      "id": "k6",
      "name": "Email CEO CHRO VP Compliance",
      "type": "n8n-nodes-base.emailSend",
      "typeVersion": 2,
      "position": [
        660,
        0
      ],
      "parameters": {
        "fromEmail": "n8n-compliance@company.com",
        "toEmail": "ceo@company.com",
        "ccEmail": "chro@company.com,vp-hr-compliance@company.com",
        "subject": "HRTech Platform KPI Dashboard \u2014 {{ $now.format('YYYY-MM-DD') }}",
        "emailType": "html",
        "message": "={{ $json.html }}"
      }
    }
  ],
  "connections": {
    "Monday 8AM": {
      "main": [
        [
          {
            "node": "Query Active Customers",
            "type": "main",
            "index": 0
          },
          {
            "node": "Query Compliance Incidents",
            "type": "main",
            "index": 0
          },
          {
            "node": "Query Onboarding Health",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query Onboarding Health": {
      "main": [
        [
          {
            "node": "Build KPI Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build KPI Email": {
      "main": [
        [
          {
            "node": "Email CEO CHRO VP Compliance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Comparison: n8n vs Zapier/Make for HRTech Compliance

Requirement Self-hosted n8n Zapier / Make
FMLA §825.500 medical confidentiality Runs in customer VPC — no third-party access Medical cert data in Zapier cloud — §825.500 violation
ADA §12112(d)(3) medical file separation Customer controls data boundary entirely Cloud subprocessor has access to accommodation records
I-9 audit response (3 business days) Audit log is employer-owned record Third-party logs — discovery gap in ICE audit
CCPA/CPRA employee data subprocessor Customer's own infrastructure — no DPA gap Undocumented subprocessor for employee PII
FLSA payroll record audit chain Full execution log in customer's Postgres Third-party execution log — not employer record
EEOC charge documentation privilege Legal hold within employer's control boundary Litigation hold requires notifying third-party cloud

Get the FlowKit HRTech Template Pack

All 5 workflows above — plus onboarding sequences, API monitors, compliance trackers, and KPI dashboards for 20+ B2B SaaS verticals — are available at stripeai.gumroad.com.

Import-ready JSON. Self-host inside your customers' security perimeters. Close the enterprise compliance gap.

Top comments (0)