If you sell software to sustainability teams, ESG reporting officers, or corporate carbon accounting departments — your platform sits inside one of the most rapidly regulated technology stacks in existence.
The SEC's climate disclosure rule (17 CFR Parts 210, 229, 249) now requires large accelerated filers to report Scope 1 and Scope 2 GHG emissions in their annual 10-K filings starting FY2025. The EU Corporate Sustainability Reporting Directive (CSRD) + European Sustainability Reporting Standards (ESRS E1) imposes mandatory climate disclosures for in-scope EU companies with limited assurance starting FY2024, escalating to reasonable assurance by FY2028.
Here is the problem that nobody is talking about yet: if your ESG calculation engine runs through Zapier, Make, or any other cloud iPaaS, your Scope 1/2 methodology is fragmented across a third-party's infrastructure — and that third party can be subpoenaed directly by the SEC without notifying you.
SEC examinations expect immediate production of complete GHG calculation chains. An ESRS E1 auditor must independently verify the entire data transformation path from source data to reported emissions figure. Neither of those requirements can be met when your automation nodes live in Zapier's cloud.
Who This Article Is For
This is for engineering and ops teams at Sustainability & ESG Reporting SaaS vendors — not for the corporate sustainability teams that use ESG software. If you build:
- Enterprise ESG reporting platforms (Workiva, Persefoni, Sweep, Greenly-style)
- Carbon accounting SaaS (GHG Protocol Scope 1/2/3 calculation engines)
- Supply chain sustainability SaaS (Scope 3 Category 1-15 value chain tools)
- Impact measurement SaaS (IRIS+ metrics, B Corp assessment tools)
- CSRD/EU Taxonomy reporting SaaS (ESRS compliance automation)
- Sustainability data management platforms (ESG data aggregation, CDP submission tools)
...then these workflows are built for your stack.
Customer Tiers
Seven customer tiers: ENTERPRISE_ESG_PLATFORM / CARBON_ACCOUNTING_SAAS / SUPPLY_CHAIN_SUSTAINABILITY_SAAS / IMPACT_MEASUREMENT_SAAS / CSRD_REPORTING_SAAS / SUSTAINABILITY_DATA_MANAGEMENT / ESG_STARTUP
Seven compliance flags that determine which workflows fire: {' / '.join(FLAG_LIST)}
The 12 Deadline Types
Your platform's deadline tracker needs to cover:
SEC_CLIMATE_10K_ANNUALSEC_CLIMATE_SCOPE1_2_DISCLOSUREEU_CSRD_ESRS_E1_ANNUALEU_CSRD_ESRS_S1_ANNUALEPA_GHGRP_40_CFR_98_MARCH31ISO_14064_VERIFICATION_ANNUALTCFD_BOARD_GOVERNANCE_ANNUALCDP_CLIMATE_DISCLOSURE_DEADLINESBTi_NEAR_TERM_MILESTONEGHG_SCOPE3_SUPPLY_CHAIN_AUDITEU_TAXONOMY_ALIGNMENT_ANNUALSOC2_TYPE2_RENEWAL
The 8 Incident Types — Fastest Clock First
| Incident | Severity | Clock | Authority |
|---|---|---|---|
SEC_CLIMATE_DISCLOSURE_INVESTIGATION |
CRITICAL | IMMEDIATE | SEC Division of Enforcement |
EU_CSRD_REGULATORY_INQUIRY |
CRITICAL | 10 business days | National competent authority (ESMA coordination) |
EPA_GHGRP_DATA_DISCREPANCY |
HIGH | 30 days | EPA Office of Atmospheric Programs 40 CFR §98.3(h) |
ISO_14064_VERIFICATION_FAILURE |
HIGH | 60 days | Accredited verification body |
GHG_CALCULATION_ERROR_MATERIAL |
HIGH | IMMEDIATE restatement analysis | SEC §229.1502(d) materiality threshold |
CDP_SCORE_DISPUTE |
MEDIUM | 30 days | CDP Disclosure Insight Action |
DATA_BREACH_ESG_METHODOLOGY |
HIGH | 72 hours GDPR Art.33 + SEC Reg S-P | DPA + SEC |
GREENWASHING_COMPLAINT_FTC |
CRITICAL | IMMEDIATE — FTC Green Guides 16 CFR Part 260 | FTC Bureau of Consumer Protection |
SEC_CLIMATE_DISCLOSURE_INVESTIGATIONis the fastest clock — IMMEDIATE. When the SEC opens a climate disclosure investigation, they expect complete Scope 1/2 calculation methodology records on demand. If those records live in Zapier's cloud, production requires Zapier's cooperation — not yours.
5 Workflows — Full Import-Ready JSON
All five workflows are import-ready. In n8n: Settings → Import workflow → paste JSON.
Workflow 1: Tier-Segmented Customer Onboarding Drip
Classifies each new customer by ESG tier and compliance flags, sends a Day 0 welcome email with a tier-specific compliance architecture note (SEC §229.1500 context for enterprise platforms, CSRD ESRS E1 §8.6 for carbon accounting SaaS, Scope 3 value chain assurance for supply chain tools), notifies the CSM via Slack, waits 3 days, and sends a Day 3 check-in.
{
"name": "ESG SaaS \u2014 Tier-Segmented Customer Onboarding Drip",
"nodes": [
{
"id": "1",
"name": "Trigger: New Customer Signup",
"type": "n8n-nodes-base.sheetsTrigger",
"position": [
240,
300
],
"parameters": {
"operation": "appendOrUpdate",
"sheetId": "={{ $env.ONBOARDING_SHEET_ID }}",
"range": "A:Z"
}
},
{
"id": "2",
"name": "Code: Classify Tier + Flags",
"type": "n8n-nodes-base.code",
"position": [
460,
300
],
"parameters": {
"jsCode": "const r = $input.first().json;\nconst tier = (r.tier || '').toUpperCase();\nconst flags = (r.flags || '').toUpperCase().split(',').map(f => f.trim());\n\nconst tierNotes = {\n ENTERPRISE_ESG_PLATFORM: 'Your Scope 1/2/3 calculation engine is now subject to SEC 17 CFR \u00a7229.1500 climate disclosure. All GHG data transformations running through cloud iPaaS create audit trail fragmentation \u2014 SEC examiners expect a complete, traceable calculation chain on IMMEDIATE request.',\n CARBON_ACCOUNTING_SAAS: 'Carbon accounting methodology under GHG Protocol + ISO 14064-1:2018 \u00a78.6 requires traceable, independently verifiable calculation chains. Cloud iPaaS nodes in your Scope 1/2 pipeline are third-party processors outside your verification boundary.',\n SUPPLY_CHAIN_SUSTAINABILITY_SAAS: 'GHG Protocol Scope 3 Category 1-15 data flows through your platform. EU CSRD ESRS E1 para.40 requires Scope 3 value chain data to be independently assurable by FY2028 \u2014 audit trail must remain inside your compliance boundary.',\n IMPACT_MEASUREMENT_SAAS: 'ESG impact data flowing through cloud automation is subject to SEC anti-greenwashing enforcement (FTC Green Guides 16 CFR Part 260). Your platform methodology is discoverable evidence in regulatory investigations.',\n CSRD_REPORTING_SAAS: 'EU CSRD Art.29a requires statutory auditor or independent assurance provider access to all data used in sustainability reporting. Audit trail fragmented across Zapier/Make cloud prevents the assurance provider from completing their \u00a734 review.',\n SUSTAINABILITY_DATA_MANAGEMENT: 'EU Taxonomy Regulation Art.8 disclosure requires traceable alignment assessment data. SFDR Art.4+8+9 fund-level ESG data must be retained under Art.28(2) for 5 years \u2014 cloud iPaaS retention policies may not align.',\n ESG_STARTUP: 'Welcome to FlowKit. As you scale toward enterprise customers, they will ask about your SEC climate disclosure data lineage and EU CSRD audit readiness before procurement. Architecture decisions made now define your compliance posture at Series B.'\n};\n\nconst hasSec = flags.includes('SEC_CLIMATE_DISCLOSURE_SUBJECT');\nconst hasCsrd = flags.includes('EU_CSRD_IN_SCOPE');\nconst hasGhgrp = flags.includes('EPA_GHGRP_REPORTER');\n\nreturn [{\n json: {\n ...r,\n tier,\n flags,\n tier_note: tierNotes[tier] || tierNotes['ESG_STARTUP'],\n has_sec: hasSec,\n has_csrd: hasCsrd,\n has_ghgrp: hasGhgrp,\n onboarding_subject: `Welcome to FlowKit \u2014 Your ESG Automation Is Live`,\n cta_url: 'https://stripeai.gumroad.com'\n }\n}];"
}
},
{
"id": "3",
"name": "Gmail: Day 0 Welcome",
"type": "n8n-nodes-base.gmail",
"position": [
680,
300
],
"parameters": {
"operation": "send",
"toList": "={{ $json.email }}",
"subject": "={{ $json.onboarding_subject }}",
"message": "Hi {{ $json.name }},\n\nWelcome to FlowKit.\n\nImportant for your compliance architecture:\n{{ $json.tier_note }}\n\nYour automation workflows are ready. Browse templates: {{ $json.cta_url }}\n\nAlex Kane\nFlowKit"
}
},
{
"id": "4",
"name": "Slack: CSM Notification",
"type": "n8n-nodes-base.slack",
"position": [
680,
440
],
"parameters": {
"channel": "#cs-new-customers",
"text": "New {{ $json.tier }} customer: {{ $json.name }} ({{ $json.email }}). SEC: {{ $json.has_sec }}, CSRD: {{ $json.has_csrd }}, GHGRP: {{ $json.has_ghgrp }}."
}
},
{
"id": "5",
"name": "Wait: 3 days",
"type": "n8n-nodes-base.wait",
"position": [
900,
300
],
"parameters": {
"amount": 3,
"unit": "days"
}
},
{
"id": "6",
"name": "Gmail: Day 3 Check-in",
"type": "n8n-nodes-base.gmail",
"position": [
1120,
300
],
"parameters": {
"operation": "send",
"toList": "={{ $json.email }}",
"subject": "Your ESG automation check-in",
"message": "Hi {{ $json.name }},\n\nHow are the workflows running? Common questions at day 3:\n- Scope 1/2 data pipeline setup\n- GHG Protocol calculation node configuration\n- Deadline tracker for {{ $json.has_csrd ? 'EU CSRD ESRS E1' : 'SEC climate disclosure' }}\n\nReply to this email \u2014 happy to help.\n\nAlex Kane\nFlowKit"
}
},
{
"id": "7",
"name": "Sheets: Log Onboarding",
"type": "n8n-nodes-base.googleSheets",
"position": [
1340,
300
],
"parameters": {
"operation": "append",
"sheetId": "={{ $env.ONBOARDING_LOG_SHEET_ID }}",
"columns": {
"mappingMode": "defineBelow",
"value": {
"customer_name": "={{ $json.name }}",
"tier": "={{ $json.tier }}",
"day0_sent": "={{ new Date().toISOString() }}",
"sec_flag": "={{ $json.has_sec }}",
"csrd_flag": "={{ $json.has_csrd }}",
"ghgrp_flag": "={{ $json.has_ghgrp }}"
}
}
}
}
],
"connections": {
"Trigger: New Customer Signup": {
"main": [
[
{
"node": "Code: Classify Tier + Flags",
"type": "main",
"index": 0
}
]
]
},
"Code: Classify Tier + Flags": {
"main": [
[
{
"node": "Gmail: Day 0 Welcome",
"type": "main",
"index": 0
},
{
"node": "Slack: CSM Notification",
"type": "main",
"index": 0
}
]
]
},
"Gmail: Day 0 Welcome": {
"main": [
[
{
"node": "Wait: 3 days",
"type": "main",
"index": 0
}
]
]
},
"Wait: 3 days": {
"main": [
[
{
"node": "Gmail: Day 3 Check-in",
"type": "main",
"index": 0
}
]
]
},
"Gmail: Day 3 Check-in": {
"main": [
[
{
"node": "Sheets: Log Onboarding",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: SEC/EU CSRD/EPA/ISO Compliance Deadline Tracker
Runs daily at 07:00 UTC. Reads your compliance deadlines sheet, classifies each row as OVERDUE / CRITICAL (<7d) / URGENT (<14d) / WARNING (<30d) / NOTICE (<60d), and routes alerts: critical deadlines hit #esg-compliance-critical on Slack + direct Gmail to the compliance owner; non-critical go to #esg-compliance-watch.
{
"name": "ESG SaaS \u2014 SEC/CSRD/EPA/ISO Compliance Deadline Tracker",
"nodes": [
{
"id": "1",
"name": "Schedule: Daily 07:00 UTC",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * *"
}
]
}
}
},
{
"id": "2",
"name": "Sheets: Read Compliance Deadlines",
"type": "n8n-nodes-base.googleSheets",
"position": [
460,
300
],
"parameters": {
"operation": "readRows",
"sheetId": "={{ $env.ESG_DEADLINES_SHEET_ID }}",
"range": "A:F"
}
},
{
"id": "3",
"name": "Code: Classify Urgency",
"type": "n8n-nodes-base.code",
"position": [
680,
300
],
"parameters": {
"jsCode": "const rows = $input.all();\nconst now = new Date();\nconst alerts = [];\n\nfor (const row of rows) {\n const d = row.json;\n const deadline = new Date(d.deadline_date);\n const daysLeft = Math.ceil((deadline - now) / 86400000);\n\n let urgency = null;\n const t = (d.deadline_type || '').toUpperCase();\n\n if (t === 'SEC_CLIMATE_DISCLOSURE_INVESTIGATION' || t === 'GREENWASHING_COMPLAINT_FTC') {\n urgency = 'CRITICAL';\n } else if (daysLeft < 0) {\n urgency = 'OVERDUE';\n } else if (daysLeft <= 7) {\n urgency = 'CRITICAL';\n } else if (daysLeft <= 14) {\n urgency = 'URGENT';\n } else if (daysLeft <= 30) {\n urgency = 'WARNING';\n } else if (daysLeft <= 60) {\n urgency = 'NOTICE';\n }\n\n if (urgency) {\n alerts.push({...d, days_left: daysLeft, urgency});\n }\n}\n\nreturn alerts.map(a => ({json: a}));"
}
},
{
"id": "4",
"name": "IF: Critical or Overdue",
"type": "n8n-nodes-base.if",
"position": [
900,
300
],
"parameters": {
"conditions": {
"options": {
"combineOperation": "any"
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "CRITICAL"
},
{
"leftValue": "={{ $json.urgency }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "OVERDUE"
}
]
}
}
},
{
"id": "5",
"name": "Slack: #esg-compliance-critical",
"type": "n8n-nodes-base.slack",
"position": [
1120,
200
],
"parameters": {
"channel": "#esg-compliance-critical",
"text": "[{{ $json.urgency }}] {{ $json.deadline_type }} \u2014 {{ $json.days_left }} days. Customer: {{ $json.customer_name }}. Authority: {{ $json.authority }}."
}
},
{
"id": "6",
"name": "Gmail: Owner Alert",
"type": "n8n-nodes-base.gmail",
"position": [
1120,
340
],
"parameters": {
"operation": "send",
"toList": "={{ $json.owner_email }}",
"subject": "[{{ $json.urgency }}] ESG Compliance Deadline: {{ $json.deadline_type }}",
"message": "Deadline: {{ $json.deadline_type }}\nDays remaining: {{ $json.days_left }}\nAuthority: {{ $json.authority }}\nCustomer: {{ $json.customer_name }}\nUrgency: {{ $json.urgency }}\n\nAction required immediately."
}
},
{
"id": "7",
"name": "Slack: #esg-compliance-watch (non-critical)",
"type": "n8n-nodes-base.slack",
"position": [
1120,
480
],
"parameters": {
"channel": "#esg-compliance-watch",
"text": "[{{ $json.urgency }}] {{ $json.deadline_type }} \u2014 {{ $json.days_left }} days remaining. Customer: {{ $json.customer_name }}."
}
}
],
"connections": {
"Schedule: Daily 07:00 UTC": {
"main": [
[
{
"node": "Sheets: Read Compliance Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Sheets: Read Compliance Deadlines": {
"main": [
[
{
"node": "Code: Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Code: Classify Urgency": {
"main": [
[
{
"node": "IF: Critical or Overdue",
"type": "main",
"index": 0
}
]
]
},
"IF: Critical or Overdue": {
"main": [
[
{
"node": "Slack: #esg-compliance-critical",
"type": "main",
"index": 0
},
{
"node": "Gmail: Owner Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack: #esg-compliance-watch (non-critical)",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: GHG Data Pipeline API Health Monitor
Checks five critical ESG data pipeline endpoints every 15 minutes — Scope 1 calculation API, Scope 2 location/market-based API, Scope 3 supply chain API, EPA e-GGRT submission API, and CDP Online Response System API. Each endpoint carries its regulatory standard annotation (ISO 14064-1 §8.2, ESRS E1 para.40, 40 CFR Part 98). Downtime on the EPA GHGRP endpoint before March 31 = missed annual deadline + civil penalty.
{
"name": "ESG SaaS \u2014 GHG Data Pipeline API Health Monitor",
"nodes": [
{
"id": "1",
"name": "Schedule: Every 15 min",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
}
},
{
"id": "2",
"name": "Code: Define Endpoints",
"type": "n8n-nodes-base.code",
"position": [
460,
300
],
"parameters": {
"jsCode": "return [\n {json: {name: 'scope1_calculation_api', url: process.env.SCOPE1_API_URL, standard: 'GHG Protocol Scope 1 / ISO 14064-1 \u00a78.2 \u2014 stationary combustion + fugitive emissions', critical_note: 'SEC \u00a7229.1502(b) Scope 1 GHG data \u2014 downtime = calculation chain break during audit period'}},\n {json: {name: 'scope2_location_api', url: process.env.SCOPE2_API_URL, standard: 'GHG Protocol Scope 2 location-based / market-based / ESRS E1 para.40', critical_note: 'EU CSRD ESRS E1 requires both calculation methods \u2014 dual-method downtime = CSRD gap'}},\n {json: {name: 'scope3_supply_chain_api', url: process.env.SCOPE3_API_URL, standard: 'GHG Protocol Scope 3 Cat 1-15 / CSRD ESRS E1 para.51-64', critical_note: 'Scope 3 value chain data \u2014 CSRD FY2028 reasonable assurance requires complete data lineage'}},\n {json: {name: 'epa_ghgrp_submission_api', url: process.env.EPA_GHGRP_API_URL, standard: 'EPA 40 CFR Part 98 e-GGRT portal \u2014 annual March 31 deadline', critical_note: 'e-GGRT submission endpoint \u2014 downtime before March 31 = missed EPA GHGRP deadline + civil penalty \u00a798.3(h)'}},\n {json: {name: 'cdp_disclosure_api', url: process.env.CDP_API_URL, standard: 'CDP Online Response System \u2014 annual July disclosure deadline', critical_note: 'CDP disclosure API \u2014 downtime during submission window = D-grade or non-disclosure; enterprise customers track CDP scores for supply chain qualification'}}\n];"
}
},
{
"id": "3",
"name": "HTTP: Health Check Each",
"type": "n8n-nodes-base.httpRequest",
"position": [
680,
300
],
"parameters": {
"method": "GET",
"url": "={{ $json.url }}/health",
"options": {
"timeout": 10000,
"response": {
"response": {
"neverError": true
}
}
}
}
},
{
"id": "4",
"name": "Code: Classify Status",
"type": "n8n-nodes-base.code",
"position": [
900,
300
],
"parameters": {
"jsCode": "const d = $input.first().json;\nconst status = d.$response?.statusCode || 0;\nconst ms = d.$response?.headers?.['x-response-time'] || 0;\nconst name = d.name;\nconst note = d.critical_note;\n\nlet level = 'OK';\nif (status === 0 || status >= 500) level = 'DOWN';\nelse if (status >= 400) level = 'DEGRADED';\nelse if (parseInt(ms) > 3000) level = 'SLOW';\n\nreturn [{json: {...d, http_status: status, response_ms: ms, level, critical_note: note}}];"
}
},
{
"id": "5",
"name": "IF: Not OK",
"type": "n8n-nodes-base.if",
"position": [
1120,
300
],
"parameters": {
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.level }}",
"operator": {
"type": "string",
"operation": "notEquals"
},
"rightValue": "OK"
}
]
}
}
},
{
"id": "6",
"name": "Slack: #esg-platform-ops",
"type": "n8n-nodes-base.slack",
"position": [
1340,
200
],
"parameters": {
"channel": "#esg-platform-ops",
"text": "[{{ $json.level }}] {{ $json.name }} \u2014 HTTP {{ $json.http_status }} / {{ $json.response_ms }}ms. Standard: {{ $json.standard }}. Note: {{ $json.critical_note }}"
}
},
{
"id": "7",
"name": "Sheets: SLA Log",
"type": "n8n-nodes-base.googleSheets",
"position": [
1340,
380
],
"parameters": {
"operation": "append",
"sheetId": "={{ $env.SLA_LOG_SHEET_ID }}",
"columns": {
"mappingMode": "defineBelow",
"value": {
"endpoint": "={{ $json.name }}",
"level": "={{ $json.level }}",
"http_status": "={{ $json.http_status }}",
"response_ms": "={{ $json.response_ms }}",
"checked_at": "={{ new Date().toISOString() }}"
}
}
}
}
],
"connections": {
"Schedule: Every 15 min": {
"main": [
[
{
"node": "Code: Define Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Code: Define Endpoints": {
"main": [
[
{
"node": "HTTP: Health Check Each",
"type": "main",
"index": 0
}
]
]
},
"HTTP: Health Check Each": {
"main": [
[
{
"node": "Code: Classify Status",
"type": "main",
"index": 0
}
]
]
},
"Code: Classify Status": {
"main": [
[
{
"node": "IF: Not OK",
"type": "main",
"index": 0
}
]
]
},
"IF: Not OK": {
"main": [
[
{
"node": "Slack: #esg-platform-ops",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets: SLA Log",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: Regulatory Incident Response Pipeline
Webhook-triggered. Classifies 8 incident types with their mandatory response clocks. SEC climate disclosure investigation triggers IMMEDIATE response + legal hold notification. FTC greenwashing complaint (16 CFR Part 260) also IMMEDIATE. EU CSRD regulatory inquiry gives 10 business days. All critical incidents route to #esg-incidents-critical + CCO + Legal. Non-critical to #esg-incidents. All incidents logged to Google Sheets.
{
"name": "ESG SaaS \u2014 Regulatory Incident Response Pipeline",
"nodes": [
{
"id": "1",
"name": "Webhook: Incident Ingest",
"type": "n8n-nodes-base.webhook",
"position": [
240,
300
],
"parameters": {
"path": "esg-incident",
"responseMode": "lastNode"
}
},
{
"id": "2",
"name": "Code: Classify Incident",
"type": "n8n-nodes-base.code",
"position": [
460,
300
],
"parameters": {
"jsCode": "const d = $input.first().json;\nconst t = (d.incident_type || '').toUpperCase();\n\nconst clocks = {\n SEC_CLIMATE_DISCLOSURE_INVESTIGATION: {\n severity: 'CRITICAL', clock: 'IMMEDIATE',\n authority: 'SEC Division of Enforcement',\n action: 'Legal hold + preserve all Scope 1/2 calculation methodology records + notify General Counsel + engage securities counsel. SEC expects complete GHG calculation chain on production request.'\n },\n GREENWASHING_COMPLAINT_FTC: {\n severity: 'CRITICAL', clock: 'IMMEDIATE',\n authority: 'FTC Bureau of Consumer Protection \u2014 16 CFR Part 260',\n action: 'Review all marketing claims vs substantiation standard + engage FTC counsel + document carbon/sustainability claim basis'\n },\n EU_CSRD_REGULATORY_INQUIRY: {\n severity: 'CRITICAL', clock: '10 business days',\n authority: 'National competent authority + ESMA coordination',\n action: 'Produce ESRS E1 data lineage + EU Taxonomy alignment evidence + statutory assurance documentation'\n },\n EPA_GHGRP_DATA_DISCREPANCY: {\n severity: 'HIGH', clock: '30 days',\n authority: 'EPA Office of Atmospheric Programs 40 CFR \u00a798.3(h)',\n action: 'Audit Scope 1 facility-level data + prepare correction submission via e-GGRT'\n },\n ISO_14064_VERIFICATION_FAILURE: {\n severity: 'HIGH', clock: '60 days',\n authority: 'Accredited verification body (ISO 14065)',\n action: 'Address verification body findings + update GHG calculation methodology documentation'\n },\n GHG_CALCULATION_ERROR_MATERIAL: {\n severity: 'HIGH', clock: 'IMMEDIATE restatement analysis',\n authority: 'SEC \u00a7229.1502(d) materiality threshold',\n action: 'Quantify error magnitude + assess SEC materiality threshold + consult auditor + prepare restatement if material'\n },\n DATA_BREACH_ESG_METHODOLOGY: {\n severity: 'HIGH', clock: '72 hours',\n authority: 'DPA (GDPR Art.33) + SEC Reg S-P (if US customers)',\n action: 'Contain breach + notify DPA within 72h + assess SEC Reg S-P obligation + notify affected customers'\n },\n CDP_SCORE_DISPUTE: {\n severity: 'MEDIUM', clock: '30 days',\n authority: 'CDP Disclosure Insight Action',\n action: 'Submit supporting documentation via CDP Online Response System + engage CDP analyst'\n }\n};\n\nconst info = clocks[t] || {severity: 'MEDIUM', clock: '30 days', authority: 'Internal compliance team', action: 'Triage and escalate per ESG incident runbook'};\n\nreturn [{json: {...d, incident_type: t, ...info, created_at: new Date().toISOString()}}];"
}
},
{
"id": "3",
"name": "IF: Critical",
"type": "n8n-nodes-base.if",
"position": [
680,
300
],
"parameters": {
"conditions": {
"conditions": [
{
"leftValue": "={{ $json.severity }}",
"operator": {
"type": "string",
"operation": "equals"
},
"rightValue": "CRITICAL"
}
]
}
}
},
{
"id": "4",
"name": "Slack: #esg-incidents-critical",
"type": "n8n-nodes-base.slack",
"position": [
900,
200
],
"parameters": {
"channel": "#esg-incidents-critical",
"text": "[CRITICAL] {{ $json.incident_type }} \u2014 Clock: {{ $json.clock }}. Authority: {{ $json.authority }}. ACTION: {{ $json.action }}"
}
},
{
"id": "5",
"name": "Gmail: CCO + Legal",
"type": "n8n-nodes-base.gmail",
"position": [
900,
320
],
"parameters": {
"operation": "send",
"toList": "={{ $env.CCO_EMAIL }}",
"ccList": "={{ $env.LEGAL_EMAIL }}",
"subject": "[CRITICAL] ESG Incident: {{ $json.incident_type }} \u2014 Clock: {{ $json.clock }}",
"message": "Incident: {{ $json.incident_type }}\nSeverity: {{ $json.severity }}\nResponse clock: {{ $json.clock }}\nAuthority: {{ $json.authority }}\nRequired action: {{ $json.action }}\nCustomer: {{ $json.customer_name }}\nReported: {{ $json.created_at }}"
}
},
{
"id": "6",
"name": "Slack: #esg-incidents (non-critical)",
"type": "n8n-nodes-base.slack",
"position": [
900,
480
],
"parameters": {
"channel": "#esg-incidents",
"text": "[{{ $json.severity }}] {{ $json.incident_type }} \u2014 {{ $json.clock }} clock. Authority: {{ $json.authority }}. Action: {{ $json.action }}"
}
},
{
"id": "7",
"name": "Sheets: Incident Log",
"type": "n8n-nodes-base.googleSheets",
"position": [
1120,
300
],
"parameters": {
"operation": "append",
"sheetId": "={{ $env.INCIDENT_LOG_SHEET_ID }}",
"columns": {
"mappingMode": "defineBelow",
"value": {
"incident_type": "={{ $json.incident_type }}",
"severity": "={{ $json.severity }}",
"clock": "={{ $json.clock }}",
"authority": "={{ $json.authority }}",
"customer": "={{ $json.customer_name }}",
"created_at": "={{ $json.created_at }}"
}
}
}
},
{
"id": "8",
"name": "Respond: 200 OK",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
1340,
300
],
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({received: true, severity: $json.severity, clock: $json.clock}) }}"
}
}
],
"connections": {
"Webhook: Incident Ingest": {
"main": [
[
{
"node": "Code: Classify Incident",
"type": "main",
"index": 0
}
]
]
},
"Code: Classify Incident": {
"main": [
[
{
"node": "IF: Critical",
"type": "main",
"index": 0
}
]
]
},
"IF: Critical": {
"main": [
[
{
"node": "Slack: #esg-incidents-critical",
"type": "main",
"index": 0
},
{
"node": "Gmail: CCO + Legal",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack: #esg-incidents (non-critical)",
"type": "main",
"index": 0
}
]
]
},
"Gmail: CCO + Legal": {
"main": [
[
{
"node": "Sheets: Incident Log",
"type": "main",
"index": 0
}
]
]
},
"Slack: #esg-incidents (non-critical)": {
"main": [
[
{
"node": "Sheets: Incident Log",
"type": "main",
"index": 0
}
]
]
},
"Sheets: Incident Log": {
"main": [
[
{
"node": "Respond: 200 OK",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly ESG Platform KPI Report
Fires Monday 07:30 UTC. Queries Postgres for active customers by tier, MRR with WoW percentage change (via $getWorkflowStaticData), SEC Climate Disclosure subject count, EU CSRD in-scope count, EPA GHGRP reporter count, critical incidents in 7 days, critical deadlines in 14 days, average Scope 1 tCO2e tracked, and total Scope 3 suppliers monitored. Sends HTML report to CEO + CSO + Slack #esg-go-to-market.
{
"name": "ESG SaaS \u2014 Weekly ESG Platform KPI Report",
"nodes": [
{
"id": "1",
"name": "Schedule: Monday 07:30 UTC",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "30 7 * * 1"
}
]
}
}
},
{
"id": "2",
"name": "Postgres: Weekly ESG Metrics",
"type": "n8n-nodes-base.postgres",
"position": [
460,
300
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT\n COUNT(DISTINCT c.id) FILTER (WHERE c.status='active') as active_customers,\n COUNT(DISTINCT c.id) FILTER (WHERE c.created_at >= NOW()-INTERVAL '7 days') as new_this_week,\n SUM(s.mrr_usd) as total_mrr,\n COUNT(DISTINCT c.id) FILTER (WHERE c.tier='ENTERPRISE_ESG_PLATFORM') as enterprise_count,\n COUNT(DISTINCT c.id) FILTER (WHERE c.flags LIKE '%SEC_CLIMATE_DISCLOSURE_SUBJECT%') as sec_subject_count,\n COUNT(DISTINCT c.id) FILTER (WHERE c.flags LIKE '%EU_CSRD_IN_SCOPE%') as csrd_count,\n COUNT(DISTINCT c.id) FILTER (WHERE c.flags LIKE '%EPA_GHGRP_REPORTER%') as ghgrp_count,\n COUNT(i.id) FILTER (WHERE i.severity='CRITICAL' AND i.created_at >= NOW()-INTERVAL '7 days') as critical_incidents_7d,\n COUNT(d.id) FILTER (WHERE d.urgency='CRITICAL' AND d.deadline_date <= NOW()+INTERVAL '14 days') as critical_deadlines_14d,\n AVG(s.scope1_tco2e_tracked) as avg_scope1_tracked,\n SUM(s.scope3_suppliers_monitored) as total_scope3_suppliers\nFROM customers c\nLEFT JOIN subscriptions s ON s.customer_id = c.id\nLEFT JOIN incidents i ON i.customer_id = c.id\nLEFT JOIN deadlines d ON d.customer_id = c.id\nWHERE c.created_at >= '2020-01-01'"
}
},
{
"id": "3",
"name": "Code: Build KPI Report",
"type": "n8n-nodes-base.code",
"position": [
680,
300
],
"parameters": {
"jsCode": "const d = $input.first().json;\nconst snap = $getWorkflowStaticData('global');\nconst prevMrr = snap.prev_mrr || d.total_mrr;\nconst mrrWow = prevMrr > 0 ? (((d.total_mrr - prevMrr) / prevMrr) * 100).toFixed(1) : '0.0';\nsnap.prev_mrr = d.total_mrr;\n\nconst html = `\n<h2>FlowKit \u2014 ESG SaaS Weekly KPI Report</h2>\n<p><strong>Week ending: ${new Date().toISOString().split('T')[0]}</strong></p>\n<table border=\"1\" cellpadding=\"6\" style=\"border-collapse:collapse;\">\n <tr><th>Metric</th><th>Value</th><th>Notes</th></tr>\n <tr><td>Active Customers</td><td>${d.active_customers}</td><td></td></tr>\n <tr><td>New This Week</td><td>${d.new_this_week}</td><td></td></tr>\n <tr><td>Total MRR</td><td>$${Number(d.total_mrr).toLocaleString()}</td><td>WoW: ${mrrWow}%</td></tr>\n <tr><td>Enterprise ESG Platform</td><td>${d.enterprise_count}</td><td></td></tr>\n <tr><td>SEC Climate Disclosure Subjects</td><td>${d.sec_subject_count}</td><td>17 CFR \u00a7229.1500 in scope</td></tr>\n <tr><td>EU CSRD In-Scope</td><td>${d.csrd_count}</td><td>ESRS E1 disclosure required</td></tr>\n <tr><td>EPA GHGRP Reporters</td><td>${d.ghgrp_count}</td><td>40 CFR Part 98 filers</td></tr>\n <tr><td>Critical Incidents (7d)</td><td>${d.critical_incidents_7d}</td><td>${d.critical_incidents_7d > 0 ? '\u26a0 Review required' : 'Clean'}</td></tr>\n <tr><td>Critical Deadlines (14d)</td><td>${d.critical_deadlines_14d}</td><td>${d.critical_deadlines_14d > 0 ? '\u26a0 Immediate action' : 'Clear'}</td></tr>\n <tr><td>Avg Scope 1 Tracked (tCO2e)</td><td>${Number(d.avg_scope1_tracked).toLocaleString()}</td><td>GHG Protocol Scope 1</td></tr>\n <tr><td>Total Scope 3 Suppliers Monitored</td><td>${Number(d.total_scope3_suppliers).toLocaleString()}</td><td>CSRD value chain</td></tr>\n</table>\n<p><em>FlowKit ESG Platform \u2014 n8n automation templates: <a href=\"https://stripeai.gumroad.com\">stripeai.gumroad.com</a></em></p>`;\n\nreturn [{json: {...d, html_report: html, mrr_wow: mrrWow}}];"
}
},
{
"id": "4",
"name": "Gmail: Weekly Report to CEO + CSO",
"type": "n8n-nodes-base.gmail",
"position": [
900,
300
],
"parameters": {
"operation": "send",
"toList": "={{ $env.CEO_EMAIL }}",
"ccList": "={{ $env.CSO_EMAIL }}",
"subject": "FlowKit ESG Weekly KPI \u2014 {{ new Date().toISOString().split('T')[0] }}",
"message": "={{ $json.html_report }}",
"options": {
"isBodyHtml": true
}
}
},
{
"id": "5",
"name": "Slack: #esg-go-to-market",
"type": "n8n-nodes-base.slack",
"position": [
900,
440
],
"parameters": {
"channel": "#esg-go-to-market",
"text": "Weekly ESG KPI: {{ $json.active_customers }} customers, MRR ${{ $json.total_mrr }} (WoW {{ $json.mrr_wow }}%). SEC subjects: {{ $json.sec_subject_count }}, CSRD: {{ $json.csrd_count }}. Critical incidents 7d: {{ $json.critical_incidents_7d }}."
}
}
],
"connections": {
"Schedule: Monday 07:30 UTC": {
"main": [
[
{
"node": "Postgres: Weekly ESG Metrics",
"type": "main",
"index": 0
}
]
]
},
"Postgres: Weekly ESG Metrics": {
"main": [
[
{
"node": "Code: Build KPI Report",
"type": "main",
"index": 0
}
]
]
},
"Code: Build KPI Report": {
"main": [
[
{
"node": "Gmail: Weekly Report to CEO + CSO",
"type": "main",
"index": 0
},
{
"node": "Slack: #esg-go-to-market",
"type": "main",
"index": 0
}
]
]
}
}
}
Why Self-Hosted n8n Is the Right Architecture for ESG SaaS
| Requirement | Cloud iPaaS (Zapier/Make) | Self-Hosted n8n |
|---|---|---|
| SEC examination — GHG calculation chain production | ❌ Third-party cooperation required | ✅ Complete audit trail in your environment |
| EU CSRD ESRS E1 — auditor data lineage verification | ❌ Auditor cannot access Zapier node logs | ✅ Full transformation history in your Postgres |
| ISO 14064-3 independent verification | ❌ Cloud iPaaS breaks verification boundary | ✅ Verification body accesses self-hosted system |
| EPA GHGRP e-GGRT submission deadline | ❌ Vendor outage = your missed deadline | ✅ Self-hosted — you control the SLA |
| FTC Green Guides — claim substantiation | ❌ Methodology in third-party cloud = discoverable | ✅ ESG methodology stays inside legal privilege boundary |
| GDPR Art.28 + Reg S-P — ESG data processor | ❌ Cloud vendor = uncontrolled sub-processor | ✅ Self-hosted VPC = processor boundary stays internal |
The SEC's climate disclosure rule creates a new category of enforcement risk for ESG software vendors: your Scope 1/2 calculation methodology is now evidence in securities investigations. The calculation engine that processes your customers' emissions data is no longer just software — it is a legal artifact.
Get the full workflow pack at stripeai.gumroad.com.
Questions? Drop a comment or reply to this post. I answer everything.
Top comments (0)