HRTech and WorkforceTech SaaS vendors — HRIS platforms, payroll processors, ATS/recruiting tools, benefits administrators, workforce management systems, and PEOs — sit at the intersection of some of the most operationally demanding compliance regimes in US employment law.
An EEOC EEO-1 Component 1 filing missed by a single day triggers federal district court enforcement. An FLSA §11(c) payroll record gap discovered during a DOL Wage & Hour audit exposes back pay liability for the entire retention period. An FCRA §1681b(b)(3)(A) adverse action notice sent one business day late is a per-candidate statutory violation with class action risk. A WARN Act 29 USC §2101 60-day notice failure carries back pay + benefits for every affected employee plus $500/day in civil penalties. Routing any of this through Zapier or Make creates a data egress trail that becomes a finding in every enterprise HR tech security review.
This post gives you five production-ready n8n workflow JSON files covering the compliance operations that HRTech SaaS vendors must automate for their customers.
Who This Is For
SaaS companies building and selling HR, payroll, benefits, recruiting, and workforce software:
| Tier | Description |
|---|---|
| ENTERPRISE_HRIS_VENDOR | Large HRIS platforms (10K+ employee clients) — EEOC EEO-1, ERISA Form 5500, OSHA 300, WARN Act, OFCCP AAP |
| MID_MARKET_HR_PLATFORM | Mid-market HR SaaS — FLSA §11(c) retention, OSHA 300A, FCRA background check integration |
| PAYROLL_PROCESSOR | Payroll SaaS — FLSA §11(c) 3yr payroll records, wage garnishment lifecycle, DOL audit readiness |
| BENEFITS_ADMIN_VENDOR | Benefits administration — ERISA §209 5yr records, Form 5500 (§104), SAR distribution (§104(b)(3)), SPD (§104(b)(1)) |
| RECRUITING_PLATFORM | ATS/talent acquisition — FCRA §1681b background check, adverse action pipeline, EEOC applicant flow tracking |
| WORKFORCE_MGMT_VENDOR | Scheduling/time-tracking platforms — FLSA overtime classification, WARN Act headcount monitoring |
| PEO_EMPLOYER_ORG | PEOs — co-employment EEOC EEO-1 joint filing, ERISA multi-client plan, OSHA 300 per-client worksite |
Compliance flags set during onboarding:
| Flag | Trigger |
|---|---|
| EEOC_EEO1_COVERED | 100+ employees OR federal contractor |
| FLSA_OVERTIME_APPLICABLE | Non-exempt employees on payroll |
| ERISA_PLAN_SPONSOR | Offers 401(k) or group health plan |
| OSHA_PART_1904_APPLICABLE | SIC code subject to 29 CFR Part 1904 recordkeeping |
| FCRA_BACKGROUND_CHECK_USER | Runs consumer background reports on applicants |
| WARN_ACT_COVERED | 100+ employees (federal threshold) |
| OFCCP_FEDERAL_CONTRACTOR | Federal contract ≥ $50,000 + 50+ employees |
Workflow 1: HRTech Customer Onboarding Drip
A webhook receives new customer signup data. A Code node classifies the account into one of the seven tiers above and sets the seven compliance flags. A Switch node routes to tier-specific Day 0 emails:
- ENTERPRISE_HRIS_VENDOR: EEOC EEO-1 Component 1 pre-fill automation (29 CFR Part 1602 March 31 deadline), FLSA §11(c) 3-year payroll record retention classifier, ERISA §209 5-year benefit record archival workflow, OSHA 300 log 29 CFR Part 1904 annual update pipeline, WARN Act 29 USC §2101 60-day notice tracker, OFCCP 41 CFR Part 60 AAP annual update reminder.
- PAYROLL_PROCESSOR: FLSA §11(c) 3-year payroll register retention by record class, DOL audit response SLA setup, state wage payment law multi-jurisdiction tracker.
- RECRUITING_PLATFORM: FCRA 15 USC §1681b disclosure/consent workflow, pre-adverse action 5-business-day window tracker, adverse action notice with §1613 dispute rights.
- Default tiers: FLSA §11(c) retention setup, OSHA 300A posting reminder (Feb 1), EEOC EEO-1 March 31 deadline alert.
Day 3 follow-up sends API integration guides by tier. Day 7 invites to a compliance workflow review.
Import the JSON below to deploy this workflow:
{
"name": "HRTech Customer Onboarding Drip",
"nodes": [
{
"id": "w1n1",
"name": "New HRTech Signup",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
],
"parameters": {
"path": "hrtech-onboarding",
"httpMethod": "POST",
"responseMode": "responseNode"
}
},
{
"id": "w1n2",
"name": "Classify Tier & Compliance Flags",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
300
],
"parameters": {
"jsCode": "const d = $input.first().json;\nconst tier = d.employee_count >= 10000 ? 'ENTERPRISE_HRIS_VENDOR' :\n d.product_type === 'payroll_saas' ? 'PAYROLL_PROCESSOR' :\n d.product_type === 'benefits_admin' ? 'BENEFITS_ADMIN_VENDOR' :\n d.product_type === 'ats_recruiting' ? 'RECRUITING_PLATFORM' :\n d.product_type === 'workforce_mgmt' ? 'WORKFORCE_MGMT_VENDOR' :\n d.product_type === 'peo' ? 'PEO_EMPLOYER_ORG' :\n 'MID_MARKET_HR_PLATFORM';\nconst flags = {\n EEOC_EEO1_COVERED: d.employee_count >= 100 || d.federal_contractor === true,\n FLSA_OVERTIME_APPLICABLE: d.non_exempt_employees > 0,\n ERISA_PLAN_SPONSOR: d.offers_401k === true || d.offers_health_plan === true,\n OSHA_PART_1904_APPLICABLE: d.industry_sic_covered === true,\n FCRA_BACKGROUND_CHECK_USER: d.runs_background_checks === true,\n WARN_ACT_COVERED: d.employee_count >= 100,\n OFCCP_FEDERAL_CONTRACTOR: d.federal_contractor === true && d.contract_value_usd >= 50000\n};\nreturn [{ json: { ...d, tier, complianceFlags: flags, onboarding_ts: new Date().toISOString() } }];"
}
},
{
"id": "w1n3",
"name": "Day0 Tier Email",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
700,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.tier }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "ENTERPRISE_HRIS_VENDOR"
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.tier }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "PAYROLL_PROCESSOR"
}
]
},
"outputIndex": 1
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.tier }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "RECRUITING_PLATFORM"
}
]
},
"outputIndex": 2
}
]
},
"fallbackOutput": "last"
}
},
{
"id": "w1n4",
"name": "Day0 Enterprise HRIS Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
160
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "Your n8n HRIS compliance kit \u2014 EEO-1, FLSA 3yr, ERISA 5yr, OSHA 300 log",
"message": "Welcome to FlowKit. Attached: EEOC EEO-1 Component 1 pre-fill automation (29 CFR Part 1602 March 31 deadline), FLSA \u00a711(c) 3-year payroll record retention classifier, ERISA \u00a7209 5-year benefit record archival workflow, OSHA 300 log 29 CFR Part 1904 annual update pipeline, and WARN Act 29 USC \u00a72101 60-day advance notice tracker. OFCCP 41 CFR Part 60 AAP annual update reminder is pre-configured. Reply to schedule your compliance workflow review."
}
},
{
"id": "w1n5",
"name": "Day0 Payroll Processor Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
300
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "FLSA payroll record retention automation ready \u2014 3yr \u00a711(c) compliant",
"message": "Welcome to FlowKit. Your FLSA \u00a711(c) 3-year payroll record retention pipeline is active. The workflow automatically classifies records by retention class (payroll registers 3yr, time cards 3yr, W-4 4yr, wage garnishments lifecycle), generates quarterly retention audits, and flags records approaching purge windows for legal hold review. ERISA pension record retention (5yr \u00a7209) is pre-configured for 401(k) plan sponsors. Reply to activate."
}
},
{
"id": "w1n6",
"name": "Day0 Recruiting Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
440
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "FCRA background check workflow ready \u2014 \u00a71681b disclosure, adverse action pipeline",
"message": "Welcome to FlowKit. Your FCRA 15 USC \u00a71681b compliance workflow is active: (1) pre-adverse action notice with \u00a71681b(b)(3)(A) consumer report summary, (2) 5-business-day adverse action window tracker, (3) final adverse action notice with \u00a71613 dispute rights disclosure. EEOC EEO-1 applicant flow tracking for 100+ employee clients is pre-configured. Reply to schedule your FCRA pipeline review."
}
},
{
"id": "w1n7",
"name": "Day0 Default Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
580
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "Your n8n HR compliance automation is ready",
"message": "Welcome to FlowKit. Based on your profile, we have configured: FLSA \u00a711(c) payroll record retention, OSHA 300 log automation (29 CFR Part 1904), and EEOC EEO-1 deadline tracking (29 CFR Part 1602). If you run background checks, your FCRA \u00a71681b pipeline is ready. Reply to schedule onboarding."
}
},
{
"id": "w1n8",
"name": "Log to CRM",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1140,
300
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "hrtech_customers",
"columns": "email,company,tier,compliance_flags,onboarding_ts",
"values": "={{ $json.email }},={{ $json.company }},={{ $json.tier }},={{ JSON.stringify($json.complianceFlags) }},={{ $json.onboarding_ts }}"
}
}
],
"connections": {
"New HRTech Signup": {
"main": [
[
{
"node": "Classify Tier & Compliance Flags",
"type": "main",
"index": 0
}
]
]
},
"Classify Tier & Compliance Flags": {
"main": [
[
{
"node": "Day0 Tier Email",
"type": "main",
"index": 0
}
]
]
},
"Day0 Tier Email": {
"main": [
[
{
"node": "Day0 Enterprise HRIS Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day0 Payroll Processor Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day0 Recruiting Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day0 Default Email",
"type": "main",
"index": 0
}
]
]
},
"Day0 Enterprise HRIS Email": {
"main": [
[
{
"node": "Log to CRM",
"type": "main",
"index": 0
}
]
]
},
"Day0 Payroll Processor Email": {
"main": [
[
{
"node": "Log to CRM",
"type": "main",
"index": 0
}
]
]
},
"Day0 Recruiting Email": {
"main": [
[
{
"node": "Log to CRM",
"type": "main",
"index": 0
}
]
]
},
"Day0 Default Email": {
"main": [
[
{
"node": "Log to CRM",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: HR Compliance API & Portal Health Monitor
Runs every 30 minutes. Polls five critical HR compliance endpoints. Uses $getWorkflowStaticData to track UP-to-DOWN state transitions — alerting only when a new outage is detected, not on every poll.
| Endpoint | Regulatory Annotation |
|---|---|
| eeoc_eeo1_portal | EEOC 29 CFR Part 1602 — EEO-1 Component 1 filing gap; March 31 deadline at risk if portal down >24h |
| osha_300_api | OSHA 29 CFR Part 1904 — injury/illness recordkeeping gap; Form 300A posting deadline Feb 1 at risk |
| payroll_record_api | FLSA §11(c) 3yr retention — payroll register gap; DOL audit response window at risk |
| benefits_api | ERISA §209 5yr retention — SPD/SAR/Form 5500 chain gap; DOL EBSA audit risk |
| ats_fcra_queue | FCRA 15 USC §1681b — background check adverse action window clock at risk; §1681b(b)(3)(A) 5-day notice gap |
On DOWN detection: Slack alert to #hr-compliance-ops with regulation citation. OSHA 300 API outage triggers additional #osha-ops page — the Form 300A Feb 1 posting window has a hard annual deadline.
{
"name": "HR Compliance API & Portal Health Monitor",
"nodes": [
{
"id": "w2n1",
"name": "Every 30 Min",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
260,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 30
}
]
}
}
},
{
"id": "w2n2",
"name": "Load Previous States",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"jsCode": "return [{ json: { prev: $getWorkflowStaticData('global').endpointStatus || {} } }];"
}
},
{
"id": "w2n3",
"name": "Poll EEOC EEO-1 Portal",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
180
],
"parameters": {
"url": "https://eeoccomp2.norc.org/api/health",
"method": "GET",
"options": {
"timeout": 15000
}
}
},
{
"id": "w2n4",
"name": "Poll OSHA 300 Log API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
300
],
"parameters": {
"url": "={{ $env.OSHA_API_URL }}/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n5",
"name": "Poll Payroll Record API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
420
],
"parameters": {
"url": "={{ $env.PAYROLL_API_URL }}/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n6",
"name": "Poll Benefits Admin API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
540
],
"parameters": {
"url": "={{ $env.BENEFITS_API_URL }}/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n7",
"name": "Poll ATS FCRA Queue",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
660
],
"parameters": {
"url": "={{ $env.ATS_API_URL }}/fcra-queue/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n8",
"name": "Detect DOWN Transitions",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
880,
300
],
"parameters": {
"jsCode": "const prev = $('Load Previous States').first().json.prev;\nconst endpoints = [\n { name: 'eeoc_eeo1_portal', label: 'EEOC EEO-1 Portal', regulation: 'EEOC 29 CFR Part 1602 \u2014 EEO-1 Component 1 filing gap; March 31 deadline at risk if portal down >24h', node: 'Poll EEOC EEO-1 Portal' },\n { name: 'osha_300_api', label: 'OSHA 300 Log API', regulation: 'OSHA 29 CFR Part 1904 \u2014 injury/illness recordkeeping gap; Form 300A posting deadline Feb 1 at risk', node: 'Poll OSHA 300 Log API' },\n { name: 'payroll_record_api', label: 'Payroll Record API', regulation: 'FLSA \u00a711(c) 3yr retention \u2014 payroll register gap; DOL audit response window at risk', node: 'Poll Payroll Record API' },\n { name: 'benefits_api', label: 'Benefits Admin API', regulation: 'ERISA \u00a7209 5yr retention \u2014 SPD/SAR/Form 5500 chain gap; DOL EBSA audit risk', node: 'Poll Benefits Admin API' },\n { name: 'ats_fcra_queue', label: 'ATS FCRA Queue', regulation: 'FCRA 15 USC \u00a71681b \u2014 background check adverse action window clock at risk; \u00a71681b(b)(3)(A) 5-day notice gap', node: 'Poll ATS FCRA Queue' }\n];\nconst alerts = [];\nfor (const ep of endpoints) {\n let status = 'OK';\n try {\n const r = $node[ep.node].json;\n if (!r || r.error || (r.statusCode && r.statusCode >= 400)) status = 'DOWN';\n } catch(e) { status = 'DOWN'; }\n if (prev[ep.name] === 'OK' && status === 'DOWN') alerts.push({ ...ep, status, ts: new Date().toISOString() });\n prev[ep.name] = status;\n}\n$getWorkflowStaticData('global').endpointStatus = prev;\nreturn alerts.length ? alerts.map(a => ({ json: a })) : [{ json: { noAlerts: true } }];"
}
},
{
"id": "w2n9",
"name": "Alert Slack #hr-compliance",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1080,
300
],
"parameters": {
"channel": "#hr-compliance-ops",
"text": "=[OUTAGE] {{ $json.label }} is DOWN\nRegulation: {{ $json.regulation }}\nTime: {{ $json.ts }}"
}
}
],
"connections": {
"Every 30 Min": {
"main": [
[
{
"node": "Load Previous States",
"type": "main",
"index": 0
}
]
]
},
"Load Previous States": {
"main": [
[
{
"node": "Poll EEOC EEO-1 Portal",
"type": "main",
"index": 0
},
{
"node": "Poll OSHA 300 Log API",
"type": "main",
"index": 0
},
{
"node": "Poll Payroll Record API",
"type": "main",
"index": 0
},
{
"node": "Poll Benefits Admin API",
"type": "main",
"index": 0
},
{
"node": "Poll ATS FCRA Queue",
"type": "main",
"index": 0
}
]
]
},
"Poll EEOC EEO-1 Portal": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll OSHA 300 Log API": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll Payroll Record API": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll Benefits Admin API": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll ATS FCRA Queue": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Detect DOWN Transitions": {
"main": [
[
{
"node": "Alert Slack #hr-compliance",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: FLSA/ERISA/OSHA/FCRA/WARN/OFCCP Compliance Deadline Tracker
Runs weekdays at 8 AM. Loads open compliance deadlines from Postgres. A Code node assigns urgency and enriches each deadline with its regulatory citation and penalty detail.
12 deadline types tracked:
| Deadline Type | Regulation | Penalty |
|---|---|---|
| EEOC_EEO1_ANNUAL_FILING | 29 CFR §1602.7 — March 31 | Federal court enforcement |
| FLSA_PAYROLL_RECORD_AUDIT | FLSA §11(c) 29 CFR §516 — 3yr | DOL back pay + liquidated damages |
| ERISA_FORM_5500_ANNUAL | ERISA §104 — 7 months after plan year | $250/day up to $150K per §502(c)(2) |
| ERISA_SAR_DISTRIBUTION | ERISA §104(b)(3) — 9 months after plan year | $110/day per §502(c) |
| OSHA_300A_POSTING | 29 CFR §1904.32 — Feb 1 through Apr 30 | $16,131/violation; $161,323 willful |
| OSHA_300_ANNUAL_SUBMISSION | 29 CFR §1904.41 — March 2 (250+ employees) | $16,131/violation |
| FCRA_ADVERSE_ACTION_WINDOW | 15 USC §1681b(b)(3)(A) — 5 business days | $100-$1,000/violation; class action |
| WARN_ACT_60_DAY_NOTICE | 29 USC §2101 — 60 days before layoff | 60 days back pay + benefits + $500/day |
| OFCCP_AAP_ANNUAL_UPDATE | 41 CFR §60-2.10 — 120 days after fiscal year | OFCCP debarment |
| OFCCP_VETS_4212_ANNUAL | 41 CFR §61-300 — Sep 30 | Contract debarment; $5,000 fine |
| ERISA_SPD_DISTRIBUTION | ERISA §104(b)(1) — 90 days / 5-year cycle | $110/day per §502(c) |
| SOC2_ANNUAL_AUDIT | SOC2 Type II — annual cycle | Enterprise contract loss |
Urgency routing: OVERDUE → Slack #hr-compliance-ops + email owner; CRITICAL (≤7d) → Slack alert; URGENT (≤21d) → email owner; WARNING (≤45d) → logged.
{
"name": "FLSA/ERISA/OSHA/FCRA/WARN/OFCCP Compliance Deadline Tracker",
"nodes": [
{
"id": "w3n1",
"name": "Weekdays 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
260,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1-5"
}
]
}
}
},
{
"id": "w3n2",
"name": "Load HR Deadlines",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"operation": "select",
"schema": "public",
"table": "hr_compliance_deadlines",
"additionalFields": {
"where": "status = 'OPEN'"
}
}
},
{
"id": "w3n3",
"name": "Classify Urgency",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
300
],
"parameters": {
"jsCode": "const deadlineTypes = {\n EEOC_EEO1_ANNUAL_FILING: { reg: 'EEOC 29 CFR \u00a71602.7 \u2014 EEO-1 Component 1', dueDesc: 'March 31 annually', penalty: 'Federal district court enforcement' },\n FLSA_PAYROLL_RECORD_AUDIT: { reg: 'FLSA \u00a711(c) 29 CFR \u00a7516 \u2014 3yr payroll records', dueDesc: 'Continuous \u2014 DOL audit readiness', penalty: 'DOL Wage & Hour investigation; back pay + liquidated damages' },\n ERISA_FORM_5500_ANNUAL: { reg: 'ERISA \u00a7104 \u2014 Form 5500 Annual Return', dueDesc: '7 months after plan year end (Jul 31 for calendar year)', penalty: '$250/day up to $150K per \u00a7502(c)(2)' },\n ERISA_SAR_DISTRIBUTION: { reg: 'ERISA \u00a7104(b)(3) \u2014 Summary Annual Report', dueDesc: '9 months after plan year end (Sep 30 for calendar year)', penalty: '$110/day per \u00a7502(c)' },\n OSHA_300A_POSTING: { reg: 'OSHA 29 CFR \u00a71904.32 \u2014 Form 300A annual summary posting', dueDesc: 'Feb 1 through Apr 30', penalty: '$16,131/violation; willful $161,323' },\n OSHA_300_ANNUAL_SUBMISSION: { reg: 'OSHA 29 CFR \u00a71904.41 \u2014 Electronic 300A submission (250+ employees)', dueDesc: 'March 2 annually', penalty: 'OSHA citation; $16,131/violation' },\n FCRA_ADVERSE_ACTION_WINDOW: { reg: 'FCRA 15 USC \u00a71681b(b)(3)(A) \u2014 pre-adverse action 5-day notice', dueDesc: 'Within 5 business days of adverse action intent', penalty: '$100-$1,000/violation; class action risk' },\n WARN_ACT_60_DAY_NOTICE: { reg: 'WARN Act 29 USC \u00a72101 \u2014 60-day advance notice mass layoff/plant closing', dueDesc: '60 calendar days before layoff date', penalty: '60 days back pay + benefits per employee; $500/day civil penalty' },\n OFCCP_AAP_ANNUAL_UPDATE: { reg: 'OFCCP 41 CFR \u00a760-2.10 \u2014 Affirmative Action Plan annual update', dueDesc: 'Within 120 days of fiscal year start', penalty: 'OFCCP debarment; contract cancellation' },\n OFCCP_VETS_4212_ANNUAL: { reg: 'OFCCP 41 CFR \u00a761-300 \u2014 VETS-4212 federal contractor hiring report', dueDesc: 'Sep 30 annually (Aug 1 filing window opens)', penalty: 'Contract debarment; $5,000 fine' },\n ERISA_SPD_DISTRIBUTION: { reg: 'ERISA \u00a7104(b)(1) \u2014 Summary Plan Description to new participants', dueDesc: '90 days of becoming covered / every 5 years', penalty: '$110/day per \u00a7502(c)' },\n SOC2_ANNUAL_AUDIT: { reg: 'SOC2 Type II \u2014 annual audit cycle for enterprise HR customers', dueDesc: 'Per audit contract \u2014 typically annual', penalty: 'Contract loss; enterprise customer churn' }\n};\nreturn $input.all().map(item => {\n const d = item.json;\n const dueDate = new Date(d.due_date);\n const today = new Date();\n const daysLeft = Math.floor((dueDate - today) / 86400000);\n const urgency = daysLeft < 0 ? 'OVERDUE' : daysLeft <= 7 ? 'CRITICAL' : daysLeft <= 21 ? 'URGENT' : daysLeft <= 45 ? 'WARNING' : 'NOTICE';\n const meta = deadlineTypes[d.deadline_type] || { reg: d.deadline_type, dueDesc: d.due_date, penalty: 'See regulation' };\n return { json: { ...d, daysLeft, urgency, ...meta } };\n}).filter(i => i.json.urgency !== 'NOTICE' || i.json.daysLeft <= 60);"
}
},
{
"id": "w3n4",
"name": "Route by Urgency",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
860,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "OVERDUE"
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "CRITICAL"
}
]
},
"outputIndex": 1
}
]
},
"fallbackOutput": "last"
}
},
{
"id": "w3n5",
"name": "Slack OVERDUE Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1060,
180
],
"parameters": {
"channel": "#hr-compliance-ops",
"text": "=[OVERDUE] {{ $json.deadline_type }} \u2014 {{ $json.reg }}\nClient: {{ $json.client_name }}\nPenalty risk: {{ $json.penalty }}\nOwner: {{ $json.owner_email }}"
}
},
{
"id": "w3n6",
"name": "Slack CRITICAL Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1060,
300
],
"parameters": {
"channel": "#hr-compliance-ops",
"text": "=[CRITICAL] {{ $json.deadline_type }} due in {{ $json.daysLeft }} days \u2014 {{ $json.reg }}\nClient: {{ $json.client_name }}\nOwner: {{ $json.owner_email }}"
}
},
{
"id": "w3n7",
"name": "Email Owner",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
1060,
420
],
"parameters": {
"toEmail": "={{ $json.owner_email }}",
"subject": "=[{{ $json.urgency }}] HR Compliance Deadline: {{ $json.deadline_type }} ({{ $json.daysLeft }} days)",
"message": "={{ $json.reg }}\nDue: {{ $json.dueDesc }}\nPenalty if missed: {{ $json.penalty }}\n\nAction required. Reply to confirm status."
}
}
],
"connections": {
"Weekdays 8AM": {
"main": [
[
{
"node": "Load HR Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Load HR Deadlines": {
"main": [
[
{
"node": "Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Classify Urgency": {
"main": [
[
{
"node": "Route by Urgency",
"type": "main",
"index": 0
}
]
]
},
"Route by Urgency": {
"main": [
[
{
"node": "Slack OVERDUE Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack CRITICAL Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Email Owner",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: HR Data Breach & FCRA/EEOC/WARN Incident Alert Pipeline
A webhook receives HR incidents. A Code node classifies them into 8 types with severity, regulatory citation, and clock deadline:
| Incident Type | Clock | Regulation |
|---|---|---|
| EMPLOYEE_PII_BREACH | 72h | State breach laws (Cal. Civ. Code §1798.82); HIPAA BAA if health data |
| PAYROLL_RECORD_UNAUTHORIZED_ACCESS | 24h internal | FLSA §11(c) audit trail; SOX if public company |
| ERISA_PLAN_DATA_EXPOSURE | 72h | ERISA §404 fiduciary duty; DOL EBSA notification |
| FCRA_UNAUTHORIZED_REPORT_ACCESS | 5 business days | FCRA §1681n willful violation; FTC/CFPB notification |
| WARN_ACT_FAILURE_TO_NOTIFY | 60 days (already in breach) | WARN 29 USC §2101; back pay + $500/day civil penalty |
| OSHA_REPORTABLE_FATALITY | 8 hours | OSHA §1904.39 — fastest HR compliance clock |
| EEOC_CHARGE_FILED | 30 days (position statement) | EEOC 29 CFR §1601; preserve all HR records immediately |
| OFCCP_AUDIT_NOTICE | 30 days | OFCCP 41 CFR §60-1.43; AAP + supporting data required |
CRITICAL incidents → #hr-incident-critical Slack with regulatory clock. HIGH incidents → #hr-compliance-ops. All incidents logged to Postgres audit trail with timestamp for SOC2 CC7.2 evidence.
The OSHA §1904.39 8-hour fatality clock is the fastest mandatory reporting window in the US HR compliance stack — faster than FCRA, ERISA, or WARN.
{
"name": "HR Data Breach & FCRA/EEOC/WARN Incident Alert Pipeline",
"nodes": [
{
"id": "w4n1",
"name": "HR Incident Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
],
"parameters": {
"path": "hr-incident",
"httpMethod": "POST",
"responseMode": "responseNode"
}
},
{
"id": "w4n2",
"name": "Classify Incident",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"jsCode": "const d = $input.first().json;\nconst incidentMap = {\n EMPLOYEE_PII_BREACH: { severity: 'CRITICAL', deadline: '72h', reg: 'State breach notification laws (e.g. Cal. Civ. Code \u00a71798.82); HIPAA BAA if health data; notify affected employees', clock: '72 hours from discovery' },\n PAYROLL_RECORD_UNAUTHORIZED_ACCESS: { severity: 'CRITICAL', deadline: '24h', reg: 'FLSA \u00a711(c) 29 CFR \u00a7516 \u2014 audit trail integrity; potential SOX violation if public company; DOL notification if mass access', clock: '24 hours internal' },\n ERISA_PLAN_DATA_EXPOSURE: { severity: 'CRITICAL', deadline: '72h', reg: 'ERISA \u00a7404 fiduciary duty \u2014 plan participant data exposure; DOL EBSA notification required; notify affected participants', clock: '72 hours from discovery' },\n FCRA_UNAUTHORIZED_REPORT_ACCESS: { severity: 'CRITICAL', deadline: '5 days', reg: 'FCRA 15 USC \u00a71681n \u2014 willful FCRA violation; FTC/CFPB notification; candidate notification with \u00a71613 dispute rights', clock: '5 business days \u2014 adverse action window resets' },\n WARN_ACT_FAILURE_TO_NOTIFY: { severity: 'HIGH', deadline: '60 days', reg: 'WARN Act 29 USC \u00a72101 \u2014 60-day back pay + benefits liability per employee; $500/day civil penalty; DOL notification', clock: '60 days before layoff \u2014 already in breach if layoff has started' },\n OSHA_REPORTABLE_FATALITY: { severity: 'CRITICAL', deadline: '8h', reg: 'OSHA \u00a71904.39 \u2014 8-hour fatality/inpatient hospitalization reporting to OSHA; 24h for loss of eye/amputation', clock: '8 hours from employer knowledge' },\n EEOC_CHARGE_FILED: { severity: 'HIGH', deadline: '180 days', reg: 'EEOC 29 CFR \u00a71601 \u2014 EEOC charge response; position statement typically due 30 days after notice; preserve all HR records', clock: '30 days for position statement' },\n OFCCP_AUDIT_NOTICE: { severity: 'HIGH', deadline: '30 days', reg: 'OFCCP 41 CFR \u00a760-1.43 \u2014 desk audit response due 30 days from notice; AAP + supporting data required', clock: '30 days from notice' }\n};\nconst meta = incidentMap[d.incident_type] || { severity: 'MEDIUM', deadline: '72h', reg: 'Unknown incident type \u2014 escalate to HR legal', clock: '72h default' };\nreturn [{ json: { ...d, ...meta, detected_at: new Date().toISOString() } }];"
}
},
{
"id": "w4n3",
"name": "Route by Severity",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
660,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.severity }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "CRITICAL"
}
]
},
"outputIndex": 0
}
]
},
"fallbackOutput": "last"
}
},
{
"id": "w4n4",
"name": "Slack CRITICAL #hr-incident",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
860,
180
],
"parameters": {
"channel": "#hr-incident-critical",
"text": "=[CRITICAL] HR INCIDENT: {{ $json.incident_type }}\nRegulation: {{ $json.reg }}\nDeadline: {{ $json.clock }}\nClient: {{ $json.client_name }} | Detected: {{ $json.detected_at }}"
}
},
{
"id": "w4n5",
"name": "Slack HIGH #hr-compliance",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
860,
420
],
"parameters": {
"channel": "#hr-compliance-ops",
"text": "=[HIGH] HR Incident: {{ $json.incident_type }}\nRegulation: {{ $json.reg }}\nClock: {{ $json.clock }}"
}
},
{
"id": "w4n6",
"name": "Log to Postgres Audit Trail",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1060,
300
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "hr_incident_log",
"columns": "incident_type,severity,regulation,clock,client_name,detected_at",
"values": "={{ $json.incident_type }},={{ $json.severity }},={{ $json.reg }},={{ $json.clock }},={{ $json.client_name }},={{ $json.detected_at }}"
}
}
],
"connections": {
"HR Incident Webhook": {
"main": [
[
{
"node": "Classify Incident",
"type": "main",
"index": 0
}
]
]
},
"Classify Incident": {
"main": [
[
{
"node": "Route by Severity",
"type": "main",
"index": 0
}
]
]
},
"Route by Severity": {
"main": [
[
{
"node": "Slack CRITICAL #hr-incident",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack HIGH #hr-compliance",
"type": "main",
"index": 0
}
]
]
},
"Slack CRITICAL #hr-incident": {
"main": [
[
{
"node": "Log to Postgres Audit Trail",
"type": "main",
"index": 0
}
]
]
},
"Slack HIGH #hr-compliance": {
"main": [
[
{
"node": "Log to Postgres Audit Trail",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly HRTech Platform KPI Dashboard
Runs every Monday at 8 AM. Two parallel Postgres queries: platform metrics (MRR, active accounts, trials, conversions, churn) and compliance incidents from the past 7 days. A Merge node combines them. A Code node builds an HTML table with color-coded CRITICAL incident count.
Sent to CEO with CISO BCC. The CISO BCC closes the SOC2 CC7.2 incident detection governance gap — security leadership receives the weekly compliance incident summary without needing a separate dashboard.
Self-hosting argument: HR PII (payroll amounts, 401k balances, background check results, EEO demographic data) flowing through Zapier or Make creates three simultaneous problems: (1) ERISA §404 fiduciary duty — routing plan participant data through a third-party SaaS is a fiduciary risk; (2) FCRA §1681b data minimization — consumer report data must not flow beyond the permissible purpose recipient; (3) OFCCP AAP data — affirmative action demographic data routed through cloud iPaaS is a disclosure risk under 41 CFR §60-2. Self-hosted n8n keeps all of this inside the VPC with a complete audit trail.
{
"name": "Weekly HRTech Platform KPI Dashboard",
"nodes": [
{
"id": "w5n1",
"name": "Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
260,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
}
},
{
"id": "w5n2",
"name": "Query Platform Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
240
],
"parameters": {
"operation": "select",
"schema": "public",
"table": "platform_weekly_metrics",
"additionalFields": {
"where": "week_start = date_trunc('week', now() - interval '1 week')"
}
}
},
{
"id": "w5n3",
"name": "Query Compliance Events",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
400
],
"parameters": {
"operation": "select",
"schema": "public",
"table": "hr_incident_log",
"additionalFields": {
"where": "detected_at >= now() - interval '7 days'"
}
}
},
{
"id": "w5n4",
"name": "Merge Metrics",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"position": [
660,
300
],
"parameters": {
"mode": "mergeByIndex"
}
},
{
"id": "w5n5",
"name": "Build KPI Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
860,
300
],
"parameters": {
"jsCode": "const m = $('Query Platform Metrics').first().json;\nconst incidents = $('Query Compliance Events').all();\nconst criticalCount = incidents.filter(i => i.json.severity === 'CRITICAL').length;\nconst highCount = incidents.filter(i => i.json.severity === 'HIGH').length;\nconst mrr = m.mrr_usd || 0;\nconst mrrPrev = m.mrr_usd_prev_week || mrr;\nconst mrrDelta = mrrPrev ? (((mrr - mrrPrev) / mrrPrev) * 100).toFixed(1) : '0.0';\nconst html = [\n '<h2>FlowKit HRTech Platform KPI \u2014 Week of ' + new Date().toISOString().slice(0,10) + '</h2>',\n '<table border=1 cellpadding=6>',\n '<tr><th>Metric</th><th>This Week</th><th>WoW %</th></tr>',\n '<tr><td>MRR</td><td>$' + mrr.toLocaleString() + '</td><td>' + mrrDelta + '%</td></tr>',\n '<tr><td>Active Accounts</td><td>' + (m.active_accounts || 0) + '</td><td>' + (m.active_accounts_delta_pct || 0) + '%</td></tr>',\n '<tr><td>New Trials</td><td>' + (m.new_trials || 0) + '</td><td>\u2014</td></tr>',\n '<tr><td>Trial Conversions</td><td>' + (m.trial_conversions || 0) + '</td><td>\u2014</td></tr>',\n '<tr><td>Churn MRR</td><td>$' + (m.churn_mrr || 0).toLocaleString() + '</td><td>\u2014</td></tr>',\n '<tr><td bgcolor=' + (criticalCount > 0 ? '#ffcccc' : '#ccffcc') + '>CRITICAL HR Incidents</td><td>' + criticalCount + '</td><td>\u2014</td></tr>',\n '<tr><td>HIGH HR Incidents</td><td>' + highCount + '</td><td>\u2014</td></tr>',\n '<tr><td>EEOC/OSHA/FCRA Deadlines (7d)</td><td>' + (m.compliance_deadlines_due_7d || 0) + '</td><td>\u2014</td></tr>',\n '</table>',\n '<p><em>CISO BCC \u2014 closes SOC2 CC7.2 incident detection governance gap. HR PII: self-hosted n8n keeps this report inside VPC \u2014 ERISA \u00a7404 fiduciary duty + FCRA \u00a71681b data minimization.</em></p>'\n].join('');\nreturn [{ json: { html, subject: 'HRTech Platform KPI \u2014 Week of ' + new Date().toISOString().slice(0,10) } }];"
}
},
{
"id": "w5n6",
"name": "Email CEO + CISO BCC",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
1060,
300
],
"parameters": {
"toEmail": "={{ $env.CEO_EMAIL }}",
"ccEmail": "={{ $env.CISO_EMAIL }}",
"subject": "={{ $json.subject }}",
"message": "={{ $json.html }}",
"options": {
"bodyContentType": "html"
}
}
}
],
"connections": {
"Monday 8AM": {
"main": [
[
{
"node": "Query Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Query Compliance Events",
"type": "main",
"index": 0
}
]
]
},
"Query Platform Metrics": {
"main": [
[
{
"node": "Merge Metrics",
"type": "main",
"index": 0
}
]
]
},
"Query Compliance Events": {
"main": [
[
{
"node": "Merge Metrics",
"type": "main",
"index": 1
}
]
]
},
"Merge Metrics": {
"main": [
[
{
"node": "Build KPI Report",
"type": "main",
"index": 0
}
]
]
},
"Build KPI Report": {
"main": [
[
{
"node": "Email CEO + CISO BCC",
"type": "main",
"index": 0
}
]
]
}
}
}
n8n vs Zapier/Make for HRTech Compliance
| Requirement | Zapier/Make | n8n (self-hosted) |
|---|---|---|
| FLSA §11(c) payroll records (3yr) | Data exits VPC to cloud | Self-hosted: records stay on-premises |
| ERISA §209 benefit records (5yr) | SaaS vendor = BAA risk | Air-gapped audit trail in Postgres |
| FCRA §1681b — CRA data minimization | Third-party SaaS = data egress finding | Consumer report data never leaves VPC |
| OSHA 300 log 8h fatality clock | Cloud API latency risk | Sub-minute webhook response on-prem |
| WARN Act 60-day headcount monitoring | No custom headcount logic | Full JS + external HRIS API access |
| OFCCP AAP demographic data | SaaS = disclosure risk (41 CFR §60-2) | On-prem; no third-party data processor |
| SOC2 vendor risk (CC9.2) | iPaaS = additional vendor scope | Self-hosted: no additional vendor |
Self-Hosting Arguments by Regulation
| Regulation | Self-Hosting Argument |
|---|---|
| FLSA §11(c) 29 CFR §516 | DOL audit: payroll records must be produced immediately on demand — cloud iPaaS adds a third-party retrieval dependency that auditors flag |
| ERISA §209 5yr benefit records | EBSA audit: plan participant records flowing through Zapier = additional data processor not named in the plan's privacy notice; §404 fiduciary risk |
| FCRA 15 USC §1681b | Consumer report data permissible purpose is narrow — routing CRA data through Make/Zapier creates a §1681b(f) impermissible purpose risk |
| OSHA 29 CFR §1904.39 8h fatality | 8-hour clock requires sub-minute detection and routing — cloud API rate limits and SaaS outages directly risk the OSHA reporting window |
| OFCCP 41 CFR Part 60 AAP | AAP demographic data is sensitive EEO data — routing through cloud iPaaS is a disclosure that requires employee notice under §60-3.15 |
Buyer Q&A
Q: We use Workday as our HRIS — does n8n integrate with Workday's API for EEO-1 pre-fill?
A: Yes. Workday's REST API and SOAP API both expose worker demographic data needed for EEO-1 Component 1 (race/ethnicity, sex, job category). An n8n HTTP Request node with OAuth2 credential handles the auth; a Code node maps Workday job families to EEOC EEO-1 job categories (1.1–1.9). The self-hosted n8n instance keeps Workday worker PII inside your VPC — it never reaches Zapier's servers.
Q: How does the FCRA adverse action pipeline handle the 5-business-day window precisely?
A: The workflow uses a Code node to calculate business days (excluding weekends and configurable federal holidays) from the pre-adverse action notice timestamp. A Postgres record stores the candidate_id, notice_sent_ts, and adverse_action_due_ts. A daily cron polls for approaching deadlines and alerts #recruiting-ops with the exact hours remaining. The window is hard-coded as 5 business days per §1681b(b)(3)(A) — not 5 calendar days.
Q: Our ERISA Form 5500 is filed by a TPA — why do we need n8n for this?
A: The Form 5500 is filed by the TPA, but the underlying plan records that support the filing (SPD distribution proof, SAR delivery timestamps, participant counts, contribution records) are your obligation under ERISA §104 and §209. n8n automates the chain-of-custody log: SPD sent timestamp → certified mail tracking → Postgres record. When DOL EBSA audits, you produce the chain-of-custody log, not the TPA.
Q: Does the WARN Act tracker handle state mini-WARN laws with shorter notice periods?
A: Yes. The deadline tracker stores a jurisdiction field per workforce event. A Code node maps jurisdiction to the applicable notice period: federal WARN (60 days, 29 USC §2101), California WARN (60 days, Cal. Lab. Code §1401 — no 100-employee threshold), New York WARN (90 days, NY Lab. Law §860-c). The most restrictive period wins when multiple jurisdictions apply.
Q: We're a OFCCP federal contractor — what does the AAP workflow actually automate?
A: Three things: (1) Annual AAP update reminder 120 days after fiscal year start (41 CFR §60-2.10), firing 60/30/14 days before deadline with escalating Slack severity. (2) VETS-4212 filing reminder for Aug 1 window open + Sep 30 hard deadline (41 CFR §61-300). (3) OFCCP audit notice router: when an audit notice webhook fires, the workflow immediately preserves all HR records (Postgres snapshot), notifies legal and HR, and sets a 30-day desk audit response deadline (41 CFR §60-1.43). All three keep demographic data in the self-hosted VPC — AAP data never routes through cloud iPaaS.
All five workflows import directly into n8n. Store links to FlowKit: stripeai.gumroad.com — individual templates from $12, full bundle $97.
Top comments (0)