If you're building a telehealth platform, RPM software, or digital health app, your automation infrastructure has to do something Zapier fundamentally cannot: keep PHI inside your own network.
Zapier's standard BAA covers basic usage, but every task that runs through their infrastructure makes your HIPAA audit scope larger and your legal exposure higher. HITECH breach notification requirements, ONC 21st Century Cures Act information blocking rules, and FDA SaMD classification thresholds all assume you control your data flows.
n8n deployed on your own infrastructure eliminates the sub-processor problem entirely. Workflow JSON is git-versioned — that's your HIPAA Security Rule CM-3 configuration change control evidence. And at the volumes digital health platforms generate (1M+ device readings/day), Zapier's per-task pricing isn't just expensive — it's budget-destroying.
Here are 5 production-grade n8n workflows for HealthTech SaaS vendors. All include import-ready JSON.
Workflow 1: EHR & Patient Data Integration Health Monitor
Your platform's value depends on live EHR integrations. If Epic's FHIR endpoint goes stale or a Cerner webhook stops delivering, clinicians get incomplete data — and you get churn before you even know there's a problem.
This workflow polls all active integrations every 5 minutes and alerts on degraded or down pipelines.
{
"name": "EHR & Patient Data Integration Health Monitor",
"nodes": [
{
"name": "Every 5 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": { "rule": { "interval": [{ "field": "minutes", "minutesInterval": 5 }] } }
},
{
"name": "Get Active Integrations",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT id, customer_id, ehr_system, health_endpoint, sla_gap_minutes FROM ehr_integrations WHERE status = 'active'"
}
},
{
"name": "Check Each Endpoint",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "={{ $json.health_endpoint }}",
"method": "GET",
"timeout": 8000,
"continueOnFail": true
}
},
{
"name": "Classify Integration Status",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const items = $input.all(); const state = $getWorkflowStaticData('global'); const now = Date.now(); const alerts = []; for (const item of items) { const d = item.json; const statusCode = item.json.statusCode || 0; const elapsed = (now - (state['last_ok_' + d.id] || now)) / 60000; let status = 'OK'; if (statusCode < 200 || statusCode >= 300) status = 'DOWN'; else if (elapsed > d.sla_gap_minutes * 1.5) status = 'DEGRADED'; else { state['last_ok_' + d.id] = now; } if (status !== 'OK') { const dedupKey = 'alerted_' + d.id; if (!state[dedupKey] || (now - state[dedupKey]) > 1800000) { state[dedupKey] = now; alerts.push({ ...d, status, elapsed_min: Math.round(elapsed) }); } } } $setWorkflowStaticData('global', state); return alerts.map(a => ({ json: a }));"
}
},
{
"name": "Slack #platform-integrations",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#platform-integrations",
"text": "={{ '🔴 EHR Integration ' + $json.status + ': ' + $json.ehr_system + ' (Customer ' + $json.customer_id + ') — ' + $json.elapsed_min + 'min since last event. Check ' + $json.health_endpoint }}"
}
}
]
}
Why this matters for HealthTech SaaS: EHR integrations are your stickiest feature and your highest churn risk. A 15-minute outage that a clinic discovers before you do is a contract review conversation. Running this inside your own VPC means integration health data — including customer EHR endpoint URLs and connection metadata — never leaves your network.
Workflow 2: New Health System Client Onboarding & HIPAA BAA Drip
Health system procurement is slow. The moment a new client signs, you want activation to start immediately — API key delivery, integration guides, BAA countersignature confirmation, and check-in touchpoints at day 3, 7, and 14.
{
"name": "New Health System Onboarding Drip",
"nodes": [
{
"name": "New Client Trigger",
"type": "n8n-nodes-base.googleSheetsTrigger",
"parameters": { "event": "rowAdded", "sheetName": "new_clients" }
},
{
"name": "Classify Client Tier",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const d = $json; let tier = 'SMALL_PRACTICE'; if (d.beds > 500 || d.client_type === 'health_system') tier = 'HEALTH_SYSTEM'; else if (d.beds > 100 || d.client_type === 'hospital') tier = 'HOSPITAL'; else if (d.client_type === 'clinic_group') tier = 'CLINIC_GROUP'; return [{ json: { ...d, tier } }];"
}
},
{
"name": "Day 0 Welcome + API Keys",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{ $json.it_admin_email }}",
"subject": "={{ 'Welcome to [Platform] — API Keys + HIPAA BAA for ' + $json.org_name }}",
"message": "={{ 'Hi ' + $json.contact_name + ', Welcome aboard. Your API key: ' + $json.api_key + '. BAA countersignature attached. EHR integration guide: [link]. Your CSM: ' + $json.csm_name + ' at ' + $json.csm_email + '. We target <4h response for clinical integration questions.' }}"
}
},
{
"name": "Notify CSM in Slack",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#csm-queue",
"text": "={{ '🏥 New ' + $json.tier + ' client: ' + $json.org_name + ' (' + $json.beds + ' beds). IT admin: ' + $json.it_admin_email + '. EHR: ' + $json.ehr_system + '. Log it in HubSpot.' }}"
}
},
{
"name": "Wait 3 Days",
"type": "n8n-nodes-base.wait",
"parameters": { "amount": 3, "unit": "days" }
},
{
"name": "Day 3 EHR Integration Check-in",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{ $json.it_admin_email }}",
"subject": "={{ 'Quick check-in: EHR integration status for ' + $json.org_name }}",
"message": "={{ 'Hi ' + $json.contact_name + ', Is your ' + $json.ehr_system + ' integration connected? If you hit any snags with FHIR endpoint config or SMART on FHIR scopes, reply here and we will get you live today. Your integration guide: [link].' }}"
}
},
{
"name": "Wait 4 Days",
"type": "n8n-nodes-base.wait",
"parameters": { "amount": 4, "unit": "days" }
},
{
"name": "Day 7 First Patient Data Milestone",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{ $json.it_admin_email }}",
"subject": "={{ 'You should be seeing live patient data by now — ' + $json.org_name }}",
"message": "={{ 'Hi ' + $json.contact_name + ', By day 7 most clients have their first patient data flowing. Log into the dashboard and check [link]. If your numbers look off, book a 30-min setup call: [calendar link]. Your CSM ' + $json.csm_name + ' can also join.' }}"
}
}
]
}
Why this matters: Health system IT teams are slow to activate — they have competing priorities and limited DevOps bandwidth. An automated 7-day drip that anticipates the exact friction points (BAA questions, FHIR scope config, SMART on FHIR) reduces time-to-first-value and reduces CSM load simultaneously.
Workflow 3: HIPAA, FDA & Digital Health Regulatory Deadline Tracker
HealthTech SaaS faces the widest regulatory surface of any software vertical: HIPAA Security Rule, HIPAA Breach Notification Rule, HITECH, ONC 21st Century Cures Act, FDA SaMD (Software as a Medical Device), SOC2, GDPR for EU patients, and state-level health data laws (CMIA, MHMD, etc.).
Missing a breach notification window (60 days post-discovery) or an FDA submission deadline is an existential event.
{
"name": "HIPAA & FDA Compliance Deadline Tracker",
"nodes": [
{
"name": "Weekdays 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * 1-5" }] } }
},
{
"name": "Get Compliance Deadlines",
"type": "n8n-nodes-base.googleSheets",
"parameters": { "operation": "getAll", "sheetName": "compliance_deadlines" }
},
{
"name": "Classify Urgency",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const actionMap = { 'HIPAA_BREACH_NOTIFICATION': 'File HHS OCR breach report at hhs.gov/hipaa — 60-day window from discovery date', 'HIPAA_SECURITY_RULE_REVIEW': 'Annual Security Rule risk analysis — document in risk register', 'HITECH_BAA_AUDIT': 'Review all Business Associate Agreements — ensure all vendors have current signed BAAs', 'ONC_CURES_INFORMATION_BLOCKING': 'ONC information blocking compliance audit — ensure no data access restriction', 'FDA_SAMD_510K': 'FDA 510(k) SaMD submission due — coordinate with regulatory affairs', 'FDA_DE_NOVO': 'FDA De Novo classification request due', 'SOC2_EVIDENCE': 'Collect SOC2 evidence for period — screenshots, logs, access reviews', 'GDPR_DPA_RENEWAL': 'Renew GDPR Data Processing Agreement with affected EHR/cloud vendors', 'HITRUST_ASSESSMENT': 'HITRUST CSF assessment preparation — gather control evidence', 'STATE_CMIA_AUDIT': 'California CMIA compliance review — patient data handling', 'STATE_MHMD_REVIEW': 'My Health My Data Act (WA) compliance — health data broker prohibition check' }; const items = $input.all(); const now = new Date(); return items.map(item => { const d = item.json; if (!d.deadline_date || !d.regulation_type) return null; const days = Math.round((new Date(d.deadline_date) - now) / 86400000); let urgency = 'NOTICE'; if (days < 0) urgency = 'OVERDUE'; else if (days <= 7) urgency = 'CRITICAL'; else if (days <= 21) urgency = 'URGENT'; else if (days <= 60) urgency = 'WARNING'; else return null; const action = actionMap[d.regulation_type] || d.required_action || 'Review deadline with compliance team'; return { json: { ...d, days_until: days, urgency, action } }; }).filter(Boolean);"
}
},
{
"name": "Route by Urgency",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataPropertyName": "urgency",
"rules": {
"rules": [
{ "value": "OVERDUE", "output": 0 },
{ "value": "CRITICAL", "output": 0 },
{ "value": "URGENT", "output": 1 },
{ "value": "WARNING", "output": 2 }
]
}
}
},
{
"name": "Slack CRITICAL #compliance-critical @here",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#compliance-critical",
"text": "={{ '<!here> 🔴 ' + $json.urgency + ': ' + $json.regulation_type + ' — ' + ($json.days_until < 0 ? Math.abs($json.days_until) + 'd overdue' : $json.days_until + 'd remaining') + '. Action: ' + $json.action + '. Owner: ' + $json.owner_email }}"
}
},
{
"name": "Email Owner",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "={{ $json.owner_email }}",
"subject": "={{ $json.urgency + ': ' + $json.regulation_type + ' deadline in ' + $json.days_until + ' days' }}",
"message": "={{ 'Regulation: ' + $json.regulation_type + '. Deadline: ' + $json.deadline_date + ' (' + $json.days_until + ' days). Required action: ' + $json.action + '. This is your ' + $json.urgency + '-level reminder.' }}"
}
}
]
}
Why this matters: A missed 60-day HIPAA breach notification window triggers mandatory HHS OCR investigation, press release, and potential $100K–$1.9M civil money penalty. No calendar reminder survives organizational chaos. This tracker runs every weekday whether or not the responsible person is in the office.
Workflow 4: RPM Device Event Fanout & Clinical Alert Pipeline
RPM platforms generate continuous device readings — blood glucose, blood pressure, heart rate, SpO2, weight. Most readings are normal. Some require a nurse notification within hours. A few require immediate provider escalation.
The challenge: classify and route thousands of events per second without routing PHI through third-party automation infrastructure.
{
"name": "RPM Device Event Fanout & Clinical Alert Pipeline",
"nodes": [
{
"name": "RPM Device Webhook",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "rpm-device-event",
"responseMode": "onReceived",
"responseCode": 200
}
},
{
"name": "Classify Clinical Severity",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const d = $json.body || $json; const reading = d.reading_value; const type = d.reading_type; const thresholds = { glucose: { critical_high: 400, high: 250, low: 70, critical_low: 54 }, systolic_bp: { critical_high: 180, high: 140, low: 90, critical_low: 70 }, heart_rate: { critical_high: 150, high: 100, low: 50, critical_low: 40 }, spo2: { critical_low: 88, low: 92 } }; const t = thresholds[type]; let severity = 'NORMAL'; if (t) { if ((t.critical_high && reading >= t.critical_high) || (t.critical_low && reading <= t.critical_low)) severity = 'CRITICAL'; else if ((t.high && reading >= t.high) || (t.low && reading <= t.low)) severity = 'ABNORMAL'; } return [{ json: { ...d, severity } }];"
}
},
{
"name": "Route by Severity",
"type": "n8n-nodes-base.switch",
"parameters": {
"dataPropertyName": "severity",
"rules": { "rules": [{ "value": "CRITICAL", "output": 0 }, { "value": "ABNORMAL", "output": 1 }, { "value": "NORMAL", "output": 2 }] }
}
},
{
"name": "CRITICAL: Page Provider via Slack",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#clinical-alerts-critical",
"text": "={{ '🔴 CRITICAL RPM: Patient ' + $json.patient_id + ' — ' + $json.reading_type + ': ' + $json.reading_value + $json.unit + ' at ' + $json.timestamp + '. Provider: ' + $json.assigned_provider + '. Review immediately in platform.' }}"
}
},
{
"name": "ABNORMAL: Queue for Nurse Review",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "insert",
"table": "clinical_review_queue",
"columns": "patient_id,reading_type,reading_value,unit,severity,timestamp,assigned_nurse,raw_payload",
"columnData": "={{ $json.patient_id }},={{ $json.reading_type }},={{ $json.reading_value }},={{ $json.unit }},={{ $json.severity }},={{ $json.timestamp }},={{ $json.assigned_nurse }},={{ JSON.stringify($json) }}"
}
},
{
"name": "NORMAL: Log to Readings Table",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "insert",
"table": "device_readings",
"columns": "patient_id,reading_type,reading_value,unit,severity,timestamp",
"columnData": "={{ $json.patient_id }},={{ $json.reading_type }},={{ $json.reading_value }},={{ $json.unit }},={{ $json.severity }},={{ $json.timestamp }}"
}
}
]
}
Why this matters for HIPAA compliance: Every device reading is PHI (linked to a named patient with a health condition). Running this event pipeline through Zapier or Make makes their servers a HIPAA sub-processor for every reading — expanding your breach notification scope to include their infrastructure. Self-hosted n8n means PHI never leaves your VPC.
Workflow 5: Weekly HealthTech Platform KPI Dashboard
Clinical leadership and investor reporting both need the same weekly numbers: active patients, device readings collected, alert incidents by severity, new health system signups, MRR.
{
"name": "Weekly HealthTech Platform KPI Dashboard",
"nodes": [
{
"name": "Monday 8AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": { "rule": { "interval": [{ "field": "cronExpression", "expression": "0 8 * * 1" }] } }
},
{
"name": "This Week Metrics",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(DISTINCT patient_id) AS active_patients, COUNT(*) AS total_readings, SUM(CASE WHEN severity = 'CRITICAL' THEN 1 ELSE 0 END) AS critical_alerts, SUM(CASE WHEN severity = 'ABNORMAL' THEN 1 ELSE 0 END) AS abnormal_alerts, COUNT(DISTINCT customer_id) AS active_health_systems, SUM(mrr_cents)/100.0 AS mrr FROM device_readings dr LEFT JOIN billing b ON dr.customer_id = b.customer_id WHERE dr.timestamp > NOW() - INTERVAL '7 days'"
}
},
{
"name": "Last Week Metrics",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(DISTINCT patient_id) AS active_patients, COUNT(*) AS total_readings, SUM(CASE WHEN severity = 'CRITICAL' THEN 1 ELSE 0 END) AS critical_alerts, SUM(mrr_cents)/100.0 AS mrr FROM device_readings dr LEFT JOIN billing b ON dr.customer_id = b.customer_id WHERE dr.timestamp BETWEEN NOW() - INTERVAL '14 days' AND NOW() - INTERVAL '7 days'"
}
},
{
"name": "Build Dashboard Email",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const state = $getWorkflowStaticData('global'); const tw = $('This Week Metrics').first().json; const lw = $('Last Week Metrics').first().json || {}; const pct = (a, b) => b > 0 ? ((a - b) / b * 100).toFixed(1) + '%' : 'N/A'; const arrow = v => parseFloat(v) >= 0 ? '▲' : '▼'; const wowPatients = pct(tw.active_patients, lw.active_patients); const wowReadings = pct(tw.total_readings, lw.total_readings); const wowMRR = pct(tw.mrr, lw.mrr); const html = '<h2>Weekly HealthTech Platform Dashboard</h2><table border=1 cellpadding=8><tr><th>Metric</th><th>This Week</th><th>WoW</th></tr><tr><td>Active Patients</td><td>' + tw.active_patients + '</td><td>' + arrow(wowPatients) + ' ' + wowPatients + '</td></tr><tr><td>Device Readings</td><td>' + Number(tw.total_readings).toLocaleString() + '</td><td>' + arrow(wowReadings) + ' ' + wowReadings + '</td></tr><tr><td>Critical Alerts</td><td>' + tw.critical_alerts + '</td><td>—</td></tr><tr><td>Abnormal Alerts</td><td>' + tw.abnormal_alerts + '</td><td>—</td></tr><tr><td>Active Health Systems</td><td>' + tw.active_health_systems + '</td><td>—</td></tr><tr><td>MRR</td><td>$' + Number(tw.mrr).toLocaleString() + '</td><td>' + arrow(wowMRR) + ' ' + wowMRR + '</td></tr></table>'; return [{ json: { html, mrr: tw.mrr, wowMRR } }];"
}
},
{
"name": "Email Leadership",
"type": "n8n-nodes-base.gmail",
"parameters": {
"to": "ceo@company.com",
"bcc": "cto@company.com,cmo@company.com,vp-cs@company.com",
"subject": "Weekly Platform Dashboard — ${{ $json.mrr }}K MRR, {{ $json.wowMRR }} WoW",
"message": "={{ $json.html }}",
"messageType": "html"
}
}
]
}
Why HealthTech SaaS Should Run n8n On-Premises
| Concern | Zapier/Make | Self-hosted n8n |
|---|---|---|
| HIPAA BAA scope | Expands PHI data flow scope | PHI stays inside your VPC |
| HITECH breach notification | Every Zapier task = PHI exposure event | Zero external exposure |
| ONC information blocking | Data access via third party | Direct DB/API access only |
| FDA SaMD audit trail | Black-box third-party logs | Git-versioned JSON + Postgres |
| GDPR for EU patients | Art.28 sub-processor paperwork | Sub-processor eliminated |
| Volume economics | 1M readings/day = $8K–$40K/mo | $40/mo VPS |
| Deployment | Cloud only | On-prem, cloud, GovCloud, air-gapped |
Get These Workflows Pre-Built
These are five of the 15 production-grade n8n templates in the FlowKit HealthTech pack at stripeai.gumroad.com. Each includes ready-to-import JSON, setup guide, and customization notes.
Individual templates start at $15. The full bundle (15 templates) is $97.
If you're building HealthTech infrastructure and want a workflow that isn't in the pack, reply here — I build custom templates.
All workflows above are import-ready. In n8n: Settings → Import workflow → paste the JSON. Swap placeholder values (Postgres credentials, Slack channel names, Gmail account) with your own.
Top comments (0)