n8n for European InsurTech & Reinsurance: 5 Automations for Solvency II, EIOPA, Lloyd's, and GDPR Article 9 (Free Workflow JSON)
European insurance technology teams — carrier software vendors, Lloyd's syndicate management platforms, reinsurance analytics SaaS, EU compliance tool companies — operate under a layered regulatory stack that most workflow automation tools weren't designed to handle.
Solvency II Pillar 3 requires XBRL-formatted reports submitted through EIOPA's Euclid portal using taxonomy versions that change every 12–18 months. If your automation tool doesn't adapt when EIOPA releases taxonomy 2.9.0, every QRT submission fails silently.
Lloyd's of London requires syndicate data to flow through Corporation-approved infrastructure (Crystal, Velonetic, DCOM). Routing syndicate bordereau or SBF submissions through Zapier creates audit trail gaps that Lloyd's Corporation can flag during annual oversight reviews.
GDPR Article 9 applies specifically to insurance: health data in underwriting, biometric fraud detection, genetic risk assessment. Routing this data through a US-hosted SaaS tool (Zapier, Make.com) requires GDPR Chapter V transfer mechanisms — and since Schrems II, those mechanisms carry residual US FISA Section 702 surveillance risk that EU DPAs are actively scrutinising.
Here are five complete n8n workflows — all with import-ready JSON — for European InsurTech and reinsurance teams.
Workflow 1: Solvency II QRT / ORSA / SFCR Deadline Tracker
What it does: Reads a Google Sheet of Solvency II and EIOPA reporting deadlines — QRTs quarterly, ORSA annually, SFCR publicly, RSR triennial, MCR quarterly, Lloyd's SBF quarterly, IDD POG annual review — and fires tiered alerts (OVERDUE / CRITICAL ≤7d / URGENT ≤14d / WARNING ≤30d) to Slack and the deadline owner's email.
Why Solvency II is automation-critical:
- EIOPA's Euclid portal uses XBRL taxonomy versions (currently 2.8.0) that change on a release cycle. QRT template IDs shift between taxonomy versions — automation built against 2.7.0 breaks on 2.8.0 submission without code-level update.
- Pillar 3 has 65+ QRT templates (S.01 through S.99 series) across Solvency I/II solo and group reporting. Tracking deadlines across solo + group + national-specific extras in a spreadsheet creates gaps.
- MCR breach triggers a supervisory ladder-of-intervention under Art.138 — automation gives teams 30-day warning before breach to arrange capital action.
Import JSON:
{
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "days",
"daysInterval": 1
}
]
},
"triggerAtHour": 7
},
"id": "solvency-ii-cron",
"name": "Weekdays 7 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
240,
300
]
},
{
"parameters": {
"operation": "read",
"documentId": "YOUR_SOLVENCY_SHEETS_ID",
"sheetName": "Sheet1"
},
"id": "solvency-sheets",
"name": "Read QRT Deadlines",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4,
"position": [
460,
300
]
},
{
"parameters": {
"jsCode": "\nconst today = new Date();\nconst items = $input.all();\nconst results = [];\nconst alerted = new Set();\n\nconst actionMap = {\n 'SOLVENCY_II_QRT_QUARTERLY': { owner: 'ActuarialTeam', portal: 'euclid.eiopa.europa.eu', note: 'Submit via EIOPA Euclid taxonomy S.01-S.99 quarterly templates' },\n 'SOLVENCY_II_ORSA_ANNUAL': { owner: 'ChiefRiskOfficer', portal: 'internal', note: 'Own Risk and Solvency Assessment \u2014 Board sign-off required' },\n 'SOLVENCY_II_SFCR_ANNUAL': { owner: 'ComplianceDirector', portal: 'national-nca.eu', note: 'Solvency and Financial Condition Report \u2014 public disclosure' },\n 'SOLVENCY_II_RSR_TRIENNIAL': { owner: 'ChiefRiskOfficer', portal: 'national-nca.eu', note: 'Regular Supervisory Report \u2014 triennial full + interim annual updates' },\n 'SOLVENCY_II_MCR_QUARTERLY': { owner: 'CFO', portal: 'euclid.eiopa.europa.eu', note: 'Minimum Capital Requirement quarterly calculation \u2014 breach triggers supervisory ladder' },\n 'EIOPA_PENSION_IORP_II_ANNUAL': { owner: 'PensionsTrustee', portal: 'euclid.eiopa.europa.eu', note: 'IORP II Directive occupational pensions annual reporting' },\n 'IDD_POG_ANNUAL_REVIEW': { owner: 'ProductGovernanceOfficer', portal: 'fca.org.uk/firms', note: 'Insurance Distribution Directive product oversight & governance annual review' },\n 'LLOYD_SBF_QUARTERLY': { owner: 'SyndicateCFO', portal: 'lloyds.com/market-resources', note: \"Lloyd's Syndicate Business Forecast quarterly submission to Lloyd's Corporation\" },\n 'LLOYD_DCA_ANNUAL': { owner: 'UnderwritingManager', portal: 'lloyds.com/delegated-authority', note: \"Lloyd's Delegated Contract Authority annual oversight review (Velonetic/DCOM)\" },\n 'GDPR_ART9_ANNUAL_DPIA': { owner: 'DataProtectionOfficer', portal: 'internal', note: 'GDPR Article 9 DPIA annual refresh \u2014 health data in underwriting triggers mandatory DPIA' },\n 'REINSURANCE_CONTRACT_RENEWAL': { owner: 'ReinsuranceManager', portal: 'internal', note: 'Treaty reinsurance contract renewal \u2014 cedant bordereau submission deadlines' },\n 'NCA_PILLAR2_DIALOGUE': { owner: 'ChiefActuary', portal: 'national-nca.eu', note: 'National Competent Authority Pillar 2 supervisory dialogue cycle' },\n};\n\nfor (const item of items) {\n const d = item.json;\n const dueDate = new Date(d.due_date);\n const daysLeft = Math.floor((dueDate - today) / 86400000);\n const key = d.deadline_type + '_' + d.due_date;\n \n if (alerted.has(key) && d.alert_sent_date) continue;\n \n let tier = null;\n let emoji = '';\n if (daysLeft < 0) { tier = 'OVERDUE'; emoji = '\ud83d\udd34'; }\n else if (daysLeft <= 7) { tier = 'CRITICAL'; emoji = '\ud83d\udea8'; }\n else if (daysLeft <= 14) { tier = 'URGENT'; emoji = '\u26a0\ufe0f'; }\n else if (daysLeft <= 30) { tier = 'WARNING'; emoji = '\ud83d\udfe1'; }\n else if (daysLeft <= 60) { tier = 'NOTICE'; emoji = '\ud83d\udcc5'; }\n \n if (!tier) continue;\n \n const action = actionMap[d.deadline_type] || { owner: 'ComplianceTeam', portal: 'internal', note: '' };\n alerted.add(key);\n results.push({ json: { ...d, daysLeft, tier, emoji, action, key } });\n}\nreturn results;\n"
},
"id": "solvency-code",
"name": "Classify Deadlines",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.tier }}",
"rightValue": "NOTICE",
"operator": {
"type": "string",
"operation": "notEquals"
}
}
]
}
},
"id": "solvency-filter",
"name": "Filter Actionable",
"type": "n8n-nodes-base.filter",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#solvency-ii-compliance",
"mode": "name"
},
"text": "={{ $json.emoji }} *Solvency II / EIOPA {{ $json.tier }}* \u2014 {{ $json.deadline_type }}\n*Days left:* {{ $json.daysLeft < 0 ? 'OVERDUE by ' + Math.abs($json.daysLeft) + ' days' : $json.daysLeft + ' days' }}\n*Due:* {{ $json.due_date }}\n*Owner:* {{ $json.action.owner }}\n*Portal:* {{ $json.action.portal }}\n*Note:* {{ $json.action.note }}",
"otherOptions": {}
},
"id": "solvency-slack",
"name": "Alert Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
1120,
240
]
},
{
"parameters": {
"fromEmail": "compliance@yourinsurtech.com",
"toEmail": "={{ $json.action.owner }}@yourinsurtech.com",
"subject": "={{ $json.emoji }} Solvency II {{ $json.tier }}: {{ $json.deadline_type }} due {{ $json.due_date }}",
"emailType": "text",
"message": "Regulatory deadline alert\\n\\nType: {{ $json.deadline_type }}\\nStatus: {{ $json.tier }} ({{ $json.daysLeft }} days remaining)\\nPortal: {{ $json.action.portal }}\\nNote: {{ $json.action.note }}\\n\\nEIOPA Euclid taxonomy version must match the submission window \u2014 check EIOPA website for current taxonomy release before submitting QRTs."
},
"id": "solvency-email",
"name": "Email Owner",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
1120,
360
]
}
],
"connections": {
"Weekdays 7 AM": {
"main": [
[
{
"node": "Read QRT Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Read QRT Deadlines": {
"main": [
[
{
"node": "Classify Deadlines",
"type": "main",
"index": 0
}
]
]
},
"Classify Deadlines": {
"main": [
[
{
"node": "Filter Actionable",
"type": "main",
"index": 0
}
]
]
},
"Filter Actionable": {
"main": [
[
{
"node": "Alert Slack",
"type": "main",
"index": 0
},
{
"node": "Email Owner",
"type": "main",
"index": 0
}
]
]
}
}
}
Spreadsheet columns: deadline_type, due_date, owner_email, alert_sent_date
Workflow 2: EIOPA Portal & Regulatory API Health Monitor
What it does: Polls EIOPA Euclid, your internal XBRL taxonomy validator, NCA national portal, Lloyd's Crystal, and reinsurance bordereau API every 15 minutes. Uses $getWorkflowStaticData to detect state transitions (OK → DOWN) and fires only on change — no alert fatigue.
The taxonomy version problem:
EIOPA releases taxonomy updates that change XBRL namespace declarations. A QRT submission attempt against an outdated taxonomy returns a validation error at the Euclid portal level, not at your API level — the health check must validate the correct taxonomy version is loaded, not just that the endpoint is reachable.
Import JSON:
{
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 15
}
]
}
},
"id": "eiopa-cron",
"name": "Every 15 Minutes",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "\nconst endpoints = [\n { name: 'EIOPA Euclid Portal', url: 'https://euclid.eiopa.europa.eu/api/health', type: 'QRT_SUBMISSION', regulation: 'Solvency II Pillar 3 Art.35' },\n { name: 'XBRL Taxonomy Service', url: 'https://eiopa-taxonomy.internal/validate', type: 'XBRL_VALIDATION', regulation: 'EIOPA Taxonomy 2.8.0 QRT templates' },\n { name: 'NCA National Portal', url: 'https://nca-portal.internal/api/status', type: 'NCA_SUBMISSION', regulation: 'National Competent Authority reporting' },\n { name: 'Lloyd's Crystal Portal', url: 'https://crystal.lloyds.com/api/ping', type: 'LLOYDS_CRYSTAL', regulation: \"Lloyd's Delegated Data Manager / Crystal reporting\" },\n { name: 'Reinsurance Bordereau API', url: 'https://reinsa.internal/bordereau/health', type: 'REINSURANCE_BORDEREAU', regulation: 'Treaty cedant bordereau submission' },\n];\nreturn endpoints.map(e => ({ json: e }));\n"
},
"id": "eiopa-endpoints",
"name": "Build Endpoints",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"url": "={{ $json.url }}",
"options": {
"timeout": 8000,
"response": {
"response": {
"responseFormat": "text"
}
}
}
},
"id": "eiopa-http",
"name": "Health Check",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
680,
300
],
"continueOnFail": true
},
{
"parameters": {
"jsCode": "\nconst item = $input.first().json;\nconst staticData = $getWorkflowStaticData('global');\nconst prevState = staticData[item.type] || 'OK';\nconst httpOk = !item.error && item.statusCode >= 200 && item.statusCode < 300;\nconst currentState = httpOk ? 'OK' : 'DOWN';\n\nif (prevState === currentState) return [];\nstaticData[item.type] = currentState;\n\nconst severity = currentState === 'DOWN' ? 'CRITICAL' : 'RECOVERED';\nreturn [{ json: { ...item, previousState: prevState, currentState, severity, ts: new Date().toISOString() } }];\n"
},
"id": "eiopa-state",
"name": "Detect State Change",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
900,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#platform-integrations",
"mode": "name"
},
"text": "={{ $json.severity === 'CRITICAL' ? '\ud83d\udd34' : '\u2705' }} *{{ $json.name }}* {{ $json.severity }}\\n*Regulation:* {{ $json.regulation }}\\n*State:* {{ $json.previousState }} \u2192 {{ $json.currentState }}\\n*Time:* {{ $json.ts }}\\n{{ $json.severity === 'CRITICAL' ? '\u26a1 Solvency II QRT submissions blocked \u2014 check EIOPA Euclid taxonomy version match' : '\u2705 Integration restored' }}",
"otherOptions": {}
},
"id": "eiopa-slack",
"name": "Alert Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
1120,
300
]
}
],
"connections": {
"Every 15 Minutes": {
"main": [
[
{
"node": "Build Endpoints",
"type": "main",
"index": 0
}
]
]
},
"Build Endpoints": {
"main": [
[
{
"node": "Health Check",
"type": "main",
"index": 0
}
]
]
},
"Health Check": {
"main": [
[
{
"node": "Detect State Change",
"type": "main",
"index": 0
}
]
]
},
"Detect State Change": {
"main": [
[
{
"node": "Alert Slack",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 3: Lloyd's Syndicate Event Alert Pipeline
What it does: Webhook receiver for Lloyd's syndicate events — SBF rejections, DCA audit notices, capacity breaches, IBA cash calls, reinsurance bordereau late submissions, GDPR breaches involving Lloyd's underwriting data. Routes each event to the correct Slack channel with regulatory context and deadline.
Why Lloyd's is different from standard insurance:
- Lloyd's SBF (Syndicate Business Forecast) submitted quarterly to Corporation via Crystal must balance against FAL (Funds at Lloyd's) calculations. Late or rejected SBF triggers an automatic capacity review.
- DCA (Delegated Contract Authority) arrangements require annual oversight reviews under Velonetic's DCOM system. Gaps in DCA audit documentation trigger Lloyd's Market Bulletin remediation requirements (Y5000 series).
- IBA (Insurance Broking Accounting) cash calls have same-day settlement windows at Lloyd's Online — a 2-hour response requirement that no scheduled-polling automation can reliably meet.
Import JSON:
{
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "lloyd-syndicate-event",
"options": {}
},
"id": "lloyd-webhook",
"name": "Lloyd's Event Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "\nconst item = $input.first().json;\nconst eventType = item.event_type;\nconst ts = new Date().toISOString();\n\nconst routingMap = {\n 'LLOYD_SBF_REJECTION': { channel: '#crystal-submissions', severity: 'CRITICAL', deadline_hours: 48, action: \"Resubmit corrected SBF to Lloyd's Crystal before next business day\", regulation: \"Lloyd's SBF submission rules \u2014 MD-GEN-0033\" },\n 'LLOYD_DCA_AUDIT_NOTICE': { channel: '#delegated-authority', severity: 'URGENT', deadline_hours: 72, action: \"Prepare DCA audit evidence pack (bordereaux, claims registers, underwriting authorities)\", regulation: \"Lloyd's Delegated Underwriting \u2014 Market Bulletin Y5000 series\" },\n 'LLOYD_CAPACITY_BREACH': { channel: '#syndicate-finance', severity: 'CRITICAL', deadline_hours: 4, action: \"Notify Lloyd's Corporation Finance \u2014 capacity utilisation breach triggers FAL review\", regulation: \"Lloyd's Capacity Regulations 2024\" },\n 'REINSURANCE_BORDEREAU_LATE': { channel: '#reinsurance-ops', severity: 'HIGH', deadline_hours: 24, action: \"Submit outstanding cedant bordereau \u2014 late submission triggers treaty penalty clause\", regulation: \"Treaty reinsurance contract Article 12 \u2014 reporting obligations\" },\n 'LLOYD_IBA_CASHCALL': { channel: '#syndicate-finance', severity: 'CRITICAL', deadline_hours: 2, action: \"Process IBA cash call via Lloyd's Online \u2014 funds must clear before settlement window closes\", regulation: \"Lloyd's IBA Settlement Rules\" },\n 'GDPR_UNDERWRITING_DATA_BREACH': { channel: '#dpo-urgent', severity: 'CRITICAL', deadline_hours: 72, action: \"Notify relevant DPA within 72h \u2014 Lloyd's underwriting data crosses EEA/UK border routinely; check transfer mechanism\", regulation: \"GDPR Art.33 / UK GDPR Art.33 \u2014 72h supervisory authority notification\" },\n 'EIOPA_SCR_BREACH': { channel: '#cro-alerts', severity: 'CRITICAL', deadline_hours: 1, action: \"Immediate CRO and CFO notification \u2014 SCR breach triggers supervisory ladder-of-intervention (IAMRA MoU)\", regulation: \"Solvency II Art.138 \u2014 supervisory powers on SCR non-compliance\" },\n};\n\nconst route = routingMap[eventType] || { channel: '#compliance-ops', severity: 'MEDIUM', deadline_hours: 24, action: 'Review and route to appropriate team', regulation: 'Unknown regulatory requirement' };\nconst deadlineTs = new Date(Date.now() + route.deadline_hours * 3600000).toISOString();\nconst dedup_key = eventType + '_' + Math.floor(Date.now() / 1800000);\n\nreturn [{ json: { ...item, ...route, deadlineTs, dedup_key, ts } }];\n"
},
"id": "lloyd-route",
"name": "Route Event",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "={{ $json.channel }}",
"mode": "name"
},
"text": "={{ $json.severity === 'CRITICAL' ? '\ud83d\udd34 @here' : $json.severity === 'URGENT' ? '\ud83d\udfe0' : '\u26a0\ufe0f' }} *Lloyd's/Reinsurance {{ $json.severity }}*: {{ $json.event_type }}\\n*Action:* {{ $json.action }}\\n*Deadline:* {{ $json.deadlineTs }} ({{ $json.deadline_hours }}h)\\n*Regulation:* {{ $json.regulation }}",
"otherOptions": {}
},
"id": "lloyd-slack",
"name": "Route to Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
680,
300
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ received: true, event_type: $json.event_type, deadline: $json.deadlineTs }) }}"
},
"id": "lloyd-respond",
"name": "ACK 200",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
680,
460
]
}
],
"connections": {
"Lloyd's Event Webhook": {
"main": [
[
{
"node": "Route Event",
"type": "main",
"index": 0
}
]
]
},
"Route Event": {
"main": [
[
{
"node": "Route to Slack",
"type": "main",
"index": 0
},
{
"node": "ACK 200",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 4: GDPR Article 9 Special Category Data Incident Pipeline
What it does: Webhook trigger for Art.9 special category data events — health data in underwriting, biometric fraud detection, genetic risk assessment, mental health claims, disability assessment. Looks up the correct DPA (by country code), calculates the 72-hour notification deadline, alerts the DPO Slack channel, and emails the legal team with the DPA contact and regulatory context.
Why Art.9 matters specifically in insurance:
- Insurance underwriting routinely processes health data (medical history, disability records, mental health history) — this is GDPR Article 9 special category data requiring an explicit processing basis under Art.9(2).
- DPIA (Data Protection Impact Assessment) is mandatory under Art.35 for systematic health data processing. Automating the incident pipeline ensures DPIA records are updated on every event.
- The Zapier/cloud routing problem: Health underwriting data routed through Zapier (US-hosted) is an international transfer under GDPR Chapter V. Post-Schrems II, Standard Contractual Clauses are theoretically available but EU DPAs have flagged US FISA Section 702 government access as incompatible with SCCs for sensitive personal data. Self-hosted n8n keeps health data inside your EEA infrastructure.
Import JSON:
{
"nodes": [
{
"parameters": {
"httpMethod": "POST",
"path": "gdpr-art9-incident",
"options": {}
},
"id": "gdpr-webhook",
"name": "GDPR Art.9 Incident Webhook",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
240,
300
]
},
{
"parameters": {
"jsCode": "\nconst item = $input.first().json;\nconst dataType = item.data_type;\nconst country = item.country_code || 'EU';\nconst ts = new Date().toISOString();\nconst dedup = $getWorkflowStaticData('global');\nconst key = dataType + '_' + Math.floor(Date.now() / 1800000);\nif (dedup[key]) return [];\ndedup[key] = true;\n\nconst dpaMap = {\n 'DE': { authority: 'BfDI / L\u00e4nder DPA', email: 'poststelle@bfdi.bund.de', deadline_hours: 72 },\n 'FR': { authority: 'CNIL', email: 'notifications@cnil.fr', deadline_hours: 72 },\n 'NL': { authority: 'AP (Autoriteit Persoonsgegevens)', email: 'avg-meldingen@autoriteitpersoonsgegevens.nl', deadline_hours: 72 },\n 'BE': { authority: 'APD / GBA', email: 'contact@apd-gba.be', deadline_hours: 72 },\n 'IT': { authority: 'Garante Privacy', email: 'protocollo@gpdp.it', deadline_hours: 72 },\n 'GB': { authority: 'ICO (UK GDPR)', email: 'casework@ico.org.uk', deadline_hours: 72 },\n 'IE': { authority: 'DPC Ireland', email: 'info@dataprotection.ie', deadline_hours: 72 },\n};\nconst dpa = dpaMap[country] || { authority: 'Lead Supervisory Authority', email: 'dpa@authority.eu', deadline_hours: 72 };\nconst deadline = new Date(Date.now() + dpa.deadline_hours * 3600000).toISOString();\n\nconst art9Types = {\n 'HEALTH_UNDERWRITING_DATA': { severity: 'CRITICAL', note: 'Art.9(2)(a) \u2014 explicit consent required for health data in underwriting. Art.9 breach = mandatory DPA notification even if <250 data subjects.' },\n 'BIOMETRIC_FRAUD_DETECTION': { severity: 'CRITICAL', note: 'Art.9(2)(b) \u2014 biometric data for fraud detection. Requires Art.35 DPIA.' },\n 'GENETIC_RISK_ASSESSMENT': { severity: 'CRITICAL', note: 'Art.9 genetic data \u2014 insurance underwriting using genetic data prohibited in many EEA states.' },\n 'MENTAL_HEALTH_CLAIMS': { severity: 'HIGH', note: 'Health category \u2014 mental health data in claims processing. Special category safeguards apply.' },\n 'DISABILITY_ASSESSMENT': { severity: 'HIGH', note: 'Disability data (Art.9) \u2014 equal treatment obligations under EU Charter Art.21.' },\n};\nconst art9 = art9Types[dataType] || { severity: 'HIGH', note: 'Special category data \u2014 verify Art.9 processing basis' };\n\nreturn [{ json: { ...item, ...dpa, ...art9, deadline, dedup_key: key, ts } }];\n"
},
"id": "gdpr-code",
"name": "Classify & Route",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
460,
300
]
},
{
"parameters": {
"select": "channel",
"channelId": {
"__rl": true,
"value": "#dpo-critical",
"mode": "name"
},
"text": "\ud83d\udd34 *GDPR Article 9 Breach* \u2014 Special Category Data\\n*Type:* {{ $json.data_type }}\\n*Country:* {{ $json.country_code }}\\n*DPA:* {{ $json.authority }}\\n*DPA Email:* {{ $json.email }}\\n*72h Deadline:* {{ $json.deadline }}\\n*Note:* {{ $json.note }}",
"otherOptions": {}
},
"id": "gdpr-slack",
"name": "Alert DPO Slack",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.1,
"position": [
680,
260
]
},
{
"parameters": {
"fromEmail": "dpo@yourinsurtech.com",
"toEmail": "legal@yourinsurtech.com",
"subject": "GDPR Art.9 CRITICAL: {{ $json.data_type }} breach \u2014 72h DPA notification clock started",
"emailType": "text",
"message": "GDPR Article 9 Special Category Data Incident\\n\\nData Type: {{ $json.data_type }}\\nCountry: {{ $json.country_code }}\\nDPA: {{ $json.authority }}\\nDPA Contact: {{ $json.email }}\\nDeadline: {{ $json.deadline }}\\n\\nNote: {{ $json.note }}\\n\\nAction Required: Notify {{ $json.authority }} within 72 hours per GDPR Art.33. For insurance companies routing health underwriting data through Zapier (a US-hosted service), verify GDPR Chapter V transfer mechanism \u2014 Schrems II invalidated Privacy Shield; Standard Contractual Clauses must account for US FISA Section 702 access risk."
},
"id": "gdpr-email",
"name": "Email Legal Team",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
680,
380
]
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={\"received\": true, \"deadline\": \"{{ $json.deadline }}\", \"dpa\": \"{{ $json.authority }}\"}"
},
"id": "gdpr-respond",
"name": "ACK 200",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1,
"position": [
680,
500
]
}
],
"connections": {
"GDPR Art.9 Incident Webhook": {
"main": [
[
{
"node": "Classify & Route",
"type": "main",
"index": 0
}
]
]
},
"Classify & Route": {
"main": [
[
{
"node": "Alert DPO Slack",
"type": "main",
"index": 0
},
{
"node": "Email Legal Team",
"type": "main",
"index": 0
},
{
"node": "ACK 200",
"type": "main",
"index": 0
}
]
]
}
}
}
Workflow 5: Weekly EU InsurTech KPI Dashboard
What it does: Monday 8 AM — queries your EU InsurTech KPI database (SCR coverage ratio, MCR status, EIOPA submission queue, open QRTs, GDPR Art.9 incidents, Lloyd's Crystal submission status), builds a colour-coded HTML table with WoW percentage changes, and emails CEO/CFO with CRO BCC. Subject line is flagged [SCR BREACH] or [GDPR ART.9] when those conditions are live.
Import JSON:
{
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"weeksInterval": 1
}
]
},
"triggerAtDay": [
1
],
"triggerAtHour": 8
},
"id": "eu-kpi-cron",
"name": "Monday 8 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [
240,
300
]
},
{
"parameters": {
"operation": "executeQuery",
"query": "SELECT metric_name, metric_value, week_ago_value, ROUND((metric_value - week_ago_value) * 100.0 / NULLIF(week_ago_value, 0), 1) AS wow_pct FROM eu_insurtech_kpis WHERE report_date = CURRENT_DATE ORDER BY sort_order"
},
"id": "eu-kpi-db",
"name": "Read EU KPIs",
"type": "n8n-nodes-base.postgres",
"typeVersion": 2.5,
"position": [
460,
300
]
},
{
"parameters": {
"jsCode": "\nconst rows = $input.all().map(i => i.json);\nconst ts = new Date().toISOString().split('T')[0];\n\nlet solvencyBreach = false;\nlet gdprIncident = false;\n\nconst tableRows = rows.map(r => {\n const trend = r.wow_pct > 0 ? '\u25b2' : r.wow_pct < 0 ? '\u25bc' : '\u2013';\n const color = r.metric_name.includes('SCR') && r.metric_value < 100 ? '#FF0000' : r.metric_name.includes('GDPR') && r.metric_value > 0 ? '#FF6600' : '#28a745';\n if (r.metric_name === 'SCR_COVERAGE_RATIO' && r.metric_value < 100) solvencyBreach = true;\n if (r.metric_name === 'GDPR_ART9_INCIDENTS_OPEN' && r.metric_value > 0) gdprIncident = true;\n return `<tr><td>${r.metric_name}</td><td style=\"color:${color}\">${r.metric_value}</td><td>${trend} ${Math.abs(r.wow_pct)}%</td></tr>`;\n}).join('');\n\nconst subjectFlag = solvencyBreach ? '[SCR BREACH] ' : gdprIncident ? '[GDPR ART.9] ' : '';\n\nreturn [{ json: { tableRows, subjectFlag, ts, solvencyBreach, gdprIncident } }];\n"
},
"id": "eu-kpi-code",
"name": "Build Dashboard",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"fromEmail": "platform@yourinsurtech.com",
"toEmail": "ceo@yourinsurtech.com",
"ccEmail": "cfo@yourinsurtech.com",
"bccEmail": "cro@yourinsurtech.com",
"subject": "={{ $json.subjectFlag }}Weekly EU InsurTech KPI Dashboard \u2014 {{ $json.ts }}",
"emailType": "html",
"message": "<h2>EU InsurTech Platform \u2014 Weekly KPI Dashboard</h2><table border='1' cellpadding='6' style='border-collapse:collapse;font-family:Arial,sans-serif'><thead><tr><th>Metric</th><th>Value</th><th>WoW</th></tr></thead><tbody>{{ $json.tableRows }}</tbody></table><hr><p style='font-size:11px;color:#666'>Solvency II SCR breach triggers supervisory ladder-of-intervention under Art.138. GDPR Art.9 incidents require 72h DPA notification. Self-hosted n8n keeps all EU insurance data inside your EEA infrastructure \u2014 no GDPR Chapter V transfer risk.</p>"
},
"id": "eu-kpi-email",
"name": "Email KPI Dashboard",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2.1,
"position": [
900,
300
]
}
],
"connections": {
"Monday 8 AM": {
"main": [
[
{
"node": "Read EU KPIs",
"type": "main",
"index": 0
}
]
]
},
"Read EU KPIs": {
"main": [
[
{
"node": "Build Dashboard",
"type": "main",
"index": 0
}
]
]
},
"Build Dashboard": {
"main": [
[
{
"node": "Email KPI Dashboard",
"type": "main",
"index": 0
}
]
]
}
}
}
The Self-Hosted n8n Argument for EU InsurTech
| Requirement | Zapier/Make.com | Self-hosted n8n |
|---|---|---|
| EIOPA XBRL taxonomy version control | Redeploy required on every taxonomy release | Update taxonomy config file, restart service |
| GDPR Art.9 data residency | US-hosted — Chapter V transfer risk | EEA-hosted — no international transfer |
| Solvency II Art.35 audit trail retention | 30-day log limit | Unlimited retention — 40-year reinsurance contracts supported |
| Lloyd's Corporation oversight | Unapproved 3rd-party routing | Approved internal infrastructure path |
| GDPR Schrems II / FISA 702 | Risk remains even with SCCs | Eliminated — data never leaves EEA |
| NCA supervisory access to audit logs | Cannot provide | Git-versioned workflow JSON = NCA audit evidence |
Get the Complete Workflow Pack
These 5 workflows are part of the FlowKit n8n Automation Templates — 15 ready-to-import JSON files for compliance, operations, and customer management automation.
Browse all templates at stripeai.gumroad.com
Each template includes:
- Import-ready workflow JSON
- Setup guide (credentials, environment variables)
- Customisation notes for your specific regulatory environment
Questions? Drop them in the comments. I read every one.
Top comments (0)