If you're building PropTech or real estate SaaS — mortgage LOS platforms, tenant screening tools, property management software, CRE analytics, or real estate investment platforms — you are sitting at the intersection of five separate federal compliance regimes: CFPB TRID, RESPA, FIRPTA, FinCEN BSA, and FCRA. Each carries its own reporting clocks, each has strict liability provisions, and each involves consumer financial data that regulators treat as highly sensitive.
The problem: most PropTech companies automate their operational workflows through cloud iPaaS tools like Zapier or Make. Those tools route nonpublic personal information (NPI) — loan applications, credit scores, SSNs, income data, foreign seller TINs — through third-party cloud servers. That creates a CFPB Regulation P service-provider exposure that many founders don't discover until their first compliance review.
This guide gives you 5 production-ready n8n workflows — all self-hosted, all free to import — that handle PropTech compliance automation without routing NPI outside your VPC.
Who This Is For — 7 Customer Tiers
| Tier | Definition | Key Compliance Flags |
|---|---|---|
ENTERPRISE_CRE_PLATFORM |
Large commercial RE data/analytics platform (ARR >= $500K) | SOC2_REQUIRED, RESPA_SECTION_8_SUBJECT |
RESIDENTIAL_BROKERAGE_SAAS |
MLS data platforms, agent CRM, brokerage management software | FAIR_HOUSING_SUBJECT, FCRA |
MORTGAGE_LENDING_OS_VENDOR |
Loan origination system (LOS), POS, mortgage point-of-sale SaaS | TRID_APPLICABLE, RESPA_SECTION_8_SUBJECT, SOC2_REQUIRED |
PROPERTY_MANAGEMENT_SAAS |
PM software, rent collection SaaS, landlord platforms | FCRA_CONSUMER_REPORTING_AGENCY, FAIR_HOUSING_SUBJECT |
REAL_ESTATE_INVESTMENT_SAAS |
RE investment analytics, REIT ops platforms, underwriting SaaS | FIRPTA_WITHHOLDING_AGENT, FINCEN_BSA_SUBJECT |
TENANT_SCREENING_SAAS |
Tenant background check, credit/criminal screening platforms | FCRA_CONSUMER_REPORTING_AGENCY, FAIR_HOUSING_SUBJECT |
PROPTECH_STARTUP |
Early-stage PropTech (<$100K ARR, pre-enterprise) | SOC2_REQUIRED (future) |
Compliance Flags
- TRID_APPLICABLE — mortgage origination platform subject to CFPB TILA-RESPA Integrated Disclosure Rule (12 CFR 1026.19)
- RESPA_SECTION_8_SUBJECT — settlement service provider subject to RESPA anti-kickback 12 USC 2607 and escrow requirements 12 USC 2609
- FIRPTA_WITHHOLDING_AGENT — platform processes foreign seller transactions where buyer/agent is withholding agent (26 USC 1445)
- FINCEN_BSA_SUBJECT — platform subject to FinCEN BSA for cash transaction reporting (31 CFR 1010.311) and SAR filing
- FCRA_CONSUMER_REPORTING_AGENCY — platform qualifies as CRA or uses consumer reports; adverse action notice requirements apply (15 USC 1681m)
- FAIR_HOUSING_SUBJECT — platform used in housing decisions subject to Fair Housing Act (42 USC 3604) and HUD enforcement
- SOC2_REQUIRED — enterprise procurement requires SOC 2 Type II for NPI/PII handling
Workflow 1: Tier-Segmented Customer Onboarding Drip
Triggers on every new customer row in Google Sheets. Classifies the customer into one of 7 tiers based on ARR and product type, injects compliance flags, and sends a 3-touch email drip (Day 0, Day 3, Day 7) with tier-specific content. Mortgage LOS vendors get TRID timing context immediately. FIRPTA platforms get withholding agent reminders on Day 7.
The Day 7 email surfaces the CFPB Regulation P self-hosting argument: NPI never leaves your VPC, eliminating the annual vendor assessment requirement under 16 CFR 313.
{
"name": "PropTech Tier-Segmented Onboarding Drip",
"nodes": [
{
"id": "1",
"name": "Google Sheets Trigger",
"type": "n8n-nodes-base.googleSheetsTrigger",
"typeVersion": 4,
"position": [
240,
300
],
"parameters": {
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "new_customers",
"mode": "name"
},
"event": "rowAdded"
}
},
{
"id": "2",
"name": "Classify Tier and Flags",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"jsCode": "const r=$input.first().json;const arr=parseFloat(r.annual_arr_usd||0);const product=(r.product_type||'').toLowerCase();let tier='PROPTECH_STARTUP';if(arr>=500000&&(product.includes('cre')||product.includes('commercial')))tier='ENTERPRISE_CRE_PLATFORM';else if(product.includes('brokerage')||product.includes('mls'))tier='RESIDENTIAL_BROKERAGE_SAAS';else if(product.includes('mortgage')||product.includes('los'))tier='MORTGAGE_LENDING_OS_VENDOR';else if(product.includes('prop_mgmt')||product.includes('pms'))tier='PROPERTY_MANAGEMENT_SAAS';else if(product.includes('invest')||product.includes('reit'))tier='REAL_ESTATE_INVESTMENT_SAAS';else if(product.includes('screen')||product.includes('tenant'))tier='TENANT_SCREENING_SAAS';const flags=[];if(tier==='MORTGAGE_LENDING_OS_VENDOR')flags.push('TRID_APPLICABLE');if(r.respa_subject==='true')flags.push('RESPA_SECTION_8_SUBJECT');if(tier==='REAL_ESTATE_INVESTMENT_SAAS')flags.push('FIRPTA_WITHHOLDING_AGENT');if(r.fincen_bsa==='true')flags.push('FINCEN_BSA_SUBJECT');if(tier==='TENANT_SCREENING_SAAS')flags.push('FCRA_CONSUMER_REPORTING_AGENCY');if(r.fair_housing==='true')flags.push('FAIR_HOUSING_SUBJECT');if(arr>=100000)flags.push('SOC2_REQUIRED');return [{json:{...r,tier,flags,complianceFlags:flags.join(',')}}];"
}
},
{
"id": "3",
"name": "Send Day 0 Welcome",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
680,
300
],
"parameters": {
"sendTo": "={{ $json.contact_email }}",
"subject": "Welcome to FlowKit - your n8n automation setup guide",
"message": "={{ 'Hi ' + $json.contact_name + ', welcome! Tier: ' + $json.tier + '. Compliance flags: ' + ($json.complianceFlags||'none') + '. NPI self-hosted: CFPB Reg P service-provider exposure eliminated. Guide: https://stripeai.gumroad.com' }}"
}
},
{
"id": "4",
"name": "Log to Sheets",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
900,
300
],
"parameters": {
"operation": "appendOrUpdate",
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "onboarding_log",
"mode": "name"
},
"columns": {
"mappingMode": "autoMapInputData"
}
}
},
{
"id": "5",
"name": "Slack CSM Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
900,
460
],
"parameters": {
"channel": "#customer-success",
"text": "={{ 'New PropTech customer: ' + $json.company_name + ' | Tier: ' + $json.tier + ' | ARR: $' + $json.annual_arr_usd + ' | Flags: ' + ($json.complianceFlags||'none') }}"
}
},
{
"id": "6",
"name": "Wait 3 Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
1120,
300
],
"parameters": {
"amount": 3,
"unit": "days"
}
},
{
"id": "7",
"name": "Day 3 Integration Tips",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1340,
300
],
"parameters": {
"sendTo": "={{ $json.contact_email }}",
"subject": "Your Week 1 n8n setup checklist",
"message": "={{ 'Hi ' + $json.contact_name + ', here are your top integrations for week 1. Tier: ' + $json.tier + '. Template bundle: https://stripeai.gumroad.com' }}"
}
},
{
"id": "8",
"name": "Wait 4 More Days",
"type": "n8n-nodes-base.wait",
"typeVersion": 1,
"position": [
1560,
300
],
"parameters": {
"amount": 4,
"unit": "days"
}
},
{
"id": "9",
"name": "Day 7 Compliance Guide",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1780,
300
],
"parameters": {
"sendTo": "={{ $json.contact_email }}",
"subject": "Your compliance automation checklist",
"message": "={{ 'Hi ' + $json.contact_name + ', week 1 complete! CFPB Reg P note: self-hosted n8n means NPI never leaves your VPC - no annual vendor assessment required under 16 CFR 313. Bundle: https://stripeai.gumroad.com' }}"
}
},
{
"id": "10",
"name": "Mark Complete",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
2000,
300
],
"parameters": {
"operation": "update",
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "onboarding_log",
"mode": "name"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"onboarding_status": "complete",
"completed_at": "={{ $now.toISO() }}"
}
}
}
}
],
"connections": {
"Google Sheets Trigger": {
"main": [
[
{
"node": "Classify Tier and Flags",
"type": "main",
"index": 0
}
]
]
},
"Classify Tier and Flags": {
"main": [
[
{
"node": "Send Day 0 Welcome",
"type": "main",
"index": 0
}
]
]
},
"Send Day 0 Welcome": {
"main": [
[
{
"node": "Log to Sheets",
"type": "main",
"index": 0
},
{
"node": "Slack CSM Alert",
"type": "main",
"index": 0
}
]
]
},
"Log to Sheets": {
"main": [
[
{
"node": "Wait 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 3 Days": {
"main": [
[
{
"node": "Day 3 Integration Tips",
"type": "main",
"index": 0
}
]
]
},
"Day 3 Integration Tips": {
"main": [
[
{
"node": "Wait 4 More Days",
"type": "main",
"index": 0
}
]
]
},
"Wait 4 More Days": {
"main": [
[
{
"node": "Day 7 Compliance Guide",
"type": "main",
"index": 0
}
]
]
},
"Day 7 Compliance Guide": {
"main": [
[
{
"node": "Mark Complete",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 2: CFPB/RESPA/FIRPTA/FinCEN Deadline Tracker
Runs every weekday at 7AM. Loads compliance deadlines from Google Sheets, classifies each by urgency (OVERDUE / CRITICAL <=3d / URGENT <=7d / WARNING <=21d), routes critical items to Slack with @here, and emails the responsible owner. The 12 deadline types this workflow monitors:
| Deadline Type | Regulation | Clock |
|---|---|---|
TRID_LOAN_ESTIMATE_3_BUSINESS_DAY |
12 CFR 1026.19(e)(1)(iii) | 3 biz days from application |
TRID_CLOSING_DISCLOSURE_3_BUSINESS_DAY |
12 CFR 1026.19(f)(1)(ii) | 3 biz days before consummation |
FINCEN_CTR_NEXT_BUSINESS_DAY |
31 CFR 1010.311 | FASTEST CLOCK — next biz day |
FIRPTA_WITHHOLDING_20_DAYS |
26 USC 1445, Rev. Proc. 2000-35 | 20 days after closing |
RESPA_ANNUAL_ESCROW_STATEMENT |
12 USC 2609(c) | 30 days after year end |
FCRA_ADVERSE_ACTION_5_BUSINESS_DAYS |
15 USC 1681m | 5 biz days from denial |
FAIR_HOUSING_HUD_COMPLAINT_RESPONSE |
24 CFR 103.204 | 10 days from complaint |
FINCEN_SAR_30_DAYS |
31 CFR 1020.320 | 30 days from detection |
CFPB_COMPLAINT_PORTAL_15_DAYS |
CFPB Supervision Manual | 15 days |
STATE_LICENSE_RENEWAL_ANNUAL |
Varies by state | Annual |
SOC2_TYPE2_RENEWAL |
SOC 2 CC6.1 | Annual |
ANNUAL_PENTEST |
GLBA Safeguards 16 CFR 314.4(f) | Annual |
{
"name": "PropTech CFPB RESPA FIRPTA FinCEN Deadline Tracker",
"nodes": [
{
"id": "1",
"name": "Daily 7AM Weekdays",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * 1-5"
}
]
}
}
},
{
"id": "2",
"name": "Load Compliance Deadlines",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
460,
300
],
"parameters": {
"operation": "readAllRows",
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "compliance_deadlines",
"mode": "name"
}
}
},
{
"id": "3",
"name": "Classify Urgency",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
],
"parameters": {
"jsCode": "const now=new Date();const items=$input.all();const actionMap={TRID_LOAN_ESTIMATE_3_BUSINESS_DAY:'Deliver LE within 3 biz days of application - 12 CFR 1026.19(e)(1)(iii). Miss = strict CFPB liability.',TRID_CLOSING_DISCLOSURE_3_BUSINESS_DAY:'Deliver CD 3 biz days before consummation - 12 CFR 1026.19(f)(1)(ii).',FINCEN_CTR_NEXT_BUSINESS_DAY:'File CTR for cash >$10K by next biz day - 31 CFR 1010.311. FASTEST CLOCK.',FIRPTA_WITHHOLDING_20_DAYS:'Remit FIRPTA withholding within 20 days of closing - 26 USC 1445.',RESPA_ANNUAL_ESCROW_STATEMENT:'Annual escrow statement within 30 days of year end - 12 USC 2609(c).',FCRA_ADVERSE_ACTION_5_BUSINESS_DAYS:'Adverse action notice within 5 biz days - 15 USC 1681m.',FAIR_HOUSING_HUD_COMPLAINT_RESPONSE:'HUD complaint response within 10 days - 24 CFR 103.204.',FINCEN_SAR_30_DAYS:'SAR within 30 days of detection - 31 CFR 1020.320.',CFPB_COMPLAINT_PORTAL_15_DAYS:'CFPB portal response within 15 days.',STATE_LICENSE_RENEWAL_ANNUAL:'Annual state RE/mortgage license renewal.',SOC2_TYPE2_RENEWAL:'Annual SOC 2 Type II renewal.',ANNUAL_PENTEST:'Annual pentest per GLBA Safeguards 16 CFR 314.4(f).'};const results=[];for(const item of items){const d=item.json;const due=new Date(d.due_date);const daysLeft=Math.floor((due-now)/86400000);let urgency='OK';if(daysLeft<0)urgency='OVERDUE';else if(daysLeft<=3)urgency='CRITICAL';else if(daysLeft<=7)urgency='URGENT';else if(daysLeft<=21)urgency='WARNING';else if(daysLeft<=60)urgency='NOTICE';else continue;results.push({json:{...d,daysLeft,urgency,actionNote:actionMap[d.deadline_type]||''}});}return results;"
}
},
{
"id": "4",
"name": "Filter Active",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
900,
300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "OK",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
}
}
},
{
"id": "5",
"name": "Switch on Urgency",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
1120,
300
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "OVERDUE",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "CRITICAL",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 1
},
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "URGENT",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 2
},
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "WARNING",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 3
}
]
}
}
},
{
"id": "6",
"name": "Slack OVERDUE at-here",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1340,
100
],
"parameters": {
"channel": "#compliance-ops",
"text": "={{ '[OVERDUE] ' + $json.deadline_type + ' | ' + $json.customer_name + ' | ' + ($json.daysLeft*-1) + ' days past due | ' + $json.actionNote + ' @here' }}"
}
},
{
"id": "7",
"name": "Slack CRITICAL",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1340,
240
],
"parameters": {
"channel": "#compliance-ops",
"text": "={{ '[CRITICAL ' + $json.daysLeft + 'd] ' + $json.deadline_type + ' | ' + $json.customer_name + ' | ' + $json.actionNote }}"
}
},
{
"id": "8",
"name": "Slack URGENT",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1340,
380
],
"parameters": {
"channel": "#compliance-ops",
"text": "={{ '[URGENT ' + $json.daysLeft + 'd] ' + $json.deadline_type + ' | ' + $json.customer_name }}"
}
},
{
"id": "9",
"name": "Slack WARNING",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1340,
520
],
"parameters": {
"channel": "#compliance-watch",
"text": "={{ '[WARNING ' + $json.daysLeft + 'd] ' + $json.deadline_type + ' | ' + $json.customer_name }}"
}
},
{
"id": "10",
"name": "Email Owner",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1560,
170
],
"parameters": {
"sendTo": "={{ $json.owner_email }}",
"subject": "={{ '[' + $json.urgency + '] ' + $json.deadline_type + ' - ' + $json.customer_name }}",
"message": "={{ $json.urgency + ': ' + $json.deadline_type + ' | Due: ' + $json.due_date + ' (' + $json.daysLeft + 'd) | ' + $json.actionNote }}"
}
},
{
"id": "11",
"name": "Log Alerts",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
1780,
300
],
"parameters": {
"operation": "appendOrUpdate",
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "deadline_alerts_log",
"mode": "name"
},
"columns": {
"mappingMode": "autoMapInputData"
}
}
}
],
"connections": {
"Daily 7AM Weekdays": {
"main": [
[
{
"node": "Load Compliance Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Load Compliance Deadlines": {
"main": [
[
{
"node": "Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Classify Urgency": {
"main": [
[
{
"node": "Filter Active",
"type": "main",
"index": 0
}
]
]
},
"Filter Active": {
"main": [
[
{
"node": "Switch on Urgency",
"type": "main",
"index": 0
}
]
]
},
"Switch on Urgency": {
"main": [
[
{
"node": "Slack OVERDUE at-here",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack CRITICAL",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack URGENT",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack WARNING",
"type": "main",
"index": 0
}
]
]
},
"Slack OVERDUE at-here": {
"main": [
[
{
"node": "Email Owner",
"type": "main",
"index": 0
}
]
]
},
"Slack CRITICAL": {
"main": [
[
{
"node": "Email Owner",
"type": "main",
"index": 0
}
]
]
},
"Slack URGENT": {
"main": [
[
{
"node": "Log Alerts",
"type": "main",
"index": 0
}
]
]
},
"Slack WARNING": {
"main": [
[
{
"node": "Log Alerts",
"type": "main",
"index": 0
}
]
]
},
"Email Owner": {
"main": [
[
{
"node": "Log Alerts",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: PropTech API Health Monitor
Polls your API endpoints every 5 minutes: mortgage pricing APIs, MLS data feeds, title/escrow APIs, tenant screening bureau APIs, property valuation services. Classifies each as DOWN / ERROR / SLOW / OK. Deduplicates alerts within a 15-minute window using $getWorkflowStaticData to prevent Slack noise. Logs all non-OK events to Postgres with the regulation annotation.
Endpoint examples with regulation notes:
| Endpoint | Regulation Note |
|---|---|
mortgage_pricing_api |
TRID 1026.19 — LE pricing data accuracy |
mls_data_feed |
RESPA 8 — settlement service referral transparency |
tenant_screening_bureau_api |
FCRA 1681 — CRA data accuracy requirement |
title_escrow_api |
RESPA 2609 — escrow accounting accuracy |
property_valuation_api |
FIRPTA 1445 — FMV determination for withholding |
{
"name": "PropTech API Health Monitor",
"nodes": [
{
"id": "1",
"name": "Every 5 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "*/5 * * * *"
}
]
}
}
},
{
"id": "2",
"name": "Load API Endpoints",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
460,
300
],
"parameters": {
"operation": "readAllRows",
"documentId": {
"__rl": true,
"value": "YOUR_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "api_endpoints",
"mode": "name"
}
}
},
{
"id": "3",
"name": "HTTP Health Check",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4,
"position": [
680,
300
],
"parameters": {
"url": "={{ $json.health_url }}",
"method": "GET",
"timeout": 8000
}
},
{
"id": "4",
"name": "Classify Status",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
],
"parameters": {
"jsCode": "const item=$input.first().json;const statusCode=item.statusCode||0;const endpointName=$('Load API Endpoints').first().json.endpoint_name||'unknown';const regulation=$('Load API Endpoints').first().json.regulation_note||'';let status='OK';if(statusCode<200||statusCode>=500)status='DOWN';else if(statusCode>=400)status='ERROR';return [{json:{endpointName,statusCode,status,regulation,checkedAt:new Date().toISOString()}}];"
}
},
{
"id": "5",
"name": "Filter Non-OK",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
1120,
300
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.status }}",
"rightValue": "OK",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
],
"combinator": "and"
}
}
},
{
"id": "6",
"name": "Dedup 15min",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1340,
300
],
"parameters": {
"jsCode": "const state=$getWorkflowStaticData('global');if(!state.alerted)state.alerted={};const key=$json.endpointName+'_'+$json.status;const now=Date.now();if(state.alerted[key]&&(now-state.alerted[key])<900000)return [];state.alerted[key]=now;return [$input.first()];"
}
},
{
"id": "7",
"name": "Slack platform-ops",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1560,
300
],
"parameters": {
"channel": "#platform-ops",
"text": "={{ 'PropTech API ' + $json.status + ': ' + $json.endpointName + ' | HTTP ' + $json.statusCode + ' | Regulation: ' + $json.regulation }}"
}
},
{
"id": "8",
"name": "Log SLA Event",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1780,
300
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "proptech_api_sla_events",
"columns": "endpoint_name,status_code,status,regulation_note,checked_at",
"values": "={{ $json.endpointName }},={{ $json.statusCode }},={{ $json.status }},={{ $json.regulation }},={{ $json.checkedAt }}"
}
}
],
"connections": {
"Every 5 Minutes": {
"main": [
[
{
"node": "Load API Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Load API Endpoints": {
"main": [
[
{
"node": "HTTP Health Check",
"type": "main",
"index": 0
}
]
]
},
"HTTP Health Check": {
"main": [
[
{
"node": "Classify Status",
"type": "main",
"index": 0
}
]
]
},
"Classify Status": {
"main": [
[
{
"node": "Filter Non-OK",
"type": "main",
"index": 0
}
]
]
},
"Filter Non-OK": {
"main": [
[
{
"node": "Dedup 15min",
"type": "main",
"index": 0
}
]
]
},
"Dedup 15min": {
"main": [
[
{
"node": "Slack platform-ops",
"type": "main",
"index": 0
}
]
]
},
"Slack platform-ops": {
"main": [
[
{
"node": "Log SLA Event",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: CFPB/RESPA/FinCEN Incident Pipeline
Accepts webhook events from your platform, ACKs immediately (200), then classifies and routes by urgency. The 8 PropTech incident types:
| Incident Type | Urgency | Regulation | SLA Note |
|---|---|---|---|
TRID_DISCLOSURE_VIOLATION |
IMMEDIATE | CFPB 12 CFR 1026.19 | Strict liability — no cure period for missed 3-biz-day LE delivery |
RESPA_KICKBACK_ALLEGED |
IMMEDIATE | RESPA 12 USC 2607 | $10K civil + 1yr criminal per violation |
FINCEN_CTR_TRIGGER |
NEXT_BIZ_DAY | FinCEN 31 CFR 1010.311 | Cash >$10K by next biz day — FASTEST PROPTECH CLOCK |
FCRA_ADVERSE_ACTION_FAILURE |
IMMEDIATE | FCRA 15 USC 1681m | 5-biz-day clock starts at denial, per-violation strict liability |
FAIR_HOUSING_HUD_COMPLAINT |
10 days | FHA 42 USC 3604 | HUD response window — failure = default finding |
FIRPTA_WITHHOLDING_DEFICIENCY |
IMMEDIATE | FIRPTA 26 USC 1445 | Agent personally liable + IRS interest |
DATA_BREACH_CONSUMER_NPI |
72 hours | GLBA Safeguards 16 CFR 314 | State + FTC within 30 days |
FINCEN_SAR_SUSPICIOUS |
30 days | FinCEN 31 CFR 1020.320 | No tipping off subject (31 USC 5318(g)(2)) |
{
"name": "PropTech CFPB RESPA FinCEN Incident Pipeline",
"nodes": [
{
"id": "1",
"name": "Webhook Trigger",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
240,
300
],
"parameters": {
"httpMethod": "POST",
"path": "proptech-incident",
"responseMode": "responseNode"
}
},
{
"id": "2",
"name": "ACK 200",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
460,
160
],
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({received:true,incident_id:$json.incident_id,ts:new Date().toISOString()}) }}"
}
},
{
"id": "3",
"name": "Classify Incident",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
440
],
"parameters": {
"jsCode": "const e=$input.first().json;const t=(e.incident_type||'').toUpperCase();const m={TRID_DISCLOSURE_VIOLATION:{urgency:'IMMEDIATE',sla:'CFPB strict liability 12 CFR 1026.19 - no cure period for missed 3-biz-day LE delivery. Enforcement initiates at violation.',ch:'#compliance-emergency'},RESPA_KICKBACK_ALLEGED:{urgency:'IMMEDIATE',sla:'RESPA 8 anti-kickback 12 USC 2607 - $10K civil plus 1yr criminal per violation. Outside counsel required.',ch:'#compliance-emergency'},FINCEN_CTR_TRIGGER:{urgency:'NEXT_BIZ_DAY',sla:'FinCEN CTR cash >$10K by next biz day - 31 CFR 1010.311. FASTEST PROPTECH CLOCK.',ch:'#compliance-ops'},FCRA_ADVERSE_ACTION_FAILURE:{urgency:'IMMEDIATE',sla:'FCRA adverse action 5-biz-day clock starts at denial - 15 USC 1681m. Per-violation strict liability.',ch:'#compliance-emergency'},FAIR_HOUSING_HUD_COMPLAINT:{urgency:'10_DAYS',sla:'HUD complaint response 10 days - 24 CFR 103.204. Failure = default finding.',ch:'#compliance-ops'},FIRPTA_WITHHOLDING_DEFICIENCY:{urgency:'IMMEDIATE',sla:'FIRPTA agent personally liable for unremitted withholding - 26 USC 1445 plus IRS interest.',ch:'#compliance-emergency'},DATA_BREACH_CONSUMER_NPI:{urgency:'72_HOURS',sla:'State breach notification plus GLBA Safeguards 16 CFR 314.4(j) - FTC within 30 days.',ch:'#security-incident'},FINCEN_SAR_SUSPICIOUS:{urgency:'30_DAYS',sla:'SAR within 30 days - 31 CFR 1020.320. No tipping off (31 USC 5318(g)(2)).',ch:'#compliance-ops'}};const info=m[t]||{urgency:'REVIEW',sla:'Manual review.',ch:'#compliance-ops'};return [{json:{...e,incident_type:t,urgency:info.urgency,sla:info.sla,alertChannel:info.ch}}];"
}
},
{
"id": "4",
"name": "Route by Urgency",
"type": "n8n-nodes-base.switch",
"typeVersion": 3,
"position": [
680,
440
],
"parameters": {
"mode": "rules",
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "IMMEDIATE",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "NEXT_BIZ_DAY",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
},
"outputIndex": 1
},
{
"conditions": {
"options": {
"caseSensitive": true
},
"conditions": [
{
"leftValue": "={{ $json.urgency }}",
"rightValue": "IMMEDIATE",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
]
},
"outputIndex": 2
}
]
}
}
},
{
"id": "5",
"name": "Slack IMMEDIATE",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
900,
200
],
"parameters": {
"channel": "={{ $json.alertChannel }}",
"text": "={{ 'IMMEDIATE PropTech Incident: ' + $json.incident_type + ' | SLA: ' + $json.sla + ' | Customer: ' + $json.customer_id + ' @channel' }}"
}
},
{
"id": "6",
"name": "Slack CTR Filing",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
900,
380
],
"parameters": {
"channel": "#compliance-ops",
"text": "={{ 'FinCEN NEXT_BIZ_DAY: ' + $json.incident_type + ' | ' + $json.sla + ' | Customer: ' + $json.customer_id }}"
}
},
{
"id": "7",
"name": "Slack Other",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
900,
560
],
"parameters": {
"channel": "={{ $json.alertChannel }}",
"text": "={{ 'PropTech Incident [' + $json.urgency + ']: ' + $json.incident_type + ' | ' + $json.sla }}"
}
},
{
"id": "8",
"name": "Log to Postgres",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
1120,
440
],
"parameters": {
"operation": "insert",
"schema": "public",
"table": "proptech_incident_log",
"columns": "incident_id,incident_type,urgency,customer_id,sla_note,received_at",
"values": "={{ $json.incident_id }},={{ $json.incident_type }},={{ $json.urgency }},={{ $json.customer_id }},={{ $json.sla }},={{ new Date().toISOString() }}"
}
}
],
"connections": {
"Webhook Trigger": {
"main": [
[
{
"node": "ACK 200",
"type": "main",
"index": 0
},
{
"node": "Classify Incident",
"type": "main",
"index": 0
}
]
]
},
"Classify Incident": {
"main": [
[
{
"node": "Route by Urgency",
"type": "main",
"index": 0
}
]
]
},
"Route by Urgency": {
"main": [
[
{
"node": "Slack IMMEDIATE",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack CTR Filing",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack Other",
"type": "main",
"index": 0
}
]
]
},
"Slack IMMEDIATE": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
},
"Slack CTR Filing": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
},
"Slack Other": {
"main": [
[
{
"node": "Log to Postgres",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly PropTech KPI Dashboard
Runs every Monday at 8AM. Parallel Postgres queries: platform metrics (customers by tier, MRR, new/churned) and compliance metrics (critical open items, FinCEN CTRs filed, TRID incidents). Merges, computes WoW% using $getWorkflowStaticData for cross-run persistence, builds HTML table, emails CEO (BCC CTO/COO), and posts to #exec-kpis.
{
"name": "PropTech Weekly KPI Dashboard",
"nodes": [
{
"id": "1",
"name": "Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1,
"position": [
240,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 8 * * 1"
}
]
}
}
},
{
"id": "2",
"name": "Query Platform Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
200
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(DISTINCT customer_id) AS active_customers, COUNT(DISTINCT CASE WHEN created_at >= NOW()-INTERVAL '7 days' THEN customer_id END) AS new_this_week, COUNT(DISTINCT CASE WHEN churned_at >= NOW()-INTERVAL '7 days' THEN customer_id END) AS churned_this_week, SUM(arr_usd)/12.0 AS mrr_usd, SUM(CASE WHEN tier='MORTGAGE_LENDING_OS_VENDOR' THEN 1 ELSE 0 END) AS mortgage_accounts, SUM(CASE WHEN tier='TENANT_SCREENING_SAAS' THEN 1 ELSE 0 END) AS screening_accounts FROM proptech_accounts WHERE churned_at IS NULL OR churned_at >= NOW()-INTERVAL '7 days'"
}
},
{
"id": "3",
"name": "Query Compliance Metrics",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2,
"position": [
460,
440
],
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(*) FILTER (WHERE status='OPEN' AND urgency IN ('OVERDUE','CRITICAL')) AS critical_open, COUNT(*) FILTER (WHERE status='FILED' AND created_at >= NOW()-INTERVAL '7 days') AS ctrs_filed_7d, COUNT(*) FILTER (WHERE incident_type LIKE 'TRID%' AND created_at >= NOW()-INTERVAL '7 days') AS trid_incidents_7d FROM proptech_incident_log"
}
},
{
"id": "4",
"name": "Merge Queries",
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
680,
300
],
"parameters": {
"mode": "combine",
"combinationMode": "mergeByPosition"
}
},
{
"id": "5",
"name": "Build KPI Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
],
"parameters": {
"jsCode": "const state=$getWorkflowStaticData('global');const d=$input.first().json;const prev=state.prev||{};const pct=(c,p)=>p>0?((c-p)/p*100).toFixed(1)+'%':'new';const html='<h2>FlowKit PropTech Weekly KPI</h2><table border=1 cellpadding=4><tr><th>Metric</th><th>This Week</th><th>WoW</th></tr><tr><td>Active Customers</td><td>'+d.active_customers+'</td><td>'+pct(d.active_customers,prev.active_customers||0)+'</td></tr><tr><td>New This Week</td><td>'+d.new_this_week+'</td><td>n/a</td></tr><tr><td>Churned</td><td>'+d.churned_this_week+'</td><td>n/a</td></tr><tr><td>MRR (USD)</td><td>$'+Number(d.mrr_usd||0).toFixed(0)+'</td><td>'+pct(d.mrr_usd,prev.mrr_usd||0)+'</td></tr><tr><td>Mortgage LOS Accounts</td><td>'+d.mortgage_accounts+'</td><td>n/a</td></tr><tr><td>Screening Accounts</td><td>'+d.screening_accounts+'</td><td>n/a</td></tr><tr><td>Critical/Overdue Compliance</td><td>'+d.critical_open+'</td><td>n/a</td></tr><tr><td>FinCEN CTRs Filed (7d)</td><td>'+d.ctrs_filed_7d+'</td><td>n/a</td></tr><tr><td>TRID Incidents (7d)</td><td>'+d.trid_incidents_7d+'</td><td>n/a</td></tr></table>';state.prev=d;return [{json:{...d,html,slackLine:'PropTech KPI: '+d.active_customers+' customers | MRR $'+Number(d.mrr_usd||0).toFixed(0)+' | '+d.critical_open+' critical compliance | '+d.ctrs_filed_7d+' CTRs filed'}}];"
}
},
{
"id": "6",
"name": "Email CEO BCC CTO",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2,
"position": [
1120,
200
],
"parameters": {
"sendTo": "ceo@yourcompany.com",
"subject": "PropTech Weekly KPI Dashboard",
"message": "={{ $json.html }}",
"options": {
"bcc": "cto@yourcompany.com,coo@yourcompany.com"
}
}
},
{
"id": "7",
"name": "Slack exec-kpis",
"type": "n8n-nodes-base.slack",
"typeVersion": 2,
"position": [
1120,
440
],
"parameters": {
"channel": "#exec-kpis",
"text": "={{ $json.slackLine }}"
}
}
],
"connections": {
"Monday 8AM": {
"main": [
[
{
"node": "Query Platform Metrics",
"type": "main",
"index": 0
},
{
"node": "Query Compliance Metrics",
"type": "main",
"index": 0
}
]
]
},
"Query Platform Metrics": {
"main": [
[
{
"node": "Merge Queries",
"type": "main",
"index": 0
}
]
]
},
"Query Compliance Metrics": {
"main": [
[
{
"node": "Merge Queries",
"type": "main",
"index": 1
}
]
]
},
"Merge Queries": {
"main": [
[
{
"node": "Build KPI Report",
"type": "main",
"index": 0
}
]
]
},
"Build KPI Report": {
"main": [
[
{
"node": "Email CEO BCC CTO",
"type": "main",
"index": 0
},
{
"node": "Slack exec-kpis",
"type": "main",
"index": 0
}
]
]
}
}
}
Why Self-Hosted n8n Wins for PropTech
| Requirement | Cloud iPaaS (Zapier/Make) | Self-Hosted n8n |
|---|---|---|
| CFPB Reg P NPI processor agreement | Need formal service provider agreement + annual vendor assessment | NPI never leaves VPC — no Reg P exposure |
| TRID audit trail | Zapier 30-day task log retention | Git-versioned workflows = permanent TRID compliance evidence |
| FinCEN BSA CTR/SAR workflow | Cloud routing = BSA sub-processor designation | Financial data stays in compliance boundary |
| FIRPTA foreign seller TIN handling | TIN/withholding data transits Zapier servers | IRS 6103 unauthorized disclosure risk eliminated |
| FCRA consumer report data | Every workflow adds CRA cloud processor | Consumer reports never leave your VPC |
| SOC 2 Type II audit | Zapier 30-day log fails SOC 2 CC7.2 | n8n execution logs stored permanently in Postgres |
| Per-execution cost at scale | 500K tasks/mo = $800+/mo Zapier Pro | $30/mo VPS handles 10M+ tasks/mo |
The sharpest argument: CFPB Regulation P (16 CFR 313) requires a written service provider agreement with any entity that receives NPI on your behalf. If your Loan Estimate workflow runs through Zapier, Zapier is an NPI processor — you need a formal agreement, annual vendor assessment, and audit rights. Self-hosted n8n eliminates this: NPI never leaves your servers.
For FIRPTA platforms: Foreign seller TINs and withholding amounts are IRS-reportable under 6103. Routing this data through a commercial cloud iPaaS creates unauthorized disclosure risk. Self-hosted n8n = withholding data never leaves your compliance boundary.
Get the Complete Bundle
All 15 production-ready n8n templates — including the PropTech compliance suite above — are available at stripeai.gumroad.com. Every workflow ships as importable JSON with setup documentation.
Individual templates: $12-$29. Full bundle (15 templates): $97.
Built for PropTech and real estate SaaS founders who ship their own n8n instance and want every compliance workflow pre-wired on day one.
Top comments (0)