DEV Community

Alex Kane
Alex Kane

Posted on

n8n for WealthTech & Investment SaaS Vendors: 5 Automations for SEC Rule 17a-4, Reg BI, FINRA Rule 4370, and Form ADV Compliance

If you're building WealthTech or investment management SaaS, your customers' trade records, client recommendations, and portfolio data carry serious regulatory weight.
SEC Rule 17a-4, Reg BI, FINRA Rule 4370, and Form ADV requirements aren't just compliance checkboxes — they're examination gates.
When the SEC requests records, they expect production from your systems — not a subpoena detour through your cloud automation vendor.

This guide covers 5 import-ready n8n workflows for WealthTech SaaS vendors, with full JSON.
Each maps to a real compliance obligation your customers are already managing.

Why WealthTech SaaS Vendors Are Moving Automation Off Cloud iPaaS

The core issue is SEC Rule 17a-4(f) — WORM electronic record storage.

Rule 17a-4(f) requires that electronically stored records be non-rewriteable, non-erasable, and immediately accessible.
Cloud iPaaS (Zapier, Make) processes and logs workflow data on their infrastructure.
When your automation routes trade records through cloud iPaaS:

  • iPaaS execution logs contain trade record data
  • That data is stored outside your WORM-compliant systems
  • SEC examination request = record production gap
  • Examination finding = potential enforcement action

The second issue is Reg BI — Best Interest obligation.
Reg BI §240.15l-1 requires broker-dealers to act in the customer's best interest at the time of a recommendation.
Automated recommendation pipelines routing client data through cloud iPaaS = third-party data handler outside your supervision boundary.
The supervision obligation doesn't stop at your network perimeter.

This is an architecture decision, not a security incident.
Self-hosted n8n eliminates both exposures by keeping automation inside your infrastructure boundary.

SEC Rule 17a-4 WORM analysis — the 5 tiers most at risk:

Tier Primary Regulation Fastest Clock Record Exposure
Enterprise Wealth Mgmt SEC 17a-4 + Reg BI IMMEDIATE SEC exam Trade + recommendation records
Broker-Dealer SaaS SEC 17a-3/17a-4 WORM IMMEDIATE SEC exam Order and trade records
RIA SaaS Vendor Advisers Act §204 + Reg BI IMMEDIATE SEC exam Client recommendation data
Robo-Advisor Platform Reg BI §240.15l-1 IMMEDIATE SEC exam Algorithm input/output records
Crypto Trading SaaS CFTC Dodd-Frank §731 Same-day CFTC reporting Swap confirmation data

The 7 Customer Tiers

