If your SaaS platform serves grid operators, utilities, nuclear facilities, refineries, or renewable energy companies — your workflows touch some of the most consequential compliance obligations in existence.
NERC CIP violations run up to $1 million per day per violation. NRC cyber incidents require a 1-hour phone call to the Operations Center. OSHA PSM accidents require oral notification within 8 hours. And EPA GHG reporters face audit trail requirements that can't be outsourced to a cloud iPaaS vendor you don't fully control.
The data sovereignty angle is severe: NERC CIP-011 designates Bulk Electric System (BES) Cyber System Information as protected information. Routing it through Zapier or Make creates an unauthorized access exposure — a Level 1 violation at $1M/day under FERC Order 216. Nuclear Cyber Security Plan data under 10 CFR §73.54 is safeguards information; unauthorized disclosure is a criminal offense under 10 CFR §73.21.
Here are 5 n8n workflows every EnergyTech and UtilityTech SaaS vendor should build — all import-ready JSON at the bottom.
Who this is for
7 customer tiers EnergyTech SaaS vendors serve:
| Tier | Description | Key compliance |
|---|---|---|
GRID_MANAGEMENT_SAAS |
BES operators, transmission system operators | NERC CIP-002 through CIP-014 |
UTILITY_ANALYTICS_SAAS |
Distribution utilities, load forecasting platforms | FERC, EPA GHG 40 CFR Part 98 |
DERM_SAAS |
Distributed Energy Resource Management | FERC Order 2222, CEII data |
RENEWABLE_ENERGY_SAAS |
Wind/solar/storage asset management | EPA GHG Part 98, NERC CIP (if interconnected) |
NUCLEAR_OPERATIONS_SAAS |
Nuclear facility operations software | NRC 10 CFR Part 73, §73.54 Cyber Security Plan |
INDUSTRIAL_PROCESS_SAAS |
Refinery, chemical plant, LNG terminal ops | OSHA PSM 29 CFR §1910.119, EPA RMP §68 |
ENERGYTECH_STARTUP |
Early-stage, initial compliance posture | SOC2, FedRAMP path |
Workflow 1: EnergyTech Customer Onboarding Drip (Tier-Segmented)
A generic welcome email won't cut it when one customer needs a NERC CIP-004 personnel access audit explanation and another needs a FERC Order 2222 DER enrollment timeline.
What it does: Webhook fires on new customer signup → Code node extracts tier and compliance flags → Sheets log → Day 0 welcome (compliance-note personalized by tier) → Wait 3d → Day 3 integration tips → Wait 4d → Day 7 check-in → Wait 7d → Day 14 QBR invite.
Compliance flags injected: NERC_CIP_APPLICABLE, NRC_10_CFR_73_APPLICABLE, OSHA_PSM_29_CFR_1910_119, FERC_ORDER_2222_SUBJECT, EPA_GHG_REPORTING_REQUIRED, SOC2_REQUIRED.
{
"name": "EnergyTech Customer Onboarding Drip \u2014 Tier Segmented",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "energytech-onboarding",
"responseMode": "responseNode"
},
"name": "Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"id": "a1b2c3d4-0001-0001-0001-000000000001",
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "const tier = $json.customer_tier || 'ENERGYTECH_STARTUP';\nconst flags = $json.compliance_flags || [];\nconst isNercCip = flags.includes('NERC_CIP_APPLICABLE');\nconst isNrc = flags.includes('NRC_10_CFR_73_APPLICABLE');\nconst isOsha = flags.includes('OSHA_PSM_29_CFR_1910_119');\nconst isFercDer = flags.includes('FERC_ORDER_2222_SUBJECT');\nconst isEpaGhg = flags.includes('EPA_GHG_REPORTING_REQUIRED');\nlet note = '';\nif (tier === 'GRID_MANAGEMENT_SAAS') note = 'NERC CIP-004 personnel access auditable; CIP-011 BES Cyber System Information stays in your enclave \u2014 not Zapier.';\nelse if (tier === 'NUCLEAR_OPERATIONS_SAAS') note = 'NRC 10 CFR \u00a773.54 CSP data stays on-prem; safeguards information unauthorized disclosure = criminal offense.';\nelse if (tier === 'INDUSTRIAL_PROCESS_SAAS') note = 'OSHA PSM 29 CFR \u00a71910.119 Process Safety Information and PHA docs remain in your perimeter \u2014 discoverable if cloud-stored.';\nelse if (tier === 'DERM_SAAS') note = 'FERC Order 2222 DER enrollment data is CEII \u2014 must stay within authorized enclosure, not a cloud iPaaS.';\nelse if (tier === 'RENEWABLE_ENERGY_SAAS') note = 'EPA GHG 40 CFR Part 98 annual report calculation audit trail owned by you, not a SaaS vendor.';\nelse note = 'Self-hosted n8n keeps all energy operational data within your perimeter.';\nreturn [{ json: { ...$json, tier, flags, note, isNercCip, isNrc, isOsha, isFercDer, isEpaGhg } }];"
},
"name": "Code \u2014 Tier + Flags",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"id": "a1b2c3d4-0001-0001-0001-000000000002",
"position": [
470,
300
]
},
{
"parameters": {
"operation": "append",
"documentId": "YOUR_SHEET_ID",
"sheetName": "customers",
"columns": {
"mappingMode": "autoMapInputData"
}
},
"name": "Sheets \u2014 Log Customer",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0001-0001-0001-000000000003",
"position": [
690,
300
]
},
{
"parameters": {
"sendTo": "={{ $json.email }}",
"subject": "Welcome to [Platform] \u2014 Your {{ $json.tier }} onboarding",
"emailType": "html",
"message": "=<p>Hi {{ $json.name }},</p><p>{{ $json.note }}</p><p>Your onboarding specialist will contact you within 2 business hours.</p>"
},
"name": "Gmail \u2014 Day 0 Welcome",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0001-0001-0001-000000000004",
"position": [
910,
300
]
},
{
"parameters": {
"amount": 3,
"unit": "days"
},
"name": "Wait \u2014 3 Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"id": "a1b2c3d4-0001-0001-0001-000000000005",
"position": [
1130,
300
]
},
{
"parameters": {
"sendTo": "={{ $('Webhook').item.json.email }}",
"subject": "Your first automation in [Platform]",
"emailType": "html",
"message": "=<p>Hi {{ $('Webhook').item.json.name }},</p><p>Day 3 tip: here are the 3 workflows our {{ $('Code \u2014 Tier + Flags').item.json.tier }} customers activate first.</p>"
},
"name": "Gmail \u2014 Day 3 Tips",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0001-0001-0001-000000000006",
"position": [
1350,
300
]
},
{
"parameters": {
"amount": 4,
"unit": "days"
},
"name": "Wait \u2014 4 Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"id": "a1b2c3d4-0001-0001-0001-000000000007",
"position": [
1570,
300
]
},
{
"parameters": {
"sendTo": "={{ $('Webhook').item.json.email }}",
"subject": "Book your power-user session",
"emailType": "html",
"message": "<p>Hi,</p><p>Ready to go deeper? Book your 30-min power-user session: [CALENDAR_LINK]</p>"
},
"name": "Gmail \u2014 Day 7 Check-In",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0001-0001-0001-000000000008",
"position": [
1790,
300
]
},
{
"parameters": {
"amount": 7,
"unit": "days"
},
"name": "Wait \u2014 7 Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"id": "a1b2c3d4-0001-0001-0001-000000000009",
"position": [
2010,
300
]
},
{
"parameters": {
"sendTo": "={{ $('Webhook').item.json.email }}",
"subject": "QBR invite \u2014 2 weeks in",
"emailType": "html",
"message": "<p>Two weeks in \u2014 let's review ROI and map your next compliance automation layer. Book: [CALENDAR_LINK]</p>"
},
"name": "Gmail \u2014 Day 14 QBR",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0001-0001-0001-000000000010",
"position": [
2230,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"status\": \"ok\"}"
},
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"id": "a1b2c3d4-0001-0001-0001-000000000011",
"position": [
470,
500
]
}
],
"connections": {
"Webhook": {
"main": [
[
{
"node": "Code \u2014 Tier + Flags",
"type": "main",
"index": 0
},
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Tier + Flags": {
"main": [
[
{
"node": "Sheets \u2014 Log Customer",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Log Customer": {
"main": [
[
{
"node": "Gmail \u2014 Day 0 Welcome",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 Day 0 Welcome": {
"main": [
[
{
"node": "Wait \u2014 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 3 Days": {
"main": [
[
{
"node": "Gmail \u2014 Day 3 Tips",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 Day 3 Tips": {
"main": [
[
{
"node": "Wait \u2014 4 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 4 Days": {
"main": [
[
{
"node": "Gmail \u2014 Day 7 Check-In",
"type": "main",
"index": 0
}
]
]
},
"Gmail \u2014 Day 7 Check-In": {
"main": [
[
{
"node": "Wait \u2014 7 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait \u2014 7 Days": {
"main": [
[
{
"node": "Gmail \u2014 Day 14 QBR",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: NERC CIP / NRC / OSHA Compliance Deadline Tracker
Your customers manage a dense calendar of overlapping compliance deadlines. Missing a NERC CIP-007 35-day patch assessment window or the annual EPA GHG March 31 filing creates direct liability — and reflects on your platform's reliability.
12 deadline types tracked:
| Deadline Type | Authority | Window |
|---|---|---|
NERC_CIP_002_SYSTEM_CATEGORIZATION_ANNUAL |
NERC CIP-002-5.1a | Annual |
NERC_CIP_005_ESP_REVIEW_QUARTERLY |
NERC CIP-005-6 | Quarterly |
NERC_CIP_007_PATCH_MGMT_35_DAY |
CIP-007-6 R2 | 35 calendar days from release |
NERC_CIP_010_BASELINE_CONFIG_ANNUAL |
NERC CIP-010-3 | Annual |
NERC_CIP_013_SUPPLY_CHAIN_PLAN_18_MONTH |
CIP-013-1 R1 | 18 months |
NERC_CIP_014_PHYSICAL_SECURITY_PLAN_ANNUAL |
NERC CIP-014-2 | Annual |
FERC_ORDER_2222_DER_ENROLLMENT_DEADLINE |
FERC Order 2222 | RTO-specific |
EPA_GHG_40_CFR_98_ANNUAL_REPORT |
40 CFR Part 98 | March 31 |
NRC_10_CFR_73_CYBER_SECURITY_PLAN_ANNUAL |
10 CFR §73.54 | Annual |
OSHA_PSM_PHA_REVALIDATION_5_YEAR |
29 CFR §1910.119(e)(5) | Every 5 years |
EPA_RMP_HAZARD_ASSESSMENT_5_YEAR |
40 CFR §68.67 | Every 5 years |
SOC2_TYPE2_ANNUAL_RENEWAL |
AICPA TSC | Annual |
{
"name": "NERC CIP / NRC / OSHA Compliance Deadline Tracker",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 24
}
]
}
},
"name": "Schedule \u2014 Daily 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"id": "a1b2c3d4-0002-0002-0002-000000000001",
"position": [
250,
300
]
},
{
"parameters": {
"operation": "read",
"documentId": "YOUR_SHEET_ID",
"sheetName": "compliance_deadlines",
"returnAllMatches": true
},
"name": "Sheets \u2014 Read Deadlines",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0002-0002-0002-000000000002",
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "const today = new Date();\nconst items = $input.all();\nconst results = [];\nfor (const item of items) {\n const due = new Date(item.json.due_date);\n const daysUntil = Math.ceil((due - today) / 86400000);\n let urgency = null;\n if (daysUntil < 0) urgency = 'OVERDUE';\n else if (daysUntil <= 14) urgency = 'CRITICAL';\n else if (daysUntil <= 30) urgency = 'URGENT';\n else if (daysUntil <= 60) urgency = 'WARNING';\n else if (daysUntil <= 90) urgency = 'NOTICE';\n if (urgency) results.push({ json: { ...item.json, urgency, daysUntil } });\n}\nreturn results;"
},
"name": "Code \u2014 Classify Urgency",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"id": "a1b2c3d4-0002-0002-0002-000000000003",
"position": [
690,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "OVERDUE",
"operator": {
"type": "string",
"operation": "equals"
}
},
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "CRITICAL",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "or"
}
},
"name": "IF \u2014 Critical or Overdue",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"id": "a1b2c3d4-0002-0002-0002-000000000004",
"position": [
910,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#nerc-cip-compliance",
"mode": "name"
},
"text": "={{ $json.urgency }}: {{ $json.deadline_type }} for {{ $json.org_name }} \u2014 due {{ $json.due_date }} ({{ $json.daysUntil }} days). Owner: {{ $json.owner_email }}"
},
"name": "Slack \u2014 NERC/NRC Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"id": "a1b2c3d4-0002-0002-0002-000000000005",
"position": [
1130,
200
]
},
{
"parameters": {
"sendTo": "={{ $json.owner_email }}",
"subject": "={{ $json.urgency }}: {{ $json.deadline_type }} due {{ $json.due_date }}",
"emailType": "html",
"message": "=<p>{{ $json.deadline_type }} for {{ $json.org_name }} is {{ $json.urgency }} ({{ $json.daysUntil }} days until {{ $json.due_date }}).</p><p>Please update compliance_deadlines sheet upon completion.</p>"
},
"name": "Gmail \u2014 Owner Email",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0002-0002-0002-000000000006",
"position": [
1130,
400
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#regulatory-watch",
"mode": "name"
},
"text": "={{ $json.urgency }}: {{ $json.deadline_type }} for {{ $json.org_name }} in {{ $json.daysUntil }} days."
},
"name": "Slack \u2014 Warning Notice",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"id": "a1b2c3d4-0002-0002-0002-000000000007",
"position": [
1130,
600
]
}
],
"connections": {
"Schedule \u2014 Daily 8AM": {
"main": [
[
{
"node": "Sheets \u2014 Read Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Read Deadlines": {
"main": [
[
{
"node": "Code \u2014 Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Classify Urgency": {
"main": [
[
{
"node": "IF \u2014 Critical or Overdue",
"type": "main",
"index": 0
}
]
]
},
"IF \u2014 Critical or Overdue": {
"main": [
[
{
"node": "Slack \u2014 NERC/NRC Alert",
"type": "main",
"index": 0
},
{
"node": "Gmail \u2014 Owner Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack \u2014 Warning Notice",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: BES Cyber System API Health Monitor (NERC CIP-007)
NERC CIP-008-6 R4 requires notification to E-ISAC and CISA within 1 hour of a reportable cyber incident. Your monitoring must run tighter than that clock — 15-minute polling gives you 3 detection cycles before the 1-hour window closes.
5 endpoints monitored with CIP annotations:
| Endpoint | Annotation |
|---|---|
grid_management_api |
BES Cyber System data — NERC CIP-011 R1.1 encryption required |
scada_integration_api |
Electronic Security Perimeter — CIP-005 R1 ingress/egress monitoring |
der_forecast_api |
FERC Order 2222 market data — CPUC/PJM/MISO API dependency |
ghg_reporting_api |
EPA 40 CFR §98.3 mandatory reporting — annual March 31 deadline |
nuclear_safety_api |
NRC 10 CFR §73.54 — 1h notification clock if cyber compromise |
{
"name": "BES Cyber System API Health Monitor (NERC CIP-007)",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"name": "Schedule \u2014 Every 15 Min",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"id": "a1b2c3d4-0003-0003-0003-000000000001",
"position": [
250,
300
]
},
{
"parameters": {
"url": "={{ $json.endpoint_url }}",
"options": {
"timeout": 10000
}
},
"name": "HTTP \u2014 Poll API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"id": "a1b2c3d4-0003-0003-0003-000000000002",
"position": [
470,
300
]
},
{
"parameters": {
"jsCode": "const endpointMap = {\n 'grid_management_api': 'BES Cyber System data \u2014 NERC CIP-011 R1.1 encryption required; CIP-005 ESP boundary',\n 'scada_integration_api': 'Electronic Security Perimeter \u2014 CIP-005 R1 ingress/egress monitoring',\n 'der_forecast_api': 'FERC Order 2222 DER market data \u2014 CPUC/PJM/MISO dependency',\n 'ghg_reporting_api': 'EPA 40 CFR \u00a798.3 mandatory reporting \u2014 annual March 31 deadline',\n 'nuclear_safety_api': 'NRC 10 CFR \u00a773.54 \u2014 1h notification clock if cyber compromise'\n};\nconst items = $input.all();\nconst down = items.filter(i => i.json.statusCode !== 200);\nreturn down.map(i => ({\n json: {\n ...i.json,\n annotation: endpointMap[i.json.endpoint_name] || 'Unknown endpoint',\n status: 'DOWN'\n }\n}));"
},
"name": "Code \u2014 Flag Down Endpoints",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"id": "a1b2c3d4-0003-0003-0003-000000000003",
"position": [
690,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#nerc-cip-critical",
"mode": "name"
},
"text": "=CRITICAL: {{ $json.endpoint_name }} is DOWN.\n{{ $json.annotation }}\nCIP-007-6 R1 patch window clock may be running. Investigate immediately."
},
"name": "Slack \u2014 CIP Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"id": "a1b2c3d4-0003-0003-0003-000000000004",
"position": [
910,
200
]
},
{
"parameters": {
"operation": "append",
"documentId": "YOUR_SHEET_ID",
"sheetName": "grid_incident_log",
"columns": {
"mappingMode": "autoMapInputData"
}
},
"name": "Sheets \u2014 Log Incident",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0003-0003-0003-000000000005",
"position": [
910,
400
]
}
],
"connections": {
"Schedule \u2014 Every 15 Min": {
"main": [
[
{
"node": "HTTP \u2014 Poll API",
"type": "main",
"index": 0
}
]
]
},
"HTTP \u2014 Poll API": {
"main": [
[
{
"node": "Code \u2014 Flag Down Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Flag Down Endpoints": {
"main": [
[
{
"node": "Slack \u2014 CIP Alert",
"type": "main",
"index": 0
},
{
"node": "Sheets \u2014 Log Incident",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: NERC CIP-008 / NRC / OSHA Incident Pipeline
The fastest clocks in energy compliance are brutal: 1 hour for NERC CIP-008 reportable incidents (E-ISAC + CISA), 1 hour for NRC cyber incidents (Operations Center 301-816-5100), 8 hours oral for OSHA PSM process accidents. An intake webhook that auto-routes each incident type to the right channel and email with the SLA printed prominently is the difference between a fine and compliance.
8 incident types with SLA routing:
| Incident Type | SLA Clock | Authority |
|---|---|---|
NERC_CIP_008_REPORTABLE_INCIDENT |
1h — E-ISAC + CISA | CIP-008-6 R4 |
NERC_CIP_008_MAJOR_INCIDENT |
1h — E-ISAC + CISA | CIP-008-6 R4 |
NRC_10_CFR_73_CYBER_INCIDENT |
1h — NRC Ops Center | 10 CFR §73.77 |
OSHA_PSM_PROCESS_ACCIDENT |
8h oral / 24h written | §1910.119(m) |
EPA_GHG_MONITORING_FAILURE |
10 days rectification | 40 CFR §98.35 |
EPA_RMP_TOXIC_RELEASE |
4h — NRC Hotline | 40 CFR Part 68 |
FERC_ORDER_2222_CURTAILMENT |
RTO immediate | FERC Order 2222 |
NERC_CIP_SUPPLY_CHAIN_COMPROMISE |
35 days patch window | CIP-013-1 R1 |
{
"name": "NERC CIP-008 / NRC / OSHA Incident Pipeline",
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "energy-incident",
"responseMode": "responseNode"
},
"name": "Webhook \u2014 Incident Intake",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"id": "a1b2c3d4-0004-0004-0004-000000000001",
"position": [
250,
300
]
},
{
"parameters": {
"jsCode": "const type = $json.incident_type;\nconst slaMap = {\n 'NERC_CIP_008_REPORTABLE_INCIDENT': '1h \u2014 E-ISAC + CISA notification (CIP-008-6 R4)',\n 'NERC_CIP_008_MAJOR_INCIDENT': '1h \u2014 E-ISAC + CISA (CIP-008-6 R4 \u2014 affects BES reliability)',\n 'NRC_10_CFR_73_CYBER_INCIDENT': '1h \u2014 NRC Operations Center 301-816-5100 (10 CFR \u00a773.77)',\n 'OSHA_PSM_PROCESS_ACCIDENT': '8h oral / 24h written \u2014 OSHA Area Office (\u00a71910.119(m))',\n 'EPA_GHG_MONITORING_FAILURE': '10 days \u2014 parametric monitor rectification (40 CFR \u00a798.35)',\n 'EPA_RMP_TOXIC_RELEASE': '4h \u2014 NRC Hotline 800-424-8802 (40 CFR Part 68)',\n 'FERC_ORDER_2222_CURTAILMENT': 'Market penalty \u2014 DER dispatch failure; notify RTO immediately',\n 'NERC_CIP_SUPPLY_CHAIN_COMPROMISE': '35 days \u2014 patch window (CIP-013-1 R1)'\n};\nconst channelMap = {\n 'NERC_CIP_008_REPORTABLE_INCIDENT': '#nerc-cip-critical',\n 'NERC_CIP_008_MAJOR_INCIDENT': '#nerc-cip-critical',\n 'NRC_10_CFR_73_CYBER_INCIDENT': '#nuclear-security',\n 'OSHA_PSM_PROCESS_ACCIDENT': '#process-safety',\n 'EPA_GHG_MONITORING_FAILURE': '#regulatory-team',\n 'EPA_RMP_TOXIC_RELEASE': '#regulatory-team',\n 'FERC_ORDER_2222_CURTAILMENT': '#grid-ops',\n 'NERC_CIP_SUPPLY_CHAIN_COMPROMISE': '#nerc-cip-critical'\n};\nreturn [{ json: { ...$json,\n sla: slaMap[type] || 'Consult compliance team',\n slack_channel: channelMap[type] || '#compliance-general',\n ts: new Date().toISOString()\n} }];"
},
"name": "Code \u2014 SLA + Channel Route",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"id": "a1b2c3d4-0004-0004-0004-000000000002",
"position": [
470,
300
]
},
{
"parameters": {
"operation": "append",
"documentId": "YOUR_SHEET_ID",
"sheetName": "incident_log",
"columns": {
"mappingMode": "autoMapInputData"
}
},
"name": "Sheets \u2014 Log Incident",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0004-0004-0004-000000000003",
"position": [
690,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "={{ $json.slack_channel }}",
"mode": "name"
},
"text": "=ENERGY INCIDENT: {{ $json.incident_type }}\nSite: {{ $json.site_name }}\nSLA: {{ $json.sla }}\nDetails: {{ $json.description }}\nTimestamp: {{ $json.ts }}"
},
"name": "Slack \u2014 Incident Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"id": "a1b2c3d4-0004-0004-0004-000000000004",
"position": [
910,
200
]
},
{
"parameters": {
"sendTo": "compliance@yourcompany.com",
"subject": "={{ 'INCIDENT: ' + $json.incident_type + ' at ' + $json.site_name }}",
"emailType": "html",
"message": "=<p><strong>Incident Type:</strong> {{ $json.incident_type }}</p><p><strong>SLA Clock:</strong> {{ $json.sla }}</p><p><strong>Site:</strong> {{ $json.site_name }}</p><p><strong>Description:</strong> {{ $json.description }}</p><p>Log in to incident_log sheet for full audit trail.</p>"
},
"name": "Gmail \u2014 Compliance Team",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0004-0004-0004-000000000005",
"position": [
910,
400
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "{\"status\": \"logged\"}"
},
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"id": "a1b2c3d4-0004-0004-0004-000000000006",
"position": [
470,
500
]
}
],
"connections": {
"Webhook \u2014 Incident Intake": {
"main": [
[
{
"node": "Code \u2014 SLA + Channel Route",
"type": "main",
"index": 0
},
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 SLA + Channel Route": {
"main": [
[
{
"node": "Sheets \u2014 Log Incident",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Log Incident": {
"main": [
[
{
"node": "Slack \u2014 Incident Alert",
"type": "main",
"index": 0
},
{
"node": "Gmail \u2014 Compliance Team",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly EnergyTech Platform KPI Dashboard
Grid operators, utility analytics teams, and nuclear facility operations managers have completely different metrics. This workflow unifies them into one Monday morning CEO briefing that also surfaces compliance event counts alongside revenue.
KPIs tracked:
- Active Utilities (customer count)
- MRR with WoW % change
- BES Systems Monitored
- NERC CIP Open Tickets
- CIP-008 Incidents YTD
- EPA GHG Reporters Monitored
- OSHA PSM Sites Tracked
- NRC Facilities Served
- API Calls (7d)
{
"name": "Weekly EnergyTech Platform KPI Dashboard",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"weeksInterval": 1,
"triggerAtDay": [
1
],
"triggerAtHour": 8
}
]
}
},
"name": "Schedule \u2014 Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"id": "a1b2c3d4-0005-0005-0005-000000000001",
"position": [
250,
300
]
},
{
"parameters": {
"operation": "read",
"documentId": "YOUR_SHEET_ID",
"sheetName": "platform_metrics",
"returnAllMatches": true
},
"name": "Sheets \u2014 Platform Metrics",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0005-0005-0005-000000000002",
"position": [
470,
200
]
},
{
"parameters": {
"operation": "read",
"documentId": "YOUR_SHEET_ID",
"sheetName": "compliance_events",
"returnAllMatches": true
},
"name": "Sheets \u2014 Compliance Events",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"id": "a1b2c3d4-0005-0005-0005-000000000003",
"position": [
470,
400
]
},
{
"parameters": {
"mode": "combine",
"combinationMode": "mergeByIndex"
},
"name": "Merge",
"type": "n8n-nodes-base.merge",
"typeVersion": 2,
"id": "a1b2c3d4-0005-0005-0005-000000000004",
"position": [
690,
300
]
},
{
"parameters": {
"jsCode": "const m = $('Sheets \u2014 Platform Metrics').first().json;\nconst c = $('Sheets \u2014 Compliance Events').first().json;\nconst prev = m.prev_mrr || m.mrr;\nconst mrrWow = prev ? (((m.mrr - prev) / prev) * 100).toFixed(1) : '0.0';\nconst html = `<h2>EnergyTech Platform KPI \u2014 Week of ${new Date().toISOString().slice(0,10)}</h2>\n<table border='1' cellpadding='6'>\n<tr><th>Metric</th><th>Value</th><th>WoW</th></tr>\n<tr><td>Active Utilities</td><td>${m.active_utilities}</td><td>\u2014</td></tr>\n<tr><td>MRR</td><td>$${Number(m.mrr).toLocaleString()}</td><td>${mrrWow}%</td></tr>\n<tr><td>BES Systems Monitored</td><td>${m.bes_systems_monitored}</td><td>\u2014</td></tr>\n<tr><td>NERC CIP Open Tickets</td><td>${c.nerc_cip_open || 0}</td><td>\u2014</td></tr>\n<tr><td>CIP-008 Incidents YTD</td><td>${c.cip_008_incidents_ytd || 0}</td><td>\u2014</td></tr>\n<tr><td>EPA GHG Reporters</td><td>${m.epa_ghg_reporters || 0}</td><td>\u2014</td></tr>\n<tr><td>OSHA PSM Sites</td><td>${m.osha_psm_sites || 0}</td><td>\u2014</td></tr>\n<tr><td>NRC Facilities</td><td>${m.nrc_facilities || 0}</td><td>\u2014</td></tr>\n<tr><td>API Calls (7d)</td><td>${Number(m.api_calls_7d).toLocaleString()}</td><td>\u2014</td></tr>\n</table>`;\nreturn [{ json: { html, mrrWow } }];"
},
"name": "Code \u2014 Build KPI HTML",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"id": "a1b2c3d4-0005-0005-0005-000000000005",
"position": [
910,
300
]
},
{
"parameters": {
"sendTo": "ceo@yourcompany.com",
"subject": "=Weekly EnergyTech KPI \u2014 MRR {{ $json.mrrWow }}% WoW",
"emailType": "html",
"message": "={{ $json.html }}",
"options": {
"bccList": "ciso@yourcompany.com, compliance@yourcompany.com"
}
},
"name": "Gmail \u2014 CEO + BCC CISO",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"id": "a1b2c3d4-0005-0005-0005-000000000006",
"position": [
1130,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#management",
"mode": "name"
},
"text": "=Weekly KPI: MRR {{ $json.mrrWow }}% WoW. Full report in email."
},
"name": "Slack \u2014 Summary",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"id": "a1b2c3d4-0005-0005-0005-000000000007",
"position": [
1130,
500
]
}
],
"connections": {
"Schedule \u2014 Monday 8AM": {
"main": [
[
{
"node": "Sheets \u2014 Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Sheets \u2014 Compliance Events",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Platform Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Sheets \u2014 Compliance Events": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Code \u2014 Build KPI HTML",
"type": "main",
"index": 0
}
]
]
},
"Code \u2014 Build KPI HTML": {
"main": [
[
{
"node": "Gmail \u2014 CEO + BCC CISO",
"type": "main",
"index": 0
},
{
"node": "Slack \u2014 Summary",
"type": "main",
"index": 0
}
]
]
}
}
}
Why self-host n8n for EnergyTech
| Compliance requirement | Cloud iPaaS risk | Self-hosted n8n fix |
|---|---|---|
| NERC CIP-011 BES Cyber System Information — "protected information" | Routing through Zapier = unauthorized access exposure → Level 1 violation → $1M/day FERC Order 216 | n8n in your CIP boundary keeps BCS data in authorized enclave |
| FERC Order 2222 DER enrollment data (site coordinates, generation capacity, interconnection agreements) — CEII designation | CEII data must stay within authorized enclosure — cloud iPaaS = unauthorized disclosure | n8n on-prem or in FedRAMP-authorized cloud keeps CEII perimeter |
| NRC 10 CFR §73.54 nuclear Cyber Security Plan — safeguards information | Unauthorized disclosure = criminal offense under 10 CFR §73.21 | n8n self-hosted in nuclear facility perimeter; safeguards data never transits vendor cloud |
| OSHA PSM 29 CFR §1910.119 Process Safety Information and PHA documents | OSHA has subpoena power — cloud-stored PSI is discoverable in litigation | PSI and PHA records in your perimeter under access controls |
| EPA Chemical-Terrorism Vulnerability Information (CVI) — RMP §68 worst-case scenario data | Routing CVI through cloud = 6 USC §621 violation reportable to CISA | CVI stays within your CVI-authorized system |
Key buyer questions
"Can NERC CIP auditors access data in your cloud iPaaS?"
If you self-host n8n, BES Cyber System Information stays inside your CIP boundary. Zapier and Make are external CSPs — routing BCS data through them expands your CIP assessment boundary to include their infrastructure.
"Our FERC Order 2222 DER enrollment data is CEII — who can see it?"
CEII (Critical Energy Infrastructure Information) must be protected under 18 CFR §388.113. DER site coordinates, generation capacity, and interconnection details flowing through a cloud iPaaS create unauthorized disclosure exposure. Self-hosted n8n keeps CEII within your authorized enclosure.
"NRC inspection found our SaaS vendor processes safeguards information — what's the fix?"
Self-hosted n8n deployed in your facility's perimeter keeps 10 CFR §73.54 Cyber Security Plan data on-premises. The workflow engine is in your environment — no safeguards data transits a vendor cloud.
"OSHA came to our refinery — can they get our PSI from a cloud vendor?"
OSHA has broad subpoena authority. Process Safety Information and Process Hazard Analysis documents stored with a cloud vendor are discoverable. Self-hosted n8n with proper access controls keeps PSI in your documented management-of-change system.
"We're an EPA GHG mandatory reporter — can we run the calculation audit trail ourselves?"
Yes. 40 CFR §98 requires reporters to retain monitoring data and calculations. Running n8n self-hosted means your GHG calculation chain — source data, aggregation logic, annual totals — stays in your records system, not a vendor's infrastructure.
Get all 15 FlowKit n8n templates
These 5 workflows are part of the FlowKit n8n template collection — pre-built, import-ready workflows for the verticals that need automation most.
Browse FlowKit templates → stripeai.gumroad.com
Individual templates: $12–$29. Full bundle (15 templates): $97.
Top comments (0)