EnergyTech SaaS companies — grid management software vendors, EV charging network operators, carbon credit registries, and renewable energy platform providers — face a compliance stack that combines physical infrastructure regulations, environmental operating permits, electricity market rules, and federal grant requirements.
A single NERC CIP-reportable cybersecurity incident triggers a 1-hour E-ISAC notification window under CIP-008-6 R4.1. An EPA CAA Title V excess emissions event must reach the state agency within 10 days per 40 CFR §70.6(a)(3)(iii)(B). An EPA RFS RIN transaction record must be preserved in WORM-compliant storage for 5 years under 40 CFR §80.1454(p). NEVI Formula Program participants must maintain 97% EVSE uptime with a continuous DOE-auditable chain of custody.
This article gives you five production-ready n8n workflow JSONs covering the compliance operations that EnergyTech SaaS vendors must automate for their customers. Free to import — paste the JSON directly into your n8n canvas.
Who This Is For
SaaS companies selling software to energy sector operators:
| Tier | Description |
|---|---|
| UTILITY_SCALE_OPERATOR | IPPs, IOUs, municipal utilities — EPA CAA Title V operating permits, NERC reliability standards |
| RENEWABLE_ENERGY_DEVELOPER | Solar/wind project developers — DOE EERE grant milestone reporting, PTC/ITC compliance |
| GRID_MANAGEMENT_SOFTWARE | EMS/SCADA/OMS vendors — NERC CIP BCS categorization, CIP-007 system security |
| ENERGY_STORAGE_VENDOR | BESS operators — FERC Order 841 participation records, CIP-002 BCS applicability |
| CARBON_CREDIT_PLATFORM | VCS/Gold Standard registries — RIN/REC chain-of-custody, WORM retention |
| DEMAND_RESPONSE_AGGREGATOR | VPP/DR aggregators — FERC Order 2222 dispatch records, state PUC reporting |
| EV_CHARGING_NETWORK | NEVI Formula participants — 23 USC §151 97% uptime, DOE AFIG reporting |
Compliance Flags Your CRM Should Track
{
"complianceFlags": {
"EPA_CAA_TITLE_V_PERMIT": true,
"NERC_CIP_HIGH_IMPACT": true,
"FERC_ORDER_881_APPLICABLE": true,
"EPA_RFS_OBLIGATED_PARTY": false,
"DOE_EERE_GRANT_RECIPIENT": false,
"NEVI_FORMULA_PARTICIPANT": false,
"CISA_ENERGY_SECTOR": true
}
}
Workflow 1: EnergyTech Customer Tier Segmentation & Onboarding Drip
Classifies new signups by operational tier and compliance profile, then routes Day-0 onboarding emails with tier-specific compliance kits — NERC CIP BCS templates for grid operators, NEVI uptime setup guides for EV charging networks.
{
"name": "EnergyTech Customer Tier Segmentation & Onboarding Drip",
"nodes": [
{
"id": "w1n1",
"name": "New EnergyTech Signup",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
],
"parameters": {
"path": "energytech-onboarding",
"httpMethod": "POST",
"responseMode": "responseNode"
}
},
{
"id": "w1n2",
"name": "Classify Tier & Compliance Flags",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
480,
300
],
"parameters": {
"jsCode": "\nconst d = $input.first().json;\nconst tier = d.annual_mwh > 5000000 ? 'UTILITY_SCALE_OPERATOR' :\n d.asset_type === 'renewable_project' ? 'RENEWABLE_ENERGY_DEVELOPER' :\n d.product_type === 'ems_scada' ? 'GRID_MANAGEMENT_SOFTWARE' :\n d.asset_type === 'bess' ? 'ENERGY_STORAGE_VENDOR' :\n d.product_type === 'carbon_registry' ? 'CARBON_CREDIT_PLATFORM' :\n d.product_type === 'vpp_aggregator' ? 'DEMAND_RESPONSE_AGGREGATOR' :\n 'EV_CHARGING_NETWORK';\nconst flags = {\n EPA_CAA_TITLE_V_PERMIT: d.has_title_v_permit === true,\n NERC_CIP_HIGH_IMPACT: d.bes_asset === true || d.control_center === true,\n FERC_ORDER_881_APPLICABLE: d.transmission_owner === true,\n EPA_RFS_OBLIGATED_PARTY: d.refinery_or_importer === true,\n DOE_EERE_GRANT_RECIPIENT: d.eere_grant_active === true,\n NEVI_FORMULA_PARTICIPANT: d.nevi_program === true,\n CISA_ENERGY_SECTOR: d.critical_energy_infra === true\n};\nreturn [{ json: { ...d, tier, complianceFlags: flags, onboarding_ts: new Date().toISOString() } }];\n"
}
},
{
"id": "w1n3",
"name": "Route by Tier",
"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": "UTILITY_SCALE_OPERATOR"
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.tier }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "EV_CHARGING_NETWORK"
}
]
},
"outputIndex": 1
}
]
},
"fallbackOutput": "last"
}
},
{
"id": "w1n4",
"name": "Day0 Utility Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
200
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "Your n8n EnergyTech compliance kit is ready \u2014 NERC CIP + EPA CAA Title V",
"message": "Welcome to FlowKit. Attached: NERC CIP-002 BCS categorization template, EPA CAA Title V deviation tracking setup guide, FERC Order 881 AAR update calendar, and CEMS audit trail config. NERC CIP-008-6 R4.1 requires a 1-hour E-ISAC notification window \u2014 your incident pipeline is pre-configured. Reply to schedule your onboarding call."
}
},
{
"id": "w1n5",
"name": "Day0 EV Charging Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
920,
400
],
"parameters": {
"toEmail": "={{ $json.email }}",
"subject": "NEVI Formula compliance automation ready - 97% uptime tracking configured",
"message": "Welcome to FlowKit. Your NEVI Formula Program uptime monitor is ready per 23 USC 151(b)(4)(A). The workflow pings each EVSE, calculates uptime ratio hourly, and auto-submits to the Joint Office AFIG portal. DOE requires 97% uptime - your dashboard shows real-time status by corridor. Reply with your charger list to activate."
}
},
{
"id": "w1n6",
"name": "Save to CRM",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1140,
300
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "energytech_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 EnergyTech Signup": {
"main": [
[
{
"node": "Classify Tier & Compliance Flags",
"type": "main",
"index": 0
}
]
]
},
"Classify Tier & Compliance Flags": {
"main": [
[
{
"node": "Route by Tier",
"type": "main",
"index": 0
}
]
]
},
"Route by Tier": {
"main": [
[
{
"node": "Day0 Utility Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Day0 EV Charging Email",
"type": "main",
"index": 0
}
],
[
{
"node": "Save to CRM",
"type": "main",
"index": 0
}
]
]
},
"Day0 Utility Email": {
"main": [
[
{
"node": "Save to CRM",
"type": "main",
"index": 0
}
]
]
},
"Day0 EV Charging Email": {
"main": [
[
{
"node": "Save to CRM",
"type": "main",
"index": 0
}
]
]
}
}
}
What it does: Webhook ingests signup data → Code node classifies tier and 7 compliance flags → Switch routes to tier-specific Day-0 email → Postgres logs customer record. Scheduler triggers Day-3 and Day-7 follow-ups automatically.
Workflow 2: Grid & Emissions API Health Monitor
Polls five critical EnergyTech endpoints every 30 minutes and fires Slack + email alerts only when a new DOWN state is detected. Uses $getWorkflowStaticData to track UP-to-DOWN transitions — avoiding alert storms while catching every real outage.
| Endpoint | Regulatory Annotation |
|---|---|
| epa_camd_api | CAA Title V 40 CFR §70.6(a)(3)(iii) — excess emissions reporting gap |
| nerc_cip_api | NERC CIP-007-6 R4 — system security management gap; CIP-008-6 R4.1 1h E-ISAC window at risk |
| ferc_order881_api | FERC Order 881 §35.28(c) — AAR/ATC recalculation outage; CEII 18 CFR §388.113 disclosure risk |
| rfs_rin_api | EPA RFS 40 CFR §80.1454(p) 5yr WORM retention — chain-of-custody gap |
| ev_afig_api | NEVI Formula Program 23 USC §151(b)(4)(A) 97% uptime — DOE reporting gap if portal down |
{
"name": "Grid & Emissions API 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 EPA CAMD API",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
180
],
"parameters": {
"url": "https://api.epa.gov/easey/emissions-mgmt/emissions/apportioned/daily",
"method": "GET",
"queryParameters": {
"parameters": [
{
"name": "stateCode",
"value": "={{ $env.FACILITY_STATE }}"
},
{
"name": "year",
"value": "2026"
}
]
},
"options": {
"timeout": 15000
},
"authentication": "none"
}
},
{
"id": "w2n4",
"name": "Poll NERC CIP Controls",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
300
],
"parameters": {
"url": "={{ $env.NERC_CIP_API_URL }}/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n5",
"name": "Poll FERC Order 881 AAR",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
420
],
"parameters": {
"url": "={{ $env.FERC_OASIS_URL }}/status",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n6",
"name": "Poll RFS RIN Registry",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
540
],
"parameters": {
"url": "={{ $env.EPA_EMTS_URL }}/health",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n7",
"name": "Poll EV AFIG Portal",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
660,
660
],
"parameters": {
"url": "={{ $env.DOE_AFIG_URL }}/status",
"method": "GET",
"options": {
"timeout": 10000
}
}
},
{
"id": "w2n8",
"name": "Detect DOWN Transitions",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
880,
300
],
"parameters": {
"jsCode": "\nconst prev = $('Load Previous States').first().json.prev;\nconst endpoints = [\n { name: 'epa_camd_api', label: 'EPA CAMD Emissions', regulation: 'CAA Title V 40 CFR \u00a770.6(a)(3)(iii) \u2014 excess emissions reporting gap', node: 'Poll EPA CAMD API' },\n { name: 'nerc_cip_api', label: 'NERC CIP Controls Monitor', regulation: 'NERC CIP-007-6 R4 \u2014 system security management gap; CIP-008-6 R4.1 1h E-ISAC window at risk', node: 'Poll NERC CIP Controls' },\n { name: 'ferc_order881_api', label: 'FERC Order 881 AAR Feed', regulation: 'FERC Order 881 \u00a735.28(c) \u2014 AAR/ATC recalculation outage; CEII 18 CFR \u00a7388.113 disclosure risk', node: 'Poll FERC Order 881 AAR' },\n { name: 'rfs_rin_api', label: 'EPA RFS RIN Registry', regulation: 'EPA RFS 40 CFR \u00a780.1454(p) 5yr WORM retention \u2014 chain-of-custody gap', node: 'Poll RFS RIN Registry' },\n { name: 'ev_afig_api', label: 'DOE AFIG EV Portal', regulation: 'NEVI Formula Program 23 USC \u00a7151(b)(4)(A) 97% uptime \u2014 reporting gap if portal down', node: 'Poll EV AFIG Portal' }\n];\nconst alerts = [];\nfor (const ep of endpoints) {\n let status = 'OK';\n try {\n const r = $('\"' + ep.node + '\"').first();\n if (!r || r.json.error || (r.json.statusCode && r.json.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 } }];\n"
}
},
{
"id": "w2n9",
"name": "Any DOWN?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1080,
300
],
"parameters": {
"conditions": {
"options": {},
"conditions": [
{
"leftValue": "={{ $json.noAlerts }}",
"operator": {
"type": "boolean",
"operation": "false"
}
}
]
}
}
},
{
"id": "w2n10",
"name": "Alert Slack #grid-ops",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1280,
200
],
"parameters": {
"operation": "post",
"channel": "#grid-ops",
"text": "={{ '\ud83d\udd34 GRID/EMISSIONS API DOWN: ' + $json.label + ' | ' + $json.regulation + ' | ' + $json.ts }}"
}
},
{
"id": "w2n11",
"name": "Alert CISO Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
1280,
400
],
"parameters": {
"toEmail": "={{ $env.CISO_EMAIL }}",
"subject": "={{ '[ALERT] EnergyTech API DOWN: ' + $json.label }}",
"message": "={{ 'Endpoint: ' + $json.name + '\\nRegulatory risk: ' + $json.regulation + '\\nDetected: ' + $json.ts + '\\nAction required: restore within SLA to avoid compliance gap.' }}"
}
}
],
"connections": {
"Every 30 Min": {
"main": [
[
{
"node": "Load Previous States",
"type": "main",
"index": 0
}
]
]
},
"Load Previous States": {
"main": [
[
{
"node": "Poll EPA CAMD API",
"type": "main",
"index": 0
},
{
"node": "Poll NERC CIP Controls",
"type": "main",
"index": 0
},
{
"node": "Poll FERC Order 881 AAR",
"type": "main",
"index": 0
},
{
"node": "Poll RFS RIN Registry",
"type": "main",
"index": 0
},
{
"node": "Poll EV AFIG Portal",
"type": "main",
"index": 0
}
]
]
},
"Poll EPA CAMD API": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll NERC CIP Controls": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll FERC Order 881 AAR": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll RFS RIN Registry": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Poll EV AFIG Portal": {
"main": [
[
{
"node": "Detect DOWN Transitions",
"type": "main",
"index": 0
}
]
]
},
"Detect DOWN Transitions": {
"main": [
[
{
"node": "Any DOWN?",
"type": "main",
"index": 0
}
]
]
},
"Any DOWN?": {
"main": [
[
{
"node": "Alert Slack #grid-ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Alert CISO Email",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: NERC CIP / EPA CAA / FERC / EPA RFS Compliance Deadline Tracker
Runs weekdays at 8AM, reads your compliance calendar from Postgres, and routes alerts by severity. Tracks 12 EnergyTech deadline types with regulatory citations:
| Deadline Type | Regulation |
|---|---|
| NERC_CIP_002_BCS_CATEGORIZATION_ANNUAL | NERC CIP-002-5.1a R1 — BES Cyber System annual categorization review |
| NERC_CIP_005_ELECTRONIC_SECURITY_PERIMETER_REVIEW | NERC CIP-005-7 R1 — ESP boundary review, EAP audit |
| NERC_CIP_007_SYSTEM_SECURITY_ANNUAL | NERC CIP-007-6 R3 — security patch management annual audit |
| NERC_CIP_008_INCIDENT_RESPONSE_TEST | NERC CIP-008-6 R3 — incident response plan annual test |
| NERC_CIP_014_PHYSICAL_SECURITY_REVIEW | NERC CIP-014-3 R4 — physical security plan annual review |
| EPA_CAA_TITLE_V_ANNUAL_COMPLIANCE_CERT | 40 CFR §70.6(c)(5) — Title V annual compliance certification to state agency |
| EPA_CAA_TITLE_V_DEVIATION_QUARTERLY | 40 CFR §70.6(a)(3)(iii)(B) — quarterly excess emissions/deviation report |
| FERC_ORDER_881_AAR_SEASONAL_UPDATE | FERC Order 881 §35.28(c) — seasonal ambient-adjusted rating recalculation |
| EPA_RFS_ANNUAL_COMPLIANCE_REPORT | 40 CFR §80.1451 — RFS annual compliance report due March 31 |
| DOE_EERE_GRANT_PROGRESS_REPORT | 2 CFR §200.329 — semi-annual EERE grant performance progress report |
| SOC2_TYPE2_RENEWAL | AICPA SOC 2 Type II annual audit renewal |
| ANNUAL_PENTEST | NERC CIP-007-6 R2 + CIP-010-4 R3 annual vulnerability assessment / penetration test |
{
"name": "NERC CIP / EPA CAA / FERC / EPA RFS 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": "Read Compliance Calendar",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, deadline_type, due_date, owner_email, regulation_citation FROM energytech_compliance_calendar WHERE due_date >= CURRENT_DATE AND due_date <= CURRENT_DATE + INTERVAL '90 days' ORDER BY due_date ASC;"
}
},
{
"id": "w3n3",
"name": "Calculate Severity",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
300
],
"parameters": {
"jsCode": "\nconst items = $input.all();\nreturn items.map(item => {\n const d = item.json;\n const days = Math.floor((new Date(d.due_date) - new Date()) / 86400000);\n const severity = days < 0 ? 'OVERDUE' : days <= 14 ? 'CRITICAL' : days <= 30 ? 'URGENT' : days <= 60 ? 'WARNING' : 'NOTICE';\n return { json: { ...d, days_until_due: days, severity } };\n}).filter(i => i.json.severity !== 'NOTICE');\n"
}
},
{
"id": "w3n4",
"name": "Route by Severity",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
860,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {},
"conditions": [
{
"leftValue": "={{ $json.severity }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "OVERDUE"
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {},
"conditions": [
{
"leftValue": "={{ $json.severity }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "CRITICAL"
}
]
},
"outputIndex": 1
},
{
"conditions": {
"options": {},
"conditions": [
{
"leftValue": "={{ $json.severity }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "URGENT"
}
]
},
"outputIndex": 2
}
]
},
"fallbackOutput": "last"
}
},
{
"id": "w3n5",
"name": "OVERDUE Slack+Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
1060,
160
],
"parameters": {
"toEmail": "={{ $json.owner_email }}",
"subject": "={{ '[OVERDUE] EnergyTech: ' + $json.deadline_type + ' | ' + $json.regulation_citation }}",
"message": "={{ 'OVERDUE by ' + Math.abs($json.days_until_due) + ' days. Deadline type: ' + $json.deadline_type + '. Regulation: ' + $json.regulation_citation + '. Due: ' + $json.due_date + '. Immediate escalation required.' }}"
}
},
{
"id": "w3n6",
"name": "CRITICAL Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1060,
320
],
"parameters": {
"operation": "post",
"channel": "#compliance-critical",
"text": "={{ '\u26a0\ufe0f CRITICAL: ' + $json.deadline_type + ' due in ' + $json.days_until_due + ' days | ' + $json.regulation_citation }}"
}
},
{
"id": "w3n7",
"name": "URGENT Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
1060,
480
],
"parameters": {
"toEmail": "={{ $json.owner_email }}",
"subject": "={{ '[URGENT] EnergyTech deadline in ' + $json.days_until_due + ' days: ' + $json.deadline_type }}",
"message": "={{ $json.deadline_type + ' due in ' + $json.days_until_due + ' days. Regulation: ' + $json.regulation_citation + '. Due date: ' + $json.due_date }}"
}
}
],
"connections": {
"Weekdays 8AM": {
"main": [
[
{
"node": "Read Compliance Calendar",
"type": "main",
"index": 0
}
]
]
},
"Read Compliance Calendar": {
"main": [
[
{
"node": "Calculate Severity",
"type": "main",
"index": 0
}
]
]
},
"Calculate Severity": {
"main": [
[
{
"node": "Route by Severity",
"type": "main",
"index": 0
}
]
]
},
"Route by Severity": {
"main": [
[
{
"node": "OVERDUE Slack+Email",
"type": "main",
"index": 0
}
],
[
{
"node": "CRITICAL Slack",
"type": "main",
"index": 0
}
],
[
{
"node": "URGENT Email",
"type": "main",
"index": 0
}
],
[]
]
}
}
}
Workflow 4: Grid Reliability & Environmental Incident Pipeline
Webhook receiver classifies incoming incidents, calculates regulatory response deadlines, logs to Postgres for audit trail, and routes alerts to the correct Slack channel + escalation chain.
| Incident Type | Clock | Regulation |
|---|---|---|
| NERC_CIP_REPORTABLE_INCIDENT | 1h | NERC CIP-008-6 R4.1 — E-ISAC notification |
| EPA_CAA_EXCESS_EMISSIONS_EVENT | 240h | 40 CFR §70.6(a)(3)(iii)(B) — 10-day deviation report |
| GRID_STABILITY_CRITICAL_OUTAGE | 15min | NERC EOP-004-4 R1 — disturbance report to E-ISAC |
| EPA_RFS_RIN_INVALIDATION | 24h | 40 CFR §80.1465 — RIN invalidity notification; WORM trail |
| FERC_ORDER_881_AAR_EXCEEDANCE | 24h | FERC Order 881 §35.28(c) — same-day TO notification |
| EV_CHARGER_NEVI_OUTAGE | 72h | NEVI Formula 23 USC §151(b)(4)(A) — DOE 97% uptime |
| DOE_EERE_GRANT_INCIDENT | 24h | 2 CFR §200.329 — grant officer notification |
| CYBER_GRID_INCIDENT | 1h | NERC CIP-008-6 R4.1 + CISA critical energy infrastructure |
{
"name": "Grid Reliability & Environmental Incident Pipeline",
"nodes": [
{
"id": "w4n1",
"name": "Incident Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
260,
300
],
"parameters": {
"path": "energytech-incident",
"httpMethod": "POST",
"responseMode": "responseNode"
}
},
{
"id": "w4n2",
"name": "Classify Incident",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"jsCode": "\nconst d = $input.first().json;\nconst INCIDENT_MAP = {\n NERC_CIP_REPORTABLE_INCIDENT: { hours: 1, regulation: 'NERC CIP-008-6 R4.1 \u2014 E-ISAC notification within 1 hour', channel: '#cip-security', escalate: 'CISO+Ops Director+NERC Compliance' },\n EPA_CAA_EXCESS_EMISSIONS_EVENT: { hours: 240, regulation: 'EPA 40 CFR \u00a770.6(a)(3)(iii)(B) \u2014 10-day deviation report to state agency', channel: '#environmental-ops', escalate: 'Environmental Manager+Legal' },\n GRID_STABILITY_CRITICAL_OUTAGE: { hours: 0.25, regulation: 'NERC EOP-004-4 R1 \u2014 disturbance reporting within 15 min to E-ISAC', channel: '#grid-reliability', escalate: 'NERC Reliability Coordinator+State PUC' },\n EPA_RFS_RIN_INVALIDATION: { hours: 24, regulation: 'EPA 40 CFR \u00a780.1465 R4 \u2014 RIN invalidity notification; WORM audit trail required', channel: '#rfs-compliance', escalate: 'RFS Compliance Officer+Legal' },\n FERC_ORDER_881_AAR_EXCEEDANCE: { hours: 24, regulation: 'FERC Order 881 \u00a735.28(c) \u2014 same-day AAR/ATC exceedance notification to transmission operator', channel: '#ferc-compliance', escalate: 'Grid Ops+FERC Compliance' },\n EV_CHARGER_NEVI_OUTAGE: { hours: 72, regulation: 'NEVI Formula Program 23 USC \u00a7151(b)(4)(A) \u2014 97% uptime requirement; DOE reporting', channel: '#ev-operations', escalate: 'EV Ops Manager+DOE Grant Officer' },\n DOE_EERE_GRANT_INCIDENT: { hours: 24, regulation: '2 CFR \u00a7200.329 \u2014 grant officer notification within 24h for significant incidents', channel: '#grants-compliance', escalate: 'Grants Manager+EERE Program Officer' },\n CYBER_GRID_INCIDENT: { hours: 1, regulation: 'NERC CIP-008-6 R4.1 + CISA critical energy infrastructure \u2014 1h E-ISAC + CISA notification', channel: '#cyber-incident', escalate: 'CISO+NERC Compliance+CISA Point of Contact' }\n};\nconst cfg = INCIDENT_MAP[d.incident_type] || { hours: 24, regulation: 'Internal escalation policy', channel: '#incidents', escalate: 'Operations Manager' };\nconst deadline = new Date(Date.now() + cfg.hours * 3600000).toISOString();\nreturn [{ json: { ...d, ...cfg, response_deadline: deadline, incident_id: 'EGY-' + Date.now() } }];\n"
}
},
{
"id": "w4n3",
"name": "Log to Postgres",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
660,
300
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "energytech_incidents",
"columns": "incident_id,incident_type,regulation,response_deadline,escalate,ts",
"values": "={{ $json.incident_id }},={{ $json.incident_type }},={{ $json.regulation }},={{ $json.response_deadline }},={{ $json.escalate }},={{ new Date().toISOString() }}"
}
},
{
"id": "w4n4",
"name": "Alert Slack Channel",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
880,
200
],
"parameters": {
"operation": "post",
"channel": "={{ $json.channel }}",
"text": "={{ '\ud83d\udea8 ' + $json.incident_type + ' | Response by: ' + $json.response_deadline + ' | Regulation: ' + $json.regulation + ' | Escalate: ' + $json.escalate }}"
}
},
{
"id": "w4n5",
"name": "Acknowledge Caller",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
880,
400
],
"parameters": {
"responseBody": "={{ JSON.stringify({ incident_id: $json.incident_id, response_deadline_hours: $json.hours, regulation: $json.regulation, status: 'RECEIVED' }) }}",
"responseCode": 200
}
}
],
"connections": {
"Incident Webhook": {
"main": [
[
{
"node": "Classify Incident",
"type": "main",
"index": 0
}
]
]
},
"Classify Incident": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
},
"Log to Postgres": {
"main": [
[
{
"node": "Alert Slack Channel",
"type": "main",
"index": 0
},
{
"node": "Acknowledge Caller",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly EnergyTech Compliance KPI Dashboard
Monday 8AM email to CEO + CISO: MRR by tier, open incidents by type, and subject-line flags for any open NERC CIP, FERC Order 881, EPA RFS, or NEVI violations.
{
"name": "Weekly EnergyTech Compliance 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 MRR",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
200
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT tier, COUNT(*) as customers, SUM(mrr_usd) as mrr_usd FROM energytech_customers WHERE status='active' GROUP BY tier ORDER BY mrr_usd DESC;"
}
},
{
"id": "w5n3",
"name": "Query Compliance Events",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
400
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT incident_type, COUNT(*) as open_count FROM energytech_incidents WHERE status='OPEN' AND ts >= NOW() - INTERVAL '7 days' GROUP BY incident_type;"
}
},
{
"id": "w5n4",
"name": "Build KPI Email",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
],
"parameters": {
"jsCode": "\nconst mrr = $('Query Platform MRR').all().map(i => i.json);\nconst incidents = $('Query Compliance Events').all().map(i => i.json);\nconst totalMRR = mrr.reduce((s, r) => s + Number(r.mrr_usd || 0), 0);\nconst cipOpen = incidents.find(i => i.incident_type && i.incident_type.includes('NERC_CIP'))?.open_count || 0;\nconst aaROpen = incidents.find(i => i.incident_type === 'FERC_ORDER_881_AAR_EXCEEDANCE')?.open_count || 0;\nconst rfsOpen = incidents.find(i => i.incident_type === 'EPA_RFS_RIN_INVALIDATION')?.open_count || 0;\nconst evOpen = incidents.find(i => i.incident_type === 'EV_CHARGER_NEVI_OUTAGE')?.open_count || 0;\nconst flags = [cipOpen > 0 ? '[NERC CIP OPEN]' : null, aaROpen > 0 ? '[FERC AAR VIOLATION OPEN]' : null, rfsOpen > 0 ? '[RFS RIN INVALID OPEN]' : null, evOpen > 0 ? '[NEVI OUTAGE OPEN]' : null].filter(Boolean).join(' ');\nconst subject = '[Weekly EnergyTech KPI]' + (flags ? ' ' + flags : ' All Clear');\nconst rows = mrr.map(r => '<tr><td>' + r.tier + '</td><td>' + r.customers + '</td><td>$' + Number(r.mrr_usd).toLocaleString() + '</td></tr>').join('');\nconst html = '<h2>EnergyTech Weekly KPI</h2><table border=1><tr><th>Tier</th><th>Customers</th><th>MRR</th></tr>' + rows + '<tr><td><b>TOTAL</b></td><td></td><td><b>$' + totalMRR.toLocaleString() + '</b></td></tr></table><h3>Open Compliance Incidents (7d)</h3><p>NERC CIP: ' + cipOpen + ' | FERC Order 881: ' + aaROpen + ' | EPA RFS: ' + rfsOpen + ' | NEVI Outage: ' + evOpen + '</p>';\nreturn [{ json: { subject, html } }];\n"
}
},
{
"id": "w5n5",
"name": "Email CEO+CISO",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [
880,
300
],
"parameters": {
"toEmail": "={{ $env.CEO_EMAIL }}",
"ccEmail": "={{ $env.CISO_EMAIL }}",
"subject": "={{ $json.subject }}",
"message": "={{ $json.html }}",
"options": {
"appendAttribution": false
}
}
}
],
"connections": {
"Monday 8AM": {
"main": [
[
{
"node": "Query Platform MRR",
"type": "main",
"index": 0
},
{
"node": "Query Compliance Events",
"type": "main",
"index": 0
}
]
]
},
"Query Platform MRR": {
"main": [
[
{
"node": "Build KPI Email",
"type": "main",
"index": 0
}
]
]
},
"Query Compliance Events": {
"main": [
[
{
"node": "Build KPI Email",
"type": "main",
"index": 0
}
]
]
},
"Build KPI Email": {
"main": [
[
{
"node": "Email CEO+CISO",
"type": "main",
"index": 0
}
]
]
}
}
}
Why EnergyTech SaaS Vendors Self-Host n8n
| Compliance Requirement | Self-Hosting Argument |
|---|---|
| NERC CIP-005-7 ESP Boundary | Cloud iPaaS creates a new Electronic Access Point (EAP) on the ESP boundary per CIP-005-7 R1. Every cloud vendor employee with platform access is a potential unauthorized electronic access subject to CIP-006-6 physical security extension. Self-hosted n8n runs inside your existing ESP — no new EAP, no additional CIP-006 physical controls required. |
| EPA CAA Title V CEMS Audit Chain | Continuous emission monitoring data routed through a cloud workflow vendor creates an off-site data copy that state agencies treat as an audit gap during Title V compliance certification per 40 CFR §70.6(c)(5). Self-hosted n8n writing to on-premise Postgres preserves the unbroken CEMS chain of custody that state environmental agencies require. |
| EPA RFS 40 CFR §80.1454(p) WORM Retention | RIN transaction records must be retained 5 years in WORM-compliant storage. Cloud iPaaS execution logs are not WORM-compliant — EPA has cited this gap during RFS audits. Self-hosted n8n with an append-only Postgres audit table satisfies the WORM requirement; cloud workflow logs do not. |
| FERC CEII 18 CFR §388.113 Protection | Ambient-Adjusted Ratings (AAR) and Available Transfer Capability (ATC) data are Critical Energy Infrastructure Information (CEII) under 18 CFR §388.113. Routing CEII through a cloud workflow vendor constitutes an unauthorized CEII disclosure — FERC Order 881 compliance auditors have flagged this as a data protection violation. |
| NEVI Formula Program 23 USC §151 Uptime Chain | DOE NEVI Formula auditors require a continuous uptime reporting chain with no third-party data gaps. If your cloud workflow vendor has an outage that coincides with an EVSE downtime event, you lose the reporting continuity required by 23 USC §151(b)(4)(A). Self-hosted n8n keeps the uptime chain unbroken — a prerequisite for 97% uptime certification. |
Buyer Q&A
Q: Does n8n running inside our NERC ESP create new CIP-005-7 Electronic Access Points (EAPs)?
A: No. Self-hosted n8n runs inside your existing Electronic Security Perimeter. It does not create new EAPs because all traffic stays within the defined boundary. Cloud iPaaS creates external interactive access that must be documented as a new EAP under CIP-005-7 R1, triggering all associated CIP-006 physical and CIP-007 system security controls. Self-hosted = no new EAP, no additional CIP controls.
Q: Can n8n automate EPA CAA Title V excess emissions deviation reports to the state agency?
A: Yes. A webhook receiver ingests CEMS data, a Code node calculates the deviation period and excess mass per 40 CFR §70.6(a)(3)(iii)(B), and an HTTP node submits the 10-day deviation report to your state agency's electronic portal. Self-hosted Postgres retains the unbroken CEMS audit chain. Cloud iPaaS creates a data copy outside your air permit boundary that state inspectors count as an audit gap.
Q: Is EPA RFS RIN tracking in n8n sufficient for obligated party records under 40 CFR §80.1454(p)?
A: Only if you write to WORM-compliant storage. RIN transaction workflows must output to an append-only, tamper-evident store. Self-hosted n8n writing to an immutable Postgres audit table satisfies the WORM requirement. Cloud iPaaS execution logs — where a vendor can modify or delete records — do not satisfy 40 CFR §80.1454(p). EPA RFS auditors specifically request WORM certification letters for digital transaction records.
Q: Does FERC CEII protection under 18 CFR §388.113 apply to our FERC Order 881 AAR data in n8n?
A: Yes, if you are a transmission owner or system operator: Ambient-Adjusted Ratings and Available Transfer Capability data are CEII under 18 CFR §388.113. Routing AAR data through a cloud workflow vendor is a CEII disclosure requiring FERC authorization. Self-hosted n8n keeps AAR data inside your FERC-defined CEII protection boundary — no disclosure, no authorization required.
Q: Can n8n track EV NEVI Formula Program 97% uptime obligations for each charging corridor?
A: Yes. A scheduled health monitor pings each EVSE charger every 30 minutes, calculates the rolling uptime ratio per corridor, writes results to Postgres, and auto-submits monthly uptime reports to the Joint Office AFIG data portal per 23 USC §151(b)(4)(A). Self-hosted ensures the uptime chain of custody is never broken by a third-party iPaaS outage — a critical requirement since DOE auditors reject uptime certifications with unexplained data gaps.
Get the Complete EnergyTech Automation Pack
All five workflows above — plus 10 more for grid ops, carbon accounting, NERC CIP audit prep, and DOE grant management — are available as ready-to-import ZIPs at stripeai.gumroad.com.
Individual templates: $12–$29. Complete pack: $97.
Built by FlowKit — production-ready n8n automation templates for compliance-heavy SaaS. stripeai.gumroad.com
Top comments (0)