Medical device companies operate under some of the strictest regulatory frameworks on earth.
FDA 21 CFR Part 820 Quality System Regulation, ISO 13485:2016 QMS certification, IEC 62304:2006+AMD1:2015 software lifecycle, EU MDR 2017/745, EU IVDR 2017/746 — every missed deadline or failed audit can mean product recalls, Warning Letters, or market withdrawal.
If your company sells quality management software, regulatory submission platforms, post-market surveillance SaaS, or clinical data management tools to medical device manufacturers, this post is for you.
These five n8n automations handle the workflows that make or break MedDevice SaaS operations — without routing FDA-controlled documents or patient data through a third-party cloud like Zapier or Make.com.
Why Self-Hosted n8n for MedDevice SaaS?
Three reasons your customers will ask for this before signing:
- 21 CFR Part 11 electronic records — audit trails for every automated action, version-controlled workflow JSON in git, timestamped execution logs. n8n's git integration satisfies CFR Part 11 §11.10(e) audit trail requirements.
- ISO 13485 §4.2.5 document control — automated workflow = documented, validated process. No manual handoffs, no undocumented steps.
- Data residency — device master records, DHFs, adverse event data, and clinical trial data cannot transit a US-based iPaaS if your customer is EU-based (GDPR Art. 44-46). Self-hosted n8n on the customer's VPC solves this.
Workflow 1: New Customer Regulatory Onboarding Drip
Different device classifications need different onboarding tracks. A Class III PMA customer needs FDA submission workflow training. An IVD company under IVDR needs different compliance playbooks than an MDR Class IIa device maker.
{
"name": "MedDevice Customer Onboarding Drip",
"nodes": [
{
"name": "Webhook - New Customer",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "meddevice-onboarding",
"httpMethod": "POST"
}
},
{
"name": "Code - Classify Account",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const d = $input.first().json;\nconst classification = d.device_class || 'CLASS_II';\nconst framework = d.regulatory_framework || 'FDA_21CFR820';\nconst complianceFlags = [];\nif (['CLASS_III','PMA'].includes(classification)) complianceFlags.push('FDA_PMA_REQUIRED','ISO13485_MANDATORY','DESIGN_CONTROLS_21CFR820_30');\nif (['CLASS_II','510K'].includes(classification)) complianceFlags.push('FDA_510K_PATHWAY','ISO13485_RECOMMENDED','SUBSTANTIAL_EQUIVALENCE_REQUIRED');\nif (framework.includes('EU_MDR')) complianceFlags.push('EU_MDR_2017_745','EUDAMED_REGISTRATION','QMS_NOTIFIED_BODY_AUDIT','IEC62304_SOFTWARE_CLASS');\nif (framework.includes('EU_IVDR')) complianceFlags.push('EU_IVDR_2017_746','PERFORMANCE_EVALUATION','CLASS_A_B_C_D_IVD');\nif (framework.includes('IEC62304')) complianceFlags.push('SOFTWARE_LIFECYCLE_IEC62304','SAFETY_CLASS_A_B_C','SOUP_TRACKING_REQUIRED');\nif (d.has_clinical_data) complianceFlags.push('21CFR11_ELECTRONIC_RECORDS','FDA_CFR_PART_11_AUDIT_TRAIL');\nreturn [{ json: { ...d, classification, framework, complianceFlags, onboardingTier: complianceFlags.length > 4 ? 'ENTERPRISE_REGULATED' : complianceFlags.length > 2 ? 'STANDARD_REGULATED' : 'BASIC', onboardedAt: new Date().toISOString() } }];"
}
},
{
"name": "Gmail - Day 0 Welcome",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.contact_email }}",
"subject": "Welcome to {{ $json.company_name }} \u2014 Your Compliance Automation Is Ready",
"message": "=Hi {{ $json.contact_name }},\n\nWelcome! Your onboarding tier: {{ $json.onboardingTier }}.\n\nRegulatory flags detected: {{ $json.complianceFlags.join(', ') }}.\n\nDay 3: Integration setup guide for your {{ $json.framework }} workflows.\nDay 7: QMS document control automation walkthrough.\nDay 14: Post-market surveillance pipeline setup.\n\nYour dedicated CSM will reach out within 24h.\n\nBest,\nThe Team"
}
},
{
"name": "Google Sheets - Log",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "append",
"sheetId": "YOUR_SHEET_ID",
"range": "Customers!A:H",
"values": [
[
"={{ $json.company_name }}",
"={{ $json.contact_email }}",
"={{ $json.classification }}",
"={{ $json.framework }}",
"={{ $json.onboardingTier }}",
"={{ $json.complianceFlags.join('|') }}",
"={{ $json.onboardedAt }}",
"D0_SENT"
]
]
}
},
{
"name": "Wait - 3 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"amount": 3,
"unit": "days"
}
},
{
"name": "Gmail - Day 3 Integration",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.contact_email }}",
"subject": "Day 3: Connect Your QMS APIs \u2014 Step-by-Step Guide",
"message": "=Hi {{ $json.contact_name }},\n\nTime to connect your quality management data sources.\n\n{{ $json.framework.includes('EU_MDR') ? 'Your EU MDR setup guide: EUDAMED API integration, notified body certificate sync, UDI-DI registration automation.' : 'Your FDA setup guide: CAPA system webhook, DHF document control integration, 510(k) submission tracker.' }}\n\nOpen your integration dashboard: [LINK]\n\nBest,\nThe Team"
}
},
{
"name": "Wait - 4 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"amount": 4,
"unit": "days"
}
},
{
"name": "Gmail - Day 7 QMS",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.contact_email }}",
"subject": "Day 7: Automate Your ISO 13485 Document Control",
"message": "=Hi {{ $json.contact_name }},\n\nISO 13485 \u00a74.2.5 requires controlled documents with revision history, approval workflows, and distribution records.\n\nHere is how to automate it in n8n: [LINK to guide]\n\nIEC 62304 SOUP tracking automation (for software teams): [LINK]\n\nBest,\nThe Team"
}
},
{
"name": "Wait - 7 Days",
"type": "n8n-nodes-base.wait",
"parameters": {
"amount": 7,
"unit": "days"
}
},
{
"name": "Gmail - Day 14 Post-Market",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.contact_email }}",
"subject": "Day 14: Post-Market Surveillance Automation \u2014 Book Your Setup Call",
"message": "=Hi {{ $json.contact_name }},\n\nPost-market surveillance is where most teams fall behind. Let us automate your PSUR/PMCF data collection, MDR/MDV vigilance reports, and FDA MAUDE adverse event monitoring.\n\nBook a 30-min setup call: [CALENDLY LINK]\n\nBest,\nThe Team"
}
}
],
"connections": {
"Webhook - New Customer": {
"main": [
[
{
"node": "Code - Classify Account",
"type": "main",
"index": 0
}
]
]
},
"Code - Classify Account": {
"main": [
[
{
"node": "Gmail - Day 0 Welcome",
"type": "main",
"index": 0
}
]
]
},
"Gmail - Day 0 Welcome": {
"main": [
[
{
"node": "Google Sheets - Log",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets - Log": {
"main": [
[
{
"node": "Wait - 3 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait - 3 Days": {
"main": [
[
{
"node": "Gmail - Day 3 Integration",
"type": "main",
"index": 0
}
]
]
},
"Gmail - Day 3 Integration": {
"main": [
[
{
"node": "Wait - 4 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait - 4 Days": {
"main": [
[
{
"node": "Gmail - Day 7 QMS",
"type": "main",
"index": 0
}
]
]
},
"Gmail - Day 7 QMS": {
"main": [
[
{
"node": "Wait - 7 Days",
"type": "main",
"index": 0
}
]
]
},
"Wait - 7 Days": {
"main": [
[
{
"node": "Gmail - Day 14 Post-Market",
"type": "main",
"index": 0
}
]
]
}
}
}
What it does: Classifies new customers by device class (Class I/II/III, IVD), regulatory framework (FDA 21 CFR Part 820/IEC 62304/EU MDR/EU IVDR), and detected compliance flags. Routes Day 0/3/7/14 emails with content tailored to their specific regulatory profile — a Class III PMA customer gets different content than a Class A IEC 62304 software team.
Workflow 2: Regulatory Submission & Audit Deadline Tracker
FDA 510(k) submissions, PMA annual reports, ISO 13485 surveillance audits, EU MDR Article 83 Periodic Safety Update Reports (PSUR), IVDR performance evaluation timelines — missed regulatory deadlines trigger Warning Letters, CE certificate suspension, and market withdrawal.
{
"name": "MedDevice Regulatory Deadline Tracker",
"nodes": [
{
"name": "Schedule - Weekdays 7AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * 1-5"
}
]
}
}
},
{
"name": "Google Sheets - Regulatory Deadlines",
"type": "n8n-nodes-base.googleSheets",
"parameters": {
"operation": "getAll",
"sheetId": "YOUR_DEADLINES_SHEET_ID",
"range": "Deadlines!A:H"
}
},
{
"name": "Code - Classify Urgency",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const today = new Date();\nconst results = [];\nfor (const row of $input.all()) {\n const d = row.json;\n const deadline = new Date(d.deadline_date);\n const daysLeft = Math.floor((deadline - today) / 86400000);\n const DEADLINE_TYPES = {\n 'FDA_510K_SUBMISSION': { reg: '21 CFR Part 807.87', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 7 ? 'CRITICAL' : daysLeft <= 21 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' },\n 'FDA_PMA_ANNUAL_REPORT': { reg: '21 CFR Part 814.84', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 90 ? 'WARNING' : 'NOTICE' },\n 'ISO13485_SURVEILLANCE_AUDIT': { reg: 'ISO 13485:2016 \u00a78.2.2', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 21 ? 'CRITICAL' : daysLeft <= 45 ? 'URGENT' : daysLeft <= 90 ? 'WARNING' : 'NOTICE' },\n 'EU_MDR_PSUR': { reg: 'EU MDR 2017/745 Art.83', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' },\n 'EU_IVDR_PERFORMANCE_EVALUATION': { reg: 'EU IVDR 2017/746 Art.87', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' },\n 'IEC62304_SOFTWARE_VALIDATION': { reg: 'IEC 62304:2006+AMD1 \u00a78.6', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 7 ? 'CRITICAL' : daysLeft <= 21 ? 'URGENT' : daysLeft <= 45 ? 'WARNING' : 'NOTICE' },\n 'FDA_MDR_VIGILANCE_REPORT': { reg: '21 CFR Part 803 \u2014 30 days', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 3 ? 'CRITICAL' : daysLeft <= 7 ? 'URGENT' : daysLeft <= 14 ? 'WARNING' : 'NOTICE' },\n 'UDI_DATABASE_UPDATE': { reg: 'FDA UDI 21 CFR Part 830', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' },\n 'EUDAMED_REGISTRATION': { reg: 'EU MDR Art.29 / IVDR Art.26', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' },\n 'NOTIFIED_BODY_AUDIT': { reg: 'EU MDR Annex VII-XI', severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' }\n };\n const info = DEADLINE_TYPES[d.deadline_type] || { reg: d.deadline_type, severity: daysLeft <= 0 ? 'OVERDUE' : daysLeft <= 14 ? 'CRITICAL' : daysLeft <= 30 ? 'URGENT' : daysLeft <= 60 ? 'WARNING' : 'NOTICE' };\n if (info.severity !== 'NOTICE') {\n results.push({ json: { ...d, daysLeft, severity: info.severity, regulatory_citation: info.reg, alert_key: `${d.customer_id}_${d.deadline_type}_${d.deadline_date}` } });\n }\n}\nreturn results;"
}
},
{
"name": "Switch - Route by Severity",
"type": "n8n-nodes-base.switch",
"parameters": {
"rules": {
"rules": [
{
"value1": "={{ $json.severity }}",
"operation": "equal",
"value2": "OVERDUE"
},
{
"value1": "={{ $json.severity }}",
"operation": "equal",
"value2": "CRITICAL"
},
{
"value1": "={{ $json.severity }}",
"operation": "equal",
"value2": "URGENT"
}
]
}
}
},
{
"name": "Slack - OVERDUE Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#regulatory-critical",
"text": "=:rotating_light: OVERDUE: {{ $json.customer_name }} \u2014 {{ $json.deadline_type }} was due {{ Math.abs($json.daysLeft) }} days ago. Reg: {{ $json.regulatory_citation }}. Owner: {{ $json.owner_email }}. Escalate now."
}
},
{
"name": "Slack - CRITICAL Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "#regulatory-ops",
"text": "=:red_circle: CRITICAL: {{ $json.customer_name }} \u2014 {{ $json.deadline_type }} due in {{ $json.daysLeft }} days. Reg: {{ $json.regulatory_citation }}."
}
},
{
"name": "Gmail - Owner Notification",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.owner_email }}",
"subject": "={{ $json.severity }}: {{ $json.deadline_type }} \u2014 {{ $json.daysLeft }} days remaining",
"message": "={{ $json.severity }} deadline alert.\n\nCustomer: {{ $json.customer_name }}\nDeadline: {{ $json.deadline_date }} ({{ $json.daysLeft }} days)\nType: {{ $json.deadline_type }}\nRegulatory Citation: {{ $json.regulatory_citation }}\n\nTake action now in your regulatory portal."
}
}
],
"connections": {
"Schedule - Weekdays 7AM": {
"main": [
[
{
"node": "Google Sheets - Regulatory Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Google Sheets - Regulatory Deadlines": {
"main": [
[
{
"node": "Code - Classify Urgency",
"type": "main",
"index": 0
}
]
]
},
"Code - Classify Urgency": {
"main": [
[
{
"node": "Switch - Route by Severity",
"type": "main",
"index": 0
}
]
]
},
"Switch - Route by Severity": {
"main": [
[
{
"node": "Slack - OVERDUE Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack - CRITICAL Alert",
"type": "main",
"index": 0
}
],
[
{
"node": "Gmail - Owner Notification",
"type": "main",
"index": 0
}
]
]
}
}
}
Deadline types tracked: FDA 510(k) submissions, PMA annual reports (21 CFR Part 814.84), ISO 13485 surveillance audits, EU MDR 2017/745 Article 83 PSURs, EU IVDR 2017/746 performance evaluations, IEC 62304 software validation milestones, FDA MDR adverse event reports (21 CFR Part 803 — 30-day window), UDI database updates, EUDAMED registrations, notified body audits. OVERDUE items page Slack immediately.
Workflow 3: QMS Document Change Control & CAPA Monitor
ISO 13485 §8.5.2 requires documented CAPA processes. IEC 62304 §9.8 requires change requests to be evaluated for safety impact. A webhook from your document management system can automatically route CAPAs, trigger safety assessments, and create audit trail entries.
{
"name": "MedDevice QMS Change Control Monitor",
"nodes": [
{
"name": "Webhook - QMS Event",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "qms-change-event",
"httpMethod": "POST"
}
},
{
"name": "Code - Classify Change",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const ev = $input.first().json;\nconst event_type = ev.event_type || 'DOCUMENT_CHANGE';\nconst CLASS_MAP = {\n 'CAPA_OPENED': { channel: '#quality-ops', severity: 'HIGH', iso_ref: 'ISO 13485:2016 \u00a78.5.2', sla_hours: 24 },\n 'CAPA_OVERDUE': { channel: '#quality-critical', severity: 'CRITICAL', iso_ref: 'ISO 13485:2016 \u00a78.5.2', sla_hours: 4 },\n 'DEVIATION_REPORTED': { channel: '#quality-ops', severity: 'MEDIUM', iso_ref: 'ISO 13485:2016 \u00a78.3', sla_hours: 48 },\n 'SOFTWARE_CHANGE_REQUEST': { channel: '#engineering-ops', severity: 'HIGH', iso_ref: 'IEC 62304:2006+AMD1 \u00a79.8', sla_hours: 12 },\n 'DHF_DOCUMENT_UPDATED': { channel: '#regulatory-ops', severity: 'MEDIUM', iso_ref: '21 CFR Part 820.30 Design Controls', sla_hours: 48 },\n 'SOC_INCIDENT': { channel: '#quality-critical', severity: 'CRITICAL', iso_ref: '21 CFR Part 820.198 Complaint Files', sla_hours: 4 },\n 'SUPPLIER_AUDIT_FINDING': { channel: '#quality-ops', severity: 'HIGH', iso_ref: 'ISO 13485:2016 \u00a77.4.1', sla_hours: 24 },\n 'VALIDATION_PROTOCOL_DEVIATION': { channel: '#regulatory-ops', severity: 'HIGH', iso_ref: 'FDA 21 CFR Part 820.75 Process Validation', sla_hours: 24 }\n};\nconst info = CLASS_MAP[event_type] || { channel: '#quality-ops', severity: 'MEDIUM', iso_ref: ev.regulatory_ref || 'ISO 13485:2016', sla_hours: 48 };\nconst sla_deadline = new Date(Date.now() + info.sla_hours * 3600000).toISOString();\nreturn [{ json: { ...ev, ...info, sla_deadline, logged_at: new Date().toISOString() } }];"
}
},
{
"name": "Slack - Route Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "={{ $json.channel }}",
"text": "={{ $json.severity }}: {{ $json.event_type }} | Customer: {{ $json.customer_name }} | Document: {{ $json.document_id }} | Reg: {{ $json.iso_ref }} | SLA: {{ $json.sla_deadline }} | Owner: {{ $json.owner_email }}"
}
},
{
"name": "Gmail - Owner Alert",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.owner_email }}",
"subject": "=[QMS {{ $json.severity }}] {{ $json.event_type }} \u2014 Action Required by {{ $json.sla_deadline }}",
"message": "=QMS Event Alert\n\nEvent: {{ $json.event_type }}\nSeverity: {{ $json.severity }}\nCustomer: {{ $json.customer_name }}\nDocument: {{ $json.document_id }}\nRegulatory Reference: {{ $json.iso_ref }}\nSLA Deadline: {{ $json.sla_deadline }}\nLogged At: {{ $json.logged_at }}\n\nLog in to your QMS portal to take action."
}
},
{
"name": "Postgres - Audit Log",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO qms_audit_log (customer_id, event_type, document_id, severity, iso_ref, sla_deadline, owner_email, logged_at) VALUES ('{{ $json.customer_id }}', '{{ $json.event_type }}', '{{ $json.document_id }}', '{{ $json.severity }}', '{{ $json.iso_ref }}', '{{ $json.sla_deadline }}', '{{ $json.owner_email }}', NOW()) ON CONFLICT DO NOTHING"
}
}
],
"connections": {
"Webhook - QMS Event": {
"main": [
[
{
"node": "Code - Classify Change",
"type": "main",
"index": 0
}
]
]
},
"Code - Classify Change": {
"main": [
[
{
"node": "Slack - Route Alert",
"type": "main",
"index": 0
}
]
]
},
"Slack - Route Alert": {
"main": [
[
{
"node": "Gmail - Owner Alert",
"type": "main",
"index": 0
}
]
]
},
"Gmail - Owner Alert": {
"main": [
[
{
"node": "Postgres - Audit Log",
"type": "main",
"index": 0
}
]
]
}
}
}
Events handled: CAPA opened/overdue (ISO 13485 §8.5.2), design deviations (§8.3), IEC 62304 software change requests (§9.8), DHF document updates (21 CFR Part 820.30 Design Controls), SOC complaints (21 CFR Part 820.198), supplier audit findings (ISO 13485 §7.4.1), validation protocol deviations (FDA 21 CFR Part 820.75). Every event writes an immutable Postgres audit log — satisfying 21 CFR Part 11 §11.10(e).
Workflow 4: Post-Market Surveillance & Adverse Event Alert Pipeline
EU MDR Article 83 requires continuous post-market surveillance. FDA 21 CFR Part 803 mandates adverse event reporting within 30 days (malfunction) or 5 days (immediate risk). Missing these windows triggers Warning Letters and import alerts.
{
"name": "MedDevice Post-Market Surveillance Pipeline",
"nodes": [
{
"name": "Webhook - Adverse Event",
"type": "n8n-nodes-base.webhook",
"parameters": {
"path": "pms-adverse-event",
"httpMethod": "POST"
}
},
{
"name": "Code - Classify Event",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const ev = $input.first().json;\nconst event_type = ev.incident_type || 'MALFUNCTION';\nconst INCIDENT_MAP = {\n 'SERIOUS_INJURY': { reg: '21 CFR Part 803.50 / EU MDR Art.87(1)(a)', reporting_days: 30, channel: '#pms-critical', escalate: true, mdr_class: 'SERIOUS_INCIDENT' },\n 'DEATH': { reg: '21 CFR Part 803.50 / EU MDR Art.87(1)(a)', reporting_days: 30, channel: '#pms-critical', escalate: true, mdr_class: 'SERIOUS_INCIDENT' },\n 'UNANTICIPATED_SERIOUS_PERFORMANCE': { reg: 'EU MDR Art.87(1)(b)', reporting_days: 15, channel: '#pms-critical', escalate: true, mdr_class: 'SERIOUS_INCIDENT' },\n 'IMMINENT_SERIOUS_PUBLIC_HEALTH': { reg: '21 CFR Part 803.53 / EU MDR Art.87(2)', reporting_days: 2, channel: '#pms-critical', escalate: true, mdr_class: 'FIELD_SAFETY_CORRECTIVE_ACTION' },\n 'MALFUNCTION': { reg: '21 CFR Part 803.50(a)(2)', reporting_days: 30, channel: '#pms-ops', escalate: false, mdr_class: 'NON_SERIOUS_INCIDENT' },\n 'FSCA_INITIATED': { reg: 'EU MDR Art.89 / 21 CFR Part 806', reporting_days: 15, channel: '#pms-critical', escalate: true, mdr_class: 'FIELD_SAFETY_CORRECTIVE_ACTION' },\n 'UDI_DISCREPANCY': { reg: 'FDA UDI 21 CFR Part 830 / EU MDR Art.27', reporting_days: 30, channel: '#regulatory-ops', escalate: false, mdr_class: 'COMPLIANCE' }\n};\nconst info = INCIDENT_MAP[event_type] || INCIDENT_MAP['MALFUNCTION'];\nconst report_deadline = new Date(Date.now() + info.reporting_days * 86400000).toISOString();\nconst daysUntilDeadline = info.reporting_days;\nreturn [{ json: { ...ev, ...info, report_deadline, daysUntilDeadline, detected_at: new Date().toISOString(), event_id: `PMS-${Date.now()}-${Math.random().toString(36).substr(2,6).toUpperCase()}` } }];"
}
},
{
"name": "Slack - Immediate Alert",
"type": "n8n-nodes-base.slack",
"parameters": {
"channel": "={{ $json.channel }}",
"text": "=:rotating_light: PMS {{ $json.mdr_class }}\nEvent: {{ $json.incident_type }} | Device: {{ $json.device_model }} | Customer: {{ $json.customer_name }}\nReg: {{ $json.reg }} | Report deadline: {{ $json.report_deadline }} ({{ $json.daysUntilDeadline }} days)\nEvent ID: {{ $json.event_id }}"
}
},
{
"name": "Gmail - Regulatory Team",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "={{ $json.regulatory_contact }}",
"subject": "=[PMS {{ $json.mdr_class }}] {{ $json.incident_type }} \u2014 Reporting Required by {{ $json.report_deadline }}",
"message": "=Post-Market Surveillance Alert\n\nEvent ID: {{ $json.event_id }}\nIncident Type: {{ $json.incident_type }}\nMDR Class: {{ $json.mdr_class }}\nDevice: {{ $json.device_model }}\nLot/UDI: {{ $json.lot_number }}\nPatient Impact: {{ $json.patient_impact || 'Under investigation' }}\n\nRegulatory Obligation: {{ $json.reg }}\nReport Deadline: {{ $json.report_deadline }}\nDays Remaining: {{ $json.daysUntilDeadline }}\n\nInitiate your MDR/EUDAMED filing immediately."
}
},
{
"name": "Postgres - PMS Audit Trail",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "INSERT INTO pms_adverse_events (event_id, customer_id, incident_type, device_model, lot_number, mdr_class, regulatory_citation, report_deadline, detected_at) VALUES ('{{ $json.event_id }}', '{{ $json.customer_id }}', '{{ $json.incident_type }}', '{{ $json.device_model }}', '{{ $json.lot_number }}', '{{ $json.mdr_class }}', '{{ $json.reg }}', '{{ $json.report_deadline }}', NOW()) ON CONFLICT (event_id) DO NOTHING"
}
}
],
"connections": {
"Webhook - Adverse Event": {
"main": [
[
{
"node": "Code - Classify Event",
"type": "main",
"index": 0
}
]
]
},
"Code - Classify Event": {
"main": [
[
{
"node": "Slack - Immediate Alert",
"type": "main",
"index": 0
}
]
]
},
"Slack - Immediate Alert": {
"main": [
[
{
"node": "Gmail - Regulatory Team",
"type": "main",
"index": 0
}
]
]
},
"Gmail - Regulatory Team": {
"main": [
[
{
"node": "Postgres - PMS Audit Trail",
"type": "main",
"index": 0
}
]
]
}
}
}
Incident types handled: Serious injury/death (21 CFR Part 803.50 — 30 days, EU MDR Art.87(1)(a)), unanticipated serious performance degradation (EU MDR Art.87(1)(b) — 15 days), imminent serious public health threat (FDA 21 CFR Part 803.53 / EU MDR Art.87(2) — 2-day emergency window), device malfunctions, FSCAs (EU MDR Art.89 / 21 CFR Part 806), and UDI discrepancies. Immutable Postgres audit trail for FDA inspections.
Workflow 5: Weekly MedDevice Platform KPI Dashboard
Your executive team, QA director, and regulatory affairs lead all need different views of the same platform health data. This workflow pulls from two database views and sends a formatted HTML digest every Monday morning.
{
"name": "MedDevice Weekly KPI Dashboard",
"nodes": [
{
"name": "Schedule - Monday 7AM",
"type": "n8n-nodes-base.scheduleTrigger",
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 7 * * 1"
}
]
}
}
},
{
"name": "Postgres - Platform Metrics",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(*) as total_customers, SUM(CASE WHEN status='ACTIVE' THEN 1 ELSE 0 END) as active_customers, SUM(CASE WHEN status='TRIAL' THEN 1 ELSE 0 END) as trial_customers, SUM(CASE WHEN created_at >= NOW() - INTERVAL '7 days' THEN 1 ELSE 0 END) as new_this_week, SUM(monthly_arr_usd) as total_arr_usd FROM customer_accounts WHERE status IN ('ACTIVE','TRIAL')"
}
},
{
"name": "Postgres - Compliance Metrics",
"type": "n8n-nodes-base.postgres",
"parameters": {
"operation": "executeQuery",
"query": "SELECT COUNT(*) as total_open_capas, SUM(CASE WHEN severity='CRITICAL' THEN 1 ELSE 0 END) as critical_capas, SUM(CASE WHEN status='OVERDUE' THEN 1 ELSE 0 END) as overdue_items, SUM(CASE WHEN deadline_date BETWEEN NOW() AND NOW() + INTERVAL '30 days' THEN 1 ELSE 0 END) as deadlines_30d, COUNT(DISTINCT customer_id) as customers_with_open_issues FROM regulatory_deadlines WHERE status = 'OPEN'"
}
},
{
"name": "Merge",
"type": "n8n-nodes-base.merge",
"parameters": {
"mode": "mergeByPosition"
}
},
{
"name": "Code - Build HTML Report",
"type": "n8n-nodes-base.code",
"parameters": {
"jsCode": "const platform = $input.all()[0].json;\nconst compliance = $input.all()[1].json;\nconst riskFlag = compliance.critical_capas > 0 || compliance.overdue_items > 3 ? ':rotating_light: COMPLIANCE RISK \u2014 ' : '';\nconst html = `<h2>${riskFlag}MedDevice Platform \u2014 Weekly KPI Report</h2><p>Week of ${new Date().toISOString().split('T')[0]}</p><h3>Platform Health</h3><table border=1><tr><th>Metric</th><th>Value</th></tr><tr><td>Active Customers</td><td>${platform.active_customers}</td></tr><tr><td>Trial Customers</td><td>${platform.trial_customers}</td></tr><tr><td>New This Week</td><td>${platform.new_this_week}</td></tr><tr><td>Total ARR</td><td>$${parseInt(platform.total_arr_usd || 0).toLocaleString()}</td></tr></table><h3>Compliance Dashboard</h3><table border=1><tr><th>Metric</th><th>Value</th></tr><tr><td>Open CAPAs</td><td>${compliance.total_open_capas}</td></tr><tr><td>Critical CAPAs</td><td><b style='color:red'>${compliance.critical_capas}</b></td></tr><tr><td>Overdue Regulatory Items</td><td><b style='color:${compliance.overdue_items > 0 ? 'red' : 'green'}'>${compliance.overdue_items}</b></td></tr><tr><td>Deadlines Next 30 Days</td><td>${compliance.deadlines_30d}</td></tr><tr><td>Customers With Open Issues</td><td>${compliance.customers_with_open_issues}</td></tr></table>`;\nreturn [{ json: { html, platform, compliance, riskFlag: !!riskFlag } }];"
}
},
{
"name": "Gmail - Weekly Report",
"type": "n8n-nodes-base.gmail",
"parameters": {
"operation": "send",
"toList": "ceo@yourcompany.com",
"ccList": "regulatory-affairs@yourcompany.com,qa-director@yourcompany.com",
"subject": "=MedDevice Platform Weekly KPI \u2014 {{ new Date().toISOString().split('T')[0] }}{{ $json.riskFlag ? ' [COMPLIANCE ALERT]' : '' }}",
"message": "={{ $json.html }}"
}
}
],
"connections": {
"Schedule - Monday 7AM": {
"main": [
[
{
"node": "Postgres - Platform Metrics",
"type": "main",
"index": 0
}
],
[
{
"node": "Postgres - Compliance Metrics",
"type": "main",
"index": 0
}
]
]
},
"Postgres - Platform Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
}
]
]
},
"Postgres - Compliance Metrics": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Code - Build HTML Report",
"type": "main",
"index": 0
}
]
]
},
"Code - Build HTML Report": {
"main": [
[
{
"node": "Gmail - Weekly Report",
"type": "main",
"index": 0
}
]
]
}
}
}
Data sources: Pulls from two Postgres views — platform metrics (customer counts, ARR, trial pipeline) and compliance metrics (open CAPAs, critical items, overdue regulatory deadlines, 30-day horizon). Sends HTML email to CEO with CC to Regulatory Affairs and QA Director. Flags compliance risk in subject line if critical CAPAs are open.
n8n vs Zapier/Make.com for MedDevice SaaS
| Factor | n8n (self-hosted) | Zapier/Make.com |
|---|---|---|
| 21 CFR Part 11 audit trail | Git-versioned workflows, execution logs | No — cloud-run, not CFR Part 11 compliant |
| ISO 13485 document control | Workflow JSON = documented process | No equivalent version control |
| Data residency (GDPR/MDR) | On your VPC — data never leaves | US cloud servers — MDR Art.82 concern |
| SOC 2 CC6.1 vendor risk | Not a vendor — you own it | Listed as vendor in SOC 2 scope |
| Custom regulatory logic | Code node — any complexity | Limited to pre-built steps |
| Cost at scale | Fixed server cost | Per-task pricing explodes at volume |
When an enterprise medical device manufacturer asks "does your software send our DHF documents to a cloud platform?", the answer with n8n is no.
Get These Workflows
All five workflows above — plus 9 more for medical device and life sciences operations — are in the FlowKit n8n Template Collection at stripeai.gumroad.com.
Templates include:
- Import-ready JSON (paste directly into n8n)
- Setup guide (which Postgres views/Sheets columns to create)
- Configuration checklist for your regulatory requirements
If you found this useful, follow @flowkithq — I publish vertical-specific n8n automation guides every week.
Tags: n8n, medical device, automation, regulatory
Top comments (0)