{
  "customer_tiers": [
    {
      "tier": "ENTERPRISE_WEALTH_MGMT_PLATFORM",
      "compliance_flags": [
        "SEC_17A4_WORM_SUBJECT",
        "RIA_REGISTERED_ADVISER",
        "FINRA_MEMBER_FIRM",
        "REG_BI_SUBJECT",
        "SOC2_REQUIRED"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE"
    },
    {
      "tier": "RIA_SAAS_VENDOR",
      "compliance_flags": [
        "RIA_REGISTERED_ADVISER",
        "REG_BI_SUBJECT"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE"
    },
    {
      "tier": "BROKER_DEALER_SAAS",
      "compliance_flags": [
        "SEC_17A4_WORM_SUBJECT",
        "FINRA_MEMBER_FIRM",
        "REG_BI_SUBJECT"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE"
    },
    {
      "tier": "CRYPTO_TRADING_SAAS",
      "compliance_flags": [
        "CFTC_SWAP_DEALER"
      ],
      "fastest_clock": "CFTC_SWAP_DATA_REPORTING same-day"
    },
    {
      "tier": "ROBO_ADVISOR_PLATFORM",
      "compliance_flags": [
        "RIA_REGISTERED_ADVISER",
        "REG_BI_SUBJECT"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE \u2014 algorithm audit trail"
    },
    {
      "tier": "ALTERNATIVE_INVESTMENT_SAAS",
      "compliance_flags": [
        "RIA_REGISTERED_ADVISER",
        "SEC_FORM_PF_FILER"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE"
    },
    {
      "tier": "WEALTHTECH_STARTUP",
      "compliance_flags": [
        "RIA_REGISTERED_ADVISER"
      ],
      "fastest_clock": "SEC_EXAMINATION_REQUEST IMMEDIATE"
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Workflow 1 — Tier-Segmented Customer Onboarding Drip

Classifies new trials by tier and compliance flags. Sends Day 0 welcome with compliance-specific note, Day 3 feature email, Day 7 trial-end sequence.
The Day 0 note for BROKER_DEALER_SAAS includes the SEC Rule 17a-4(f) WORM storage analysis.
The Day 0 note for ROBO_ADVISOR_PLATFORM includes the Reg BI supervision boundary analysis.

{
  "name": "WealthTech SaaS \u2014 Tier-Segmented Customer Onboarding Drip",
  "nodes": [
    {
      "id": "1",
      "name": "Webhook \u2014 trial_started",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "path": "wealthtech-trial-started",
        "responseMode": "onReceived"
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "2",
      "name": "Code \u2014 Tier + Flag Classifier",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "\nconst d = $input.first().json;\nconst plan = (d.plan || '').toLowerCase();\nconst userCount = d.user_count || 0;\nconst product = (d.product_type || '').toLowerCase();\nconst aum = d.aum_under_management || 0;\n\n// Tier classification\nlet tier = 'WEALTHTECH_STARTUP';\nif (product.includes('broker') || product.includes('bd')) tier = 'BROKER_DEALER_SAAS';\nelse if (product.includes('ria') || product.includes('adviser') || product.includes('advisor')) tier = 'RIA_SAAS_VENDOR';\nelse if (product.includes('crypto') || product.includes('digital_asset')) tier = 'CRYPTO_TRADING_SAAS';\nelse if (product.includes('robo') || product.includes('automated_advice')) tier = 'ROBO_ADVISOR_PLATFORM';\nelse if (product.includes('hedge') || product.includes('alt') || product.includes('private_equity')) tier = 'ALTERNATIVE_INVESTMENT_SAAS';\nelse if (userCount >= 1000 || aum >= 1000000000 || plan === 'enterprise') tier = 'ENTERPRISE_WEALTH_MGMT_PLATFORM';\n\n// Compliance flags\nconst flags = [];\nif (tier === 'BROKER_DEALER_SAAS') { flags.push('SEC_17A4_WORM_SUBJECT'); flags.push('FINRA_MEMBER_FIRM'); flags.push('REG_BI_SUBJECT'); }\nif (tier === 'RIA_SAAS_VENDOR') { flags.push('RIA_REGISTERED_ADVISER'); flags.push('REG_BI_SUBJECT'); }\nif (tier === 'ROBO_ADVISOR_PLATFORM') { flags.push('RIA_REGISTERED_ADVISER'); flags.push('REG_BI_SUBJECT'); }\nif (tier === 'CRYPTO_TRADING_SAAS') { flags.push('CFTC_SWAP_DEALER'); }\nif (tier === 'ALTERNATIVE_INVESTMENT_SAAS') { flags.push('RIA_REGISTERED_ADVISER'); flags.push('SEC_FORM_PF_FILER'); }\nif (tier === 'ENTERPRISE_WEALTH_MGMT_PLATFORM') { flags.push('SEC_17A4_WORM_SUBJECT'); flags.push('RIA_REGISTERED_ADVISER'); flags.push('FINRA_MEMBER_FIRM'); flags.push('REG_BI_SUBJECT'); }\nif (userCount >= 250 || tier === 'ENTERPRISE_WEALTH_MGMT_PLATFORM') flags.push('SOC2_REQUIRED');\n\n// Tier-specific Day 0 note\nconst day0Notes = {\n  ENTERPRISE_WEALTH_MGMT_PLATFORM: 'SEC Rule 17a-4 WORM: cloud iPaaS routing order and trade records = electronic record storage outside your SEC-compliant system = examination finding risk. Reg BI: automation routing client recommendation data through cloud iPaaS = third-party data handler outside supervision boundary.',\n  RIA_SAAS_VENDOR: 'SEC Advisers Act \u00a7204 recordkeeping: adviser client records in cloud iPaaS = third-party storage without explicit SEC books and records authority. Form ADV Part 2 disclosure obligation: cloud automation vendor relationship may require disclosure.',\n  BROKER_DEALER_SAAS: 'SEC Rule 17a-4(f) WORM: electronically stored records must be non-rewriteable and non-erasable. Cloud iPaaS that processes trade records does not meet WORM standard. FINRA Rule 4370: BCP must account for third-party technology dependencies.',\n  CRYPTO_TRADING_SAAS: 'CFTC Dodd-Frank \u00a7731: swap data reporting obligations require audit-grade recordkeeping. Cloud iPaaS routing swap confirmation data = reportable transaction records outside CFTC-compliant boundary.',\n  ROBO_ADVISOR_PLATFORM: 'Reg BI \u00a717 CFR \u00a7240.15l-1: automated investment advice = recommendation subject to Best Interest obligation. Cloud iPaaS routing algorithm inputs and outputs = supervision gap outside your control boundary.',\n  ALTERNATIVE_INVESTMENT_SAAS: 'SEC Form PF: quarterly systemic risk reporting for hedge funds and private equity. Fund data routing through cloud iPaaS = third-party data processor requiring Form ADV Part 2 disclosure + SEC examination exposure.',\n  WEALTHTECH_STARTUP: 'SEC examination readiness: cloud iPaaS creates record production gaps. When the SEC requests records, you produce from your systems \u2014 not from your cloud automation vendor. Self-hosted n8n keeps all workflow data inside your perimeter.'\n};\n\nreturn [{json: {\n  ...d,\n  tier,\n  flags,\n  day0_compliance_note: day0Notes[tier] || day0Notes.WEALTHTECH_STARTUP\n}}];\n"
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "3",
      "name": "Sheets \u2014 Log Trial",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "trials",
        "dataMode": "autoMapInputData"
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "4",
      "name": "Gmail \u2014 Day 0 Welcome",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "={{ $json.email }}",
        "subject": "Welcome to {{ $json.product_name }} \u2014 your compliance automation setup guide",
        "emailType": "html",
        "message": "={{ '<p>Hi ' + $json.first_name + ',</p><p>You are now on the ' + $json.plan + ' trial.</p><p><strong>Compliance Note:</strong> ' + $json.day0_compliance_note + '</p><p>Your onboarding checklist is ready. Reply to this email with any questions.</p>' }}"
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "5",
      "name": "Wait \u2014 3 days",
      "type": "n8n-nodes-base.wait",
      "parameters": {
        "amount": 3,
        "unit": "days"
      },
      "position": [
        1000,
        0
      ]
    },
    {
      "id": "6",
      "name": "Gmail \u2014 Day 3 Feature",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "={{ $json.email }}",
        "subject": "The automation your {{ $json.tier.replace(/_/g, ' ').toLowerCase() }} customers ask about most",
        "emailType": "html",
        "message": "<p>Based on what similar vendors are automating: SEC/FINRA deadline tracking, API health monitoring for trading systems, and incident response pipelines. All run inside your infrastructure \u2014 no trade records or client data egressing to third-party servers.</p>"
      },
      "position": [
        1250,
        0
      ]
    },
    {
      "id": "7",
      "name": "Wait \u2014 4 days",
      "type": "n8n-nodes-base.wait",
      "parameters": {
        "amount": 4,
        "unit": "days"
      },
      "position": [
        1500,
        0
      ]
    },
    {
      "id": "8",
      "name": "Gmail \u2014 Day 7 Trial End",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "={{ $json.email }}",
        "subject": "Your trial ends in 48 hours \u2014 3 things to do before then",
        "emailType": "html",
        "message": "<p>Export your workflow JSON, schedule a 15-min call with our team, and review the SEC Rule 17a-4 / Reg BI self-hosting checklist we prepared for your tier.</p>"
      },
      "position": [
        1750,
        0
      ]
    }
  ],
  "connections": {
    "Webhook \u2014 trial_started": {
      "main": [
        [
          {
            "node": "Code \u2014 Tier + Flag Classifier",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Tier + Flag Classifier": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Log Trial",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets \u2014 Log Trial": {
      "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 Feature",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 Day 3 Feature": {
      "main": [
        [
          {
            "node": "Wait \u2014 4 days",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait \u2014 4 days": {
      "main": [
        [
          {
            "node": "Gmail \u2014 Day 7 Trial End",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 2 — SEC / FINRA / CFTC / OCC Compliance Deadline Tracker

Reads a Google Sheet of compliance deadlines daily. Classifies as OVERDUE / CRITICAL / URGENT / WARNING / NOTICE. Routes critical items to Slack #compliance-urgent and emails the owner.

12 deadline types covered:

Deadline Type Statute Window
SEC_EXAMINATION_REQUEST SEC Rule 17a-4 IMMEDIATE — record production required
SEC_FORM_ADV_ANNUAL_UPDATE Advisers Act §203 Annual — within 90d of fiscal year end
SEC_FORM_PF_QUARTERLY Dodd-Frank §404 45d after quarter end (15d for large advisers)
FINRA_4370_BCP_ANNUAL_REVIEW FINRA Rule 4370 Annual
FINRA_INQUIRY_RESPONSE FINRA Rule 8210 10-15 business days standard
REG_BI_BEST_INTEREST_ANNUAL_REVIEW 17 CFR §240.15l-1 Annual
SEC_17A4_RECORDS_EXAMINATION 17 CFR §240.17a-4(f) IMMEDIATE upon exam
CFTC_SWAP_DATA_REPORTING Dodd-Frank §731 Same-day for new swaps
MSRB_RULE_G36_DISCLOSURE MSRB Rule G-36 Within 1 business day
OCC_SUPERVISORY_RESPONSE OCC 12 CFR §30 IMMEDIATE upon notice
SOC2_TYPE2_RENEWAL Annual
ANNUAL_PENTEST Annual
{
  "name": "WealthTech SaaS \u2014 SEC/FINRA/CFTC/OCC Compliance Deadline Tracker",
  "nodes": [
    {
      "id": "1",
      "name": "Schedule \u2014 Daily 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * *"
            }
          ]
        }
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "2",
      "name": "Sheets \u2014 Read Deadlines",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "read",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "compliance_deadlines"
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "3",
      "name": "Code \u2014 Urgency Classifier",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "\nconst today = new Date();\nconst urgent = [];\nfor (const row of $input.all()) {\n  const d = row.json;\n  const due = new Date(d.due_date);\n  const days = Math.ceil((due - today) / 86400000);\n  // 12 WealthTech deadline types\n  const deadlineTypes = [\n    'SEC_EXAMINATION_REQUEST',            // IMMEDIATE \u2014 record production required\n    'SEC_FORM_ADV_ANNUAL_UPDATE',         // Annual \u2014 within 90d of fiscal year end\n    'SEC_FORM_PF_QUARTERLY',              // 45d after quarter end (large advisers: 15d)\n    'FINRA_4370_BCP_ANNUAL_REVIEW',       // Annual\n    'FINRA_INQUIRY_RESPONSE',             // 10-15 business days standard\n    'REG_BI_BEST_INTEREST_ANNUAL_REVIEW', // Annual\n    'SEC_17A4_RECORDS_EXAMINATION',       // IMMEDIATE upon exam\n    'CFTC_SWAP_DATA_REPORTING',           // Same-day for new swaps\n    'MSRB_RULE_G36_DISCLOSURE',           // Within 1 business day\n    'OCC_SUPERVISORY_RESPONSE',           // IMMEDIATE upon notice\n    'SOC2_TYPE2_RENEWAL',                 // Annual\n    'ANNUAL_PENTEST'                      // Annual\n  ];\n  let urgency = 'UPCOMING';\n  if (days < 0) urgency = 'OVERDUE';\n  else if (days <= 3) urgency = 'CRITICAL';\n  else if (days <= 7) urgency = 'URGENT';\n  else if (days <= 14) urgency = 'WARNING';\n  else if (days <= 30) urgency = 'NOTICE';\n  if (days <= 30) urgent.push({...d, days_remaining: days, urgency});\n}\nreturn urgent.map(r => ({json: r}));\n"
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "4",
      "name": "IF \u2014 Critical or Overdue",
      "type": "n8n-nodes-base.if",
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": false
          },
          "conditions": [
            {
              "leftValue": "={{ $json.urgency }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "CRITICAL"
            },
            {
              "leftValue": "={{ $json.urgency }}",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "rightValue": "OVERDUE"
            }
          ],
          "combinator": "or"
        }
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "5",
      "name": "Slack \u2014 Critical Alert",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#compliance-urgent",
        "text": "={{ '\ud83d\udea8 ' + $json.urgency + ': ' + $json.deadline_type + ' \u2014 ' + $json.customer_name + ' \u2014 ' + $json.days_remaining + 'd remaining. Owner: ' + $json.owner }}"
      },
      "position": [
        1000,
        100
      ]
    },
    {
      "id": "6",
      "name": "Gmail \u2014 Owner Notice",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "={{ $json.owner_email }}",
        "subject": "={{ '[' + $json.urgency + '] ' + $json.deadline_type + ' \u2014 ' + $json.days_remaining + ' days' }}",
        "emailType": "html",
        "message": "={{ '<p><strong>' + $json.deadline_type + '</strong></p><p>Customer: ' + $json.customer_name + '</p><p>Due: ' + $json.due_date + ' (' + $json.days_remaining + ' days remaining)</p><p>Action required: ' + $json.action_required + '</p>' }}"
      },
      "position": [
        1000,
        -100
      ]
    },
    {
      "id": "7",
      "name": "Sheets \u2014 Log",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "deadline_audit"
      },
      "position": [
        1250,
        0
      ]
    }
  ],
  "connections": {
    "Schedule \u2014 Daily 8AM": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Read Deadlines",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets \u2014 Read Deadlines": {
      "main": [
        [
          {
            "node": "Code \u2014 Urgency Classifier",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Urgency Classifier": {
      "main": [
        [
          {
            "node": "IF \u2014 Critical or Overdue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 Critical or Overdue": {
      "main": [
        [
          {
            "node": "Slack \u2014 Critical Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Gmail \u2014 Owner Notice",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 Critical Alert": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 Owner Notice": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 3 — Trading & Compliance API Health Monitor

Checks order management, portfolio management, trade reporting, compliance screening, and client portal APIs every 15 minutes.
Each endpoint is mapped to its compliance context:

  • order_management_api → SEC Rule 17a-3/17a-4 — downtime = record creation gap = examination finding
  • trade_reporting_api → FINRA TRACE/MSRB RTRS — same-day reporting; downtime = late report
  • compliance_screening_api → OFAC SDN — trading without screening = regulatory violation
{
  "name": "WealthTech SaaS \u2014 Trading & Compliance API Health Monitor",
  "nodes": [
    {
      "id": "1",
      "name": "Schedule \u2014 Every 15min",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "*/15 * * * *"
            }
          ]
        }
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "2",
      "name": "Sheets \u2014 Endpoints",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "read",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "api_endpoints"
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "3",
      "name": "HTTP \u2014 Check Endpoint",
      "type": "n8n-nodes-base.httpRequest",
      "parameters": {
        "url": "={{ $json.endpoint_url }}",
        "method": "GET",
        "timeout": 10000,
        "continueOnFail": true
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "4",
      "name": "Code \u2014 Classify Health",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "\n// WealthTech API endpoints with SEC/FINRA compliance context:\n// order_management_api = SEC 17a-3/17a-4 order records \u2014 downtime = record creation gap\n// portfolio_mgmt_api = Reg BI \u00a7240.15l-1 \u2014 best interest obligation continues during outage\n// trade_reporting_api = FINRA TRACE/MSRB RTRS \u2014 late reporting = examination finding\n// compliance_screening_api = OFAC SDN screening \u2014 trading without screening = regulatory violation\n// client_portal_api = SEC Advisers Act \u00a7204 \u2014 client record access obligation\nconst item = $input.first().json;\nconst statusCode = item.statusCode || 0;\nconst endpoint = item.endpoint_name || 'unknown';\nconst complianceNote = {\n  order_management_api: 'SEC Rule 17a-3/17a-4 \u2014 order records must be created and retained. Downtime = record creation gap = examination finding.',\n  portfolio_mgmt_api: 'Reg BI \u00a7240.15l-1 \u2014 Best Interest obligation continues during API downtime. Recommendation pipeline break creates supervision gap.',\n  trade_reporting_api: 'FINRA TRACE/MSRB RTRS \u2014 same-day trade reporting required. Downtime = late reporting = examination finding.',\n  compliance_screening_api: 'OFAC SDN / FINRA OFAC \u2014 screening must occur before trade execution. API downtime = unsupported trading without sanctions screening.',\n  client_portal_api: 'SEC Advisers Act \u00a7204 \u2014 client access to account statements. Downtime creates access rights gap.'\n}[endpoint] || 'Financial services compliance dependency';\nconst healthy = statusCode >= 200 && statusCode < 300;\nreturn [{json: {endpoint, statusCode, healthy, complianceNote, checked_at: new Date().toISOString()}}];\n"
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "5",
      "name": "IF \u2014 Down",
      "type": "n8n-nodes-base.if",
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.healthy }}",
              "operator": {
                "type": "boolean",
                "operation": "false"
              }
            }
          ]
        }
      },
      "position": [
        1000,
        0
      ]
    },
    {
      "id": "6",
      "name": "Slack \u2014 API Down Alert",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#platform-ops",
        "text": "={{ '\ud83d\udd34 API DOWN: ' + $json.endpoint + ' (HTTP ' + $json.statusCode + ') \u2014 Compliance note: ' + $json.complianceNote }}"
      },
      "position": [
        1250,
        100
      ]
    },
    {
      "id": "7",
      "name": "Sheets \u2014 Health Log",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "api_health_log"
      },
      "position": [
        1250,
        -100
      ]
    }
  ],
  "connections": {
    "Schedule \u2014 Every 15min": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Endpoints",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets \u2014 Endpoints": {
      "main": [
        [
          {
            "node": "HTTP \u2014 Check Endpoint",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP \u2014 Check Endpoint": {
      "main": [
        [
          {
            "node": "Code \u2014 Classify Health",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Classify Health": {
      "main": [
        [
          {
            "node": "IF \u2014 Down",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "IF \u2014 Down": {
      "main": [
        [
          {
            "node": "Slack \u2014 API Down Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Sheets \u2014 Health Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 4 — Incident Pipeline

Webhook-triggered. Classifies 8 incident types. Routes to Slack and emails compliance lead.

SEC_EXAMINATION_REQUEST is the fastest clock — immediate record production required.
Cloud iPaaS routing trade records = records outside your direct-access perimeter = production delay = examination finding.

Incident Type Clock Statute
SEC_EXAMINATION_REQUEST IMMEDIATE SEC Rule 17a-4
FINRA_INVESTIGATION_NOTICE 10-15 business days FINRA Rule 8210
REG_BI_SUITABILITY_COMPLAINT IMMEDIATE 17 CFR §240.15l-1
SEC_17A4_RECORD_PRODUCTION IMMEDIATE upon request 17 CFR §240.17a-4(f)
CFTC_ENFORCEMENT_ACTION 30d to respond Dodd-Frank §731
DATA_BREACH_INVESTOR_PII 72h + SEC Reg S-P 17 CFR §248
SYSTEM_OUTAGE_TRADING SLA + FINRA 4370 BCP FINRA Rule 4370
OCC_SUPERVISORY_AGREEMENT IMMEDIATE OCC 12 CFR §30
{
  "name": "WealthTech SaaS \u2014 Incident Pipeline (SEC / FINRA / Reg BI / CFTC)",
  "nodes": [
    {
      "id": "1",
      "name": "Webhook \u2014 Incident",
      "type": "n8n-nodes-base.webhook",
      "parameters": {
        "path": "wealthtech-incident",
        "responseMode": "onReceived"
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "2",
      "name": "Code \u2014 Classify Incident",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "\nconst d = $input.first().json;\nconst type = d.incident_type || 'UNKNOWN';\n// 8 WealthTech incident types with response clocks:\nconst clocks = {\n  SEC_EXAMINATION_REQUEST: {\n    clock: 'IMMEDIATE',\n    note: 'SEC examination request requires immediate record production. Cloud iPaaS routing trade records = records outside your direct-access perimeter = production delay = examination finding. Self-hosted n8n = records stay in your infrastructure.',\n    actions: ['Preserve all workflow execution logs', 'Notify CCO and general counsel', 'Identify all record types requested', 'Engage securities counsel', 'Prepare document production from your systems']\n  },\n  FINRA_INVESTIGATION_NOTICE: {\n    clock: '10-15 business days standard',\n    note: 'FINRA Rule 8210 \u2014 information request. FINRA can demand records from member firms and associated persons. Third-party automation vendor records may require separate subpoena if hosted externally.',\n    actions: ['Notify CCO immediately', 'Identify all records within FINRA scope', 'Engage outside counsel', 'Respond within stated deadline', 'Document production completeness']\n  },\n  REG_BI_SUITABILITY_COMPLAINT: {\n    clock: 'IMMEDIATE',\n    note: 'Reg BI \u00a7240.15l-1 \u2014 Best Interest standard. Customer complaint triggers supervision review. Recommendation data routing through cloud iPaaS = data handler outside supervision boundary = gap in oversight obligation.',\n    actions: ['Pull recommendation audit trail', 'Review algorithm decision log', 'Notify compliance officer', 'Respond to customer within 3 business days', 'Document Best Interest analysis']\n  },\n  SEC_17A4_RECORD_PRODUCTION: {\n    clock: 'IMMEDIATE upon request',\n    note: 'SEC Rule 17a-4(f) \u2014 electronic records must be immediately accessible for 2 years, then accessible for 6 years. Cloud iPaaS trade data = records outside WORM-compliant storage = production failure risk.',\n    actions: ['Identify all 17a-4 record categories', 'Produce immediately accessible records (2yr)', 'Confirm WORM storage compliance', 'Notify CCO', 'Engage securities counsel']\n  },\n  CFTC_ENFORCEMENT_ACTION: {\n    clock: '30d to respond',\n    note: 'CFTC Dodd-Frank \u00a7731 swap dealer reporting. Enforcement action for failure to report swap data same-day. Cloud iPaaS routing swap confirmations = reportable data outside direct CFTC submission control.',\n    actions: ['Preserve all swap confirmation records', 'Audit CFTC SDR submission completeness', 'Engage CFTC-specialized counsel', 'Prepare response within 30d', 'Document remediation plan']\n  },\n  DATA_BREACH_INVESTOR_PII: {\n    clock: '72h state law + SEC notification',\n    note: 'State breach notification + SEC Reg S-P (17 CFR \u00a7248) \u2014 safeguards rule. Customer financial data breach requires state notification and SEC examination disclosure.',\n    actions: ['Engage breach counsel', 'Notify affected customers', 'File state notification within 72h', 'Prepare SEC examination response', 'Assess Reg S-P safeguards rule compliance']\n  },\n  SYSTEM_OUTAGE_TRADING: {\n    clock: 'SLA + regulatory reporting',\n    note: 'Platform SLA. FINRA Rule 4370 BCP: member firms must maintain business continuity. Extended outage may trigger FINRA notification obligation.',\n    actions: ['Activate BCP', 'Post status page update', 'Notify FINRA if outage exceeds BCP threshold', 'Track SEC 17a-4 record creation gaps', 'Document restoration timeline']\n  },\n  OCC_SUPERVISORY_AGREEMENT: {\n    clock: 'IMMEDIATE',\n    note: 'OCC safety and soundness \u2014 supervisory agreement or consent order. Technology dependencies including third-party automation vendors may be in scope for OCC examination.',\n    actions: ['Notify board and senior management', 'Engage OCC-specialized counsel', 'Document all third-party technology dependencies', 'Prepare corrective action plan', 'Identify cloud automation as TPSP per OCC guidance']\n  }\n};\nconst info = clocks[type] || clocks.SYSTEM_OUTAGE_TRADING;\nreturn [{json: {\n  ...d,\n  incident_type: type,\n  response_clock: info.clock,\n  compliance_note: info.note,\n  required_actions: info.actions,\n  logged_at: new Date().toISOString()\n}}];\n"
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "3",
      "name": "Sheets \u2014 Log Incident",
      "type": "n8n-nodes-base.googleSheets",
      "parameters": {
        "operation": "appendOrUpdate",
        "documentId": "YOUR_SHEET_ID",
        "sheetName": "incident_log"
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "4",
      "name": "Slack \u2014 Incident Alert",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#compliance-incident",
        "text": "={{ '\ud83d\udea8 WealthTech Incident: ' + $json.incident_type + ' | Clock: ' + $json.response_clock + ' | ' + $json.compliance_note }}"
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "5",
      "name": "Gmail \u2014 Compliance Lead",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "compliance@yourcompany.com",
        "subject": "={{ '[INCIDENT] ' + $json.incident_type + ' \u2014 ' + $json.response_clock + ' clock' }}",
        "emailType": "html",
        "message": "={{ '<p><strong>Incident Type:</strong> ' + $json.incident_type + '</p><p><strong>Clock:</strong> ' + $json.response_clock + '</p><p><strong>Note:</strong> ' + $json.compliance_note + '</p><p><strong>Actions:</strong> ' + $json.required_actions.join(', ') + '</p>' }}"
      },
      "position": [
        1000,
        0
      ]
    }
  ],
  "connections": {
    "Webhook \u2014 Incident": {
      "main": [
        [
          {
            "node": "Code \u2014 Classify Incident",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Classify Incident": {
      "main": [
        [
          {
            "node": "Sheets \u2014 Log Incident",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Sheets \u2014 Log Incident": {
      "main": [
        [
          {
            "node": "Slack \u2014 Incident Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack \u2014 Incident Alert": {
      "main": [
        [
          {
            "node": "Gmail \u2014 Compliance Lead",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 5 — Weekly WealthTech KPI Dashboard

Monday 8AM. Queries Postgres for account counts by tier, MRR, compliance flag distribution, and open incidents. Sends HTML report to CEO and one-liner to Slack.

{
  "name": "WealthTech SaaS \u2014 Weekly KPI Dashboard",
  "nodes": [
    {
      "id": "1",
      "name": "Schedule \u2014 Monday 8AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 8 * * 1"
            }
          ]
        }
      },
      "position": [
        0,
        0
      ]
    },
    {
      "id": "2",
      "name": "Postgres \u2014 KPI Query",
      "type": "n8n-nodes-base.postgres",
      "parameters": {
        "operation": "executeQuery",
        "query": "\nSELECT\n  COUNT(DISTINCT account_id) FILTER (WHERE tier = 'ENTERPRISE_WEALTH_MGMT_PLATFORM') AS enterprise_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE tier = 'RIA_SAAS_VENDOR') AS ria_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE tier = 'BROKER_DEALER_SAAS') AS broker_dealer_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE tier = 'CRYPTO_TRADING_SAAS') AS crypto_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE tier = 'ROBO_ADVISOR_PLATFORM') AS robo_advisor_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE status = 'trial') AS active_trials,\n  COUNT(DISTINCT account_id) FILTER (WHERE status = 'active') AS paying_accounts,\n  SUM(mrr) AS total_mrr,\n  AVG(mrr) AS avg_mrr,\n  COUNT(DISTINCT account_id) FILTER (WHERE flags @> ARRAY['SEC_17A4_WORM_SUBJECT']) AS sec_17a4_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE flags @> ARRAY['REG_BI_SUBJECT']) AS reg_bi_accounts,\n  COUNT(DISTINCT account_id) FILTER (WHERE flags @> ARRAY['FINRA_MEMBER_FIRM']) AS finra_member_accounts,\n  COUNT(*) FILTER (WHERE event_type = 'SEC_EXAMINATION_REQUEST' AND created_at >= NOW() - INTERVAL '7 days') AS sec_exam_requests_7d,\n  COUNT(*) FILTER (WHERE event_type = 'FINRA_INVESTIGATION_NOTICE' AND created_at >= NOW() - INTERVAL '7 days') AS finra_inquiries_7d,\n  COUNT(*) FILTER (WHERE event_type = 'REG_BI_SUITABILITY_COMPLAINT' AND created_at >= NOW() - INTERVAL '7 days') AS reg_bi_complaints_7d\nFROM accounts LEFT JOIN events USING (account_id)\n"
      },
      "position": [
        250,
        0
      ]
    },
    {
      "id": "3",
      "name": "Code \u2014 Format Report",
      "type": "n8n-nodes-base.code",
      "parameters": {
        "jsCode": "\nconst d = $input.first().json;\nconst html = `<h2>FlowKit WealthTech SaaS \u2014 Weekly KPI</h2>\n<table border='1' cellpadding='6'>\n<tr><th>Metric</th><th>Value</th></tr>\n<tr><td>Enterprise Accounts</td><td>${d.enterprise_accounts}</td></tr>\n<tr><td>RIA SaaS Accounts</td><td>${d.ria_accounts}</td></tr>\n<tr><td>Broker-Dealer SaaS Accounts</td><td>${d.broker_dealer_accounts}</td></tr>\n<tr><td>Crypto Trading SaaS Accounts</td><td>${d.crypto_accounts}</td></tr>\n<tr><td>Robo-Advisor Accounts</td><td>${d.robo_advisor_accounts}</td></tr>\n<tr><td>Active Trials</td><td>${d.active_trials}</td></tr>\n<tr><td>Paying Accounts</td><td>${d.paying_accounts}</td></tr>\n<tr><td>Total MRR</td><td>$${Number(d.total_mrr||0).toLocaleString()}</td></tr>\n<tr><td>Avg MRR</td><td>$${Number(d.avg_mrr||0).toFixed(0)}</td></tr>\n<tr><th colspan='2'>Compliance Coverage</th></tr>\n<tr><td>SEC Rule 17a-4 Subject Accounts</td><td>${d.sec_17a4_accounts}</td></tr>\n<tr><td>Reg BI Subject Accounts</td><td>${d.reg_bi_accounts}</td></tr>\n<tr><td>FINRA Member Firm Accounts</td><td>${d.finra_member_accounts}</td></tr>\n<tr><th colspan='2'>Incident Activity (7d)</th></tr>\n<tr><td>SEC Examination Requests</td><td>${d.sec_exam_requests_7d}</td></tr>\n<tr><td>FINRA Inquiries</td><td>${d.finra_inquiries_7d}</td></tr>\n<tr><td>Reg BI Complaints</td><td>${d.reg_bi_complaints_7d}</td></tr>\n</table>`;\nreturn [{json: {...d, html_report: html}}];\n"
      },
      "position": [
        500,
        0
      ]
    },
    {
      "id": "4",
      "name": "Gmail \u2014 KPI Report",
      "type": "n8n-nodes-base.gmail",
      "parameters": {
        "operation": "send",
        "toEmail": "ceo@yourcompany.com",
        "subject": "WealthTech SaaS Weekly KPI \u2014 {{ $now.format('YYYY-MM-DD') }}",
        "emailType": "html",
        "message": "={{ $json.html_report }}"
      },
      "position": [
        750,
        0
      ]
    },
    {
      "id": "5",
      "name": "Slack \u2014 One-liner",
      "type": "n8n-nodes-base.slack",
      "parameters": {
        "channel": "#go-to-market",
        "text": "={{ 'Weekly KPI: ' + $json.paying_accounts + ' paying / ' + $json.active_trials + ' trials / MRR $' + Number($json.total_mrr||0).toLocaleString() + ' | SEC17a4: ' + $json.sec_17a4_accounts + ' accts | RegBI: ' + $json.reg_bi_accounts + ' | FINRA: ' + $json.finra_member_accounts + ' | Incidents 7d: SEC=' + $json.sec_exam_requests_7d + ' FINRA=' + $json.finra_inquiries_7d + ' RegBI=' + $json.reg_bi_complaints_7d }}"
      },
      "position": [
        1000,
        0
      ]
    }
  ],
  "connections": {
    "Schedule \u2014 Monday 8AM": {
      "main": [
        [
          {
            "node": "Postgres \u2014 KPI Query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Postgres \u2014 KPI Query": {
      "main": [
        [
          {
            "node": "Code \u2014 Format Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code \u2014 Format Report": {
      "main": [
        [
          {
            "node": "Gmail \u2014 KPI Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail \u2014 KPI Report": {
      "main": [
        [
          {
            "node": "Slack \u2014 One-liner",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Why Self-Hosted n8n Wins the WealthTech Procurement Conversation

Factor Cloud iPaaS (Zapier/Make) Self-Hosted n8n
SEC Rule 17a-4 WORM iPaaS logs contain trade records outside WORM-compliant storage Trade workflow data stays inside your WORM-compliant perimeter
SEC examination production Records in cloud vendor systems = production detour or delay Immediate production from your systems
Reg BI supervision Algorithm I/O routing through cloud iPaaS = supervision gap Recommendation pipeline runs inside supervision boundary
FINRA Rule 4370 BCP Cloud iPaaS is TPSP requiring BCP dependency documentation Self-hosted n8n is part of your own BCP
CFTC swap reporting Swap data routing through cloud iPaaS = reportable data outside direct CFTC submission control Swap workflow data inside your audit boundary
Form ADV disclosure Cloud automation vendor = third-party relationship requiring ADV Part 2 disclosure Internal tool, no additional disclosure required
Cost at scale $299+/mo growing with task volume One Docker container, unlimited workflows

SEC Rule 17a-4 is a binary gate for broker-dealer and RIA procurement.
Cloud iPaaS fails the WORM standard by architecture. Self-hosted n8n passes it by architecture.


If you're building WealthTech SaaS and your automation stack routes trade records or client recommendation data through cloud iPaaS,
you're one SEC examination request away from a record production gap.

These workflows run on self-hosted n8n. Download the JSON, import, configure your Sheets IDs and API keys.

The complete FlowKit n8n Automation Template library (15 templates) is at stripeai.gumroad.com.

Top comments (0)