DEV Community

Alex Kane
Alex Kane

Posted on

n8n for AI/ML Platform SaaS: 5 Automations for EU AI Act GPAI, GDPR Art.22, NIST AI RMF 2.0, FTC UDAP AI Claims (Free JSON)

Most AI/ML Platform SaaS vendors know their customers face AI regulation. What they underestimate is that their platform itself is subject to a separate compliance layer — one that activates the moment it processes a training record, serves a model inference, or logs a decision outcome.

This is for the engineering and compliance teams at AI/ML infrastructure vendors: MLOps platforms, generative AI API providers, AI governance tools, computer vision SaaS, NLP platforms, and AI decision systems. Your customers have regulatory obligations. But so does the platform that powers them.

The Compliance Stack Nobody Fully Maps

The EU AI Act (Regulation 2024/1689) is the most comprehensive AI-specific regulation now in force. It creates three distinct obligation layers that AI/ML Platform SaaS vendors rarely separate cleanly:

GPAI Model Provider obligations (Art.51-55): If your platform provides a general-purpose AI model — any model trained on broad data with general applicability — you are a GPAI provider. Art.51 requires registration. Art.53 requires technical documentation. Art.55 requires systemic risk evaluation for models above 10^25 FLOPs (approximately GPT-4-scale). This clock starts at training completion, not market launch.

High-Risk System obligations (Art.6, Annex III): Computer vision SaaS doing biometric categorization, emotion recognition, or identity verification is presumptively high-risk under Annex III. AI decision SaaS in credit scoring, hiring screening, or insurance underwriting is high-risk. High-risk systems require conformity assessments, post-market monitoring, and Art.73 serious incident reporting within 15 days to the applicable sectoral authority (EASA for aviation, EMSA for maritime, EBA for financial).

GDPR Art.22 automated decision obligations: Every AI decision system making legally significant automated decisions — without meaningful human review — creates an Art.22 obligation. The right to explanation, the right to contest, and the 1-month DSAR response window all start the moment the automated decision is made. Routing that decision event through a cloud iPaaS creates a subprocessor disclosure obligation and a chain-of-custody gap.

Then there is the US layer: FTC Section 5 UDAP applies to every AI performance claim in your marketing. "99% accuracy" requires substantiation before publication. "State-of-the-art" is a deceptive superlative without evidence. OMB M-24-10 requires federal agencies to maintain AI use case registries — if your platform serves federal customers, their compliance obligation creates a due diligence question about your documentation.

Five n8n workflows close the most common gaps. All five are import-ready JSON.

Workflow 1: EU AI Act GPAI Model Provider Compliance Monitor

What it does: Runs daily against your GPAI model registry in Postgres. For each active model, it checks: Art.51 registration status, Art.53 technical documentation completeness, and Art.55 systemic risk evaluation status for models above 10^25 FLOPs. Non-compliant models trigger a Slack alert to #ai-compliance with the specific flag (ART51_GPAI_NOT_REGISTERED, TECHNICAL_DOC_MISSING, ART55_SYSTEMIC_RISK_EVAL_REQUIRED). All results log to a gpai_compliance_log Postgres table with timestamp.

Why self-hosted n8n: The GPAI model registry contains your proprietary model capabilities, FLOPs estimates, and training data documentation — information that would constitute a significant competitive disclosure if it transited a third-party cloud automation layer. Self-hosted n8n keeps the compliance monitoring entirely within your VPC.

{
  "name": "EU AI Act GPAI Model Provider Compliance Monitor",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 24
            }
          ]
        }
      },
      "name": "Daily Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT model_id, model_name, flops_estimate, gpai_registration_status, technical_doc_complete, systemic_risk_evaluated FROM gpai_model_registry WHERE is_active = true",
        "options": {}
      },
      "name": "Query GPAI Registry",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const models = $input.all();\nconst SYSTEMIC_RISK_THRESHOLD = 1e25;\nconst results = models.map(item => {\n  const m = item.json;\n  const flops = parseFloat(m.flops_estimate) || 0;\n  const isSystemicRisk = flops >= SYSTEMIC_RISK_THRESHOLD;\n  const flags = [];\n  if (!m.technical_doc_complete) flags.push('TECHNICAL_DOC_MISSING');\n  if (isSystemicRisk && !m.systemic_risk_evaluated) flags.push('ART55_SYSTEMIC_RISK_EVAL_REQUIRED');\n  if (m.gpai_registration_status !== 'REGISTERED') flags.push('ART51_GPAI_NOT_REGISTERED');\n  return {\n    model_id: m.model_id,\n    model_name: m.model_name,\n    flops_estimate: m.flops_estimate,\n    is_systemic_risk: isSystemicRisk,\n    flags: flags,\n    compliance_status: flags.length === 0 ? 'COMPLIANT' : 'NON_COMPLIANT',\n    checked_at: new Date().toISOString()\n  };\n});\nreturn results.map(r => ({ json: r }));"
      },
      "name": "Assess GPAI Compliance",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "cond1",
              "leftValue": "={{ $json.compliance_status }}",
              "rightValue": "NON_COMPLIANT",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "Non-Compliant Filter",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        850,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#ai-compliance",
          "mode": "name"
        },
        "text": "=*EU AI Act GPAI Alert* \u2014 {{ $json.model_name }}\nStatus: {{ $json.compliance_status }}\nFlags: {{ $json.flags.join(', ') }}\nSystemic Risk (>10^25 FLOPs): {{ $json.is_systemic_risk }}\nRef: Regulation 2024/1689 Art.51-55",
        "otherOptions": {}
      },
      "name": "Slack AI Compliance Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        1050,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO gpai_compliance_log (model_id, model_name, is_systemic_risk, flags, compliance_status, checked_at) VALUES ('{{ $json.model_id }}', '{{ $json.model_name }}', {{ $json.is_systemic_risk }}, '{{ $json.flags.join(',') }}', '{{ $json.compliance_status }}', NOW()) ON CONFLICT DO NOTHING",
        "options": {}
      },
      "name": "Log GPAI Audit",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1050,
        400
      ]
    }
  ],
  "connections": {
    "Daily Schedule": {
      "main": [
        [
          {
            "node": "Query GPAI Registry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query GPAI Registry": {
      "main": [
        [
          {
            "node": "Assess GPAI Compliance",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assess GPAI Compliance": {
      "main": [
        [
          {
            "node": "Non-Compliant Filter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Non-Compliant Filter": {
      "main": [
        [
          {
            "node": "Slack AI Compliance Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log GPAI Audit",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 2: GDPR Art.22 Automated Decision Right-to-Explanation Handler

What it does: Webhook trigger fires when your AI system records a decision outcome. The Code node classifies whether the decision type has legal or significant effect (loan decision, hiring decision, insurance underwriting, credit scoring, benefit determination) and whether human review was available. If Art.22 applies — legal effect, no human review — it routes to a #gdpr-automated-decisions Slack alert with the 1-month DSAR deadline and logs the full decision record to art22_decision_log including decision_id, data_subject_id, decision_type, outcome, model_id, and dsar_deadline.

The clock that matters: GDPR Art.22 does not require that the data subject request an explanation. The obligation to offer human review is triggered at decision time. If your AI decision platform processes the event without recording that human review was available, you have created an Art.22 violation before the data subject knows a decision was made.

{
  "name": "GDPR Art.22 Automated Decision Right-to-Explanation Handler",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "art22-automated-decision",
        "responseMode": "responseNode",
        "options": {}
      },
      "name": "Webhook: Automated Decision Event",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        250,
        300
      ],
      "webhookId": "art22-webhook"
    },
    {
      "parameters": {
        "jsCode": "const event = $input.first().json;\nconst decisionType = event.decision_type || 'UNKNOWN';\nconst hasHumanReview = event.human_review_available === true;\nconst legalEffect = ['LOAN_DECISION', 'HIRING_DECISION', 'INSURANCE_UNDERWRITING', 'CREDIT_SCORING', 'BENEFIT_DETERMINATION', 'PAROLE_DECISION'].includes(decisionType);\nconst art22Applies = legalEffect && !hasHumanReview;\nconst dsarDeadline = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();\nreturn [{\n  json: {\n    decision_id: event.decision_id,\n    data_subject_id: event.data_subject_id,\n    decision_type: decisionType,\n    decision_outcome: event.decision_outcome,\n    model_id: event.model_id,\n    legal_significant_effect: legalEffect,\n    human_review_available: hasHumanReview,\n    art22_applies: art22Applies,\n    explanation_required: art22Applies,\n    dsar_deadline: dsarDeadline,\n    processing_ts: new Date().toISOString()\n  }\n}];"
      },
      "name": "Classify Art.22 Applicability",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "art22check",
              "leftValue": "={{ $json.art22_applies }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "Art.22 Applies?",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#gdpr-automated-decisions",
          "mode": "name"
        },
        "text": "=*GDPR Art.22 Human Review Required*\nDecision ID: {{ $json.decision_id }}\nData Subject: {{ $json.data_subject_id }}\nDecision Type: {{ $json.decision_type }}\nOutcome: {{ $json.decision_outcome }}\nExplanation Required: YES\nDSAR Deadline: {{ $json.dsar_deadline }}\nRef: GDPR Art.22 \u2014 right to human review + explanation",
        "otherOptions": {}
      },
      "name": "Slack Human Review Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        850,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO art22_decision_log (decision_id, data_subject_id, decision_type, decision_outcome, model_id, art22_applies, explanation_required, dsar_deadline, processing_ts) VALUES ('{{ $json.decision_id }}', '{{ $json.data_subject_id }}', '{{ $json.decision_type }}', '{{ $json.decision_outcome }}', '{{ $json.model_id }}', {{ $json.art22_applies }}, {{ $json.explanation_required }}, '{{ $json.dsar_deadline }}', NOW())",
        "options": {}
      },
      "name": "Log Art.22 Decision",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        850,
        400
      ]
    }
  ],
  "connections": {
    "Webhook: Automated Decision Event": {
      "main": [
        [
          {
            "node": "Classify Art.22 Applicability",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Art.22 Applicability": {
      "main": [
        [
          {
            "node": "Art.22 Applies?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Art.22 Applies?": {
      "main": [
        [
          {
            "node": "Slack Human Review Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Art.22 Decision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 3: NIST AI RMF 2.0 / ISO 42001:2023 Quarterly Risk Assessment Pipeline

What it does: Quarterly schedule trigger queries your AI system registry. For each system, it scores the four NIST AI RMF 2.0 functions (GOVERN, MAP, MEASURE, MANAGE) against a 0-100 scale and checks ISO 42001:2023 Clause 6.1 risk assessment completion status. Systems scoring below 70 on any function, or with incomplete ISO 42001 Clause 6.1 documentation, generate nonconformity flags and a Slack alert to #ai-governance. Overall risk rating (LOW/MEDIUM/HIGH) is calculated from the average RMF score. All assessments log to ai_rmf_assessments.

The audit evidence question: When SOC 2 Type II auditors, EU AI Act notified bodies, or enterprise procurement teams ask for evidence of your AI risk management process, the quarterly assessment log and the GOVERN/MAP/MEASURE/MANAGE score history are the answer. A Postgres table with timestamps is more defensible than a spreadsheet with no chain-of-custody.

{
  "name": "NIST AI RMF 2.0 / ISO 42001:2023 Quarterly Risk Assessment Pipeline",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "weeksInterval": 13
            }
          ]
        }
      },
      "name": "Quarterly Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        250,
        300
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT system_id, system_name, risk_tier, govern_score, map_score, measure_score, manage_score, iso42001_clause61_status, last_assessed FROM ai_system_registry WHERE is_active = true",
        "options": {}
      },
      "name": "Query AI System Registry",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "jsCode": "const systems = $input.all();\nconst results = systems.map(item => {\n  const s = item.json;\n  const scores = [s.govern_score, s.map_score, s.measure_score, s.manage_score].map(v => parseFloat(v) || 0);\n  const avgScore = scores.reduce((a, b) => a + b, 0) / scores.length;\n  const nonconformities = [];\n  if (s.govern_score < 70) nonconformities.push('GOVERN_DEFICIT');\n  if (s.map_score < 70) nonconformities.push('MAP_DEFICIT');\n  if (s.measure_score < 70) nonconformities.push('MEASURE_DEFICIT');\n  if (s.manage_score < 70) nonconformities.push('MANAGE_DEFICIT');\n  if (s.iso42001_clause61_status !== 'COMPLETE') nonconformities.push('ISO42001_CLAUSE61_INCOMPLETE');\n  const riskRating = avgScore >= 80 ? 'LOW' : avgScore >= 60 ? 'MEDIUM' : 'HIGH';\n  return {\n    system_id: s.system_id,\n    system_name: s.system_name,\n    risk_tier: s.risk_tier,\n    avg_rmf_score: avgScore.toFixed(1),\n    risk_rating: riskRating,\n    nonconformities: nonconformities,\n    assessed_at: new Date().toISOString()\n  };\n});\nreturn results.map(r => ({ json: r }));"
      },
      "name": "Score NIST AI RMF Functions",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "high-risk",
              "leftValue": "={{ $json.risk_rating }}",
              "rightValue": "LOW",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "Not Low Risk?",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        850,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#ai-governance",
          "mode": "name"
        },
        "text": "=*NIST AI RMF 2.0 Quarterly Alert* \u2014 {{ $json.system_name }}\nRisk Rating: {{ $json.risk_rating }}\nAvg RMF Score: {{ $json.avg_rmf_score }}/100\nNonconformities: {{ $json.nonconformities.join(', ') }}\nRisk Tier: {{ $json.risk_tier }}\nRef: NIST AI RMF 2.0 GOVERN/MAP/MEASURE/MANAGE + ISO 42001:2023 Clause 6.1",
        "otherOptions": {}
      },
      "name": "Slack Governance Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        1050,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO ai_rmf_assessments (system_id, system_name, risk_tier, avg_rmf_score, risk_rating, nonconformities, assessed_at) VALUES ('{{ $json.system_id }}', '{{ $json.system_name }}', '{{ $json.risk_tier }}', {{ $json.avg_rmf_score }}, '{{ $json.risk_rating }}', '{{ $json.nonconformities.join(',') }}', NOW())",
        "options": {}
      },
      "name": "Log RMF Assessment",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1050,
        400
      ]
    }
  ],
  "connections": {
    "Quarterly Trigger": {
      "main": [
        [
          {
            "node": "Query AI System Registry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Query AI System Registry": {
      "main": [
        [
          {
            "node": "Score NIST AI RMF Functions",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Score NIST AI RMF Functions": {
      "main": [
        [
          {
            "node": "Not Low Risk?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Not Low Risk?": {
      "main": [
        [
          {
            "node": "Slack Governance Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log RMF Assessment",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 4: FTC UDAP AI Claims Substantiation Monitor

What it does: Webhook trigger fires when marketing copy containing AI performance claims is submitted for review. The Code node scans for red-flag patterns: percentage accuracy/precision claims, superlative AI claims ("best AI", "most accurate", "state-of-the-art"), absolute performance guarantees, and regulatory status claims ("HIPAA-compliant", "FedRAMP authorized") that require specific evidence. Flagged claims route to #legal-ai-claims with the specific FTC violation type. Federal customer claims also flag for OMB M-24-10 use case registry review. All claims log to ai_claims_log.

Why this matters now: The FTC's 2023 AI Claims Policy Statement and 2024 enforcement actions (including settlements against AI companies for unsubstantiated performance claims) established that FTC Section 5 applies fully to AI marketing. "Our AI achieves 95% accuracy" requires a test methodology, sample size, and benchmark protocol — not just an internal benchmark on curated data.

{
  "name": "FTC UDAP AI Claims Substantiation Monitor",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "ai-claims-review",
        "responseMode": "responseNode",
        "options": {}
      },
      "name": "Webhook: AI Marketing Claim Submitted",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        250,
        300
      ],
      "webhookId": "ai-claims-webhook"
    },
    {
      "parameters": {
        "jsCode": "const claim = $input.first().json;\nconst claimText = (claim.claim_text || '').toLowerCase();\nconst redFlags = [\n  { pattern: /\\d+%\\s*(accuracy|precision|recall|f1|success|uptime)/, type: 'UNSUBSTANTIATED_PERFORMANCE_METRIC' },\n  { pattern: /(best|most accurate|leading|superior|state.of.the.art)\\s+ai/i, type: 'SUPERLATIVE_AI_CLAIM' },\n  { pattern: /guaranteed|always|never fails|100%/, type: 'ABSOLUTE_PERFORMANCE_CLAIM' },\n  { pattern: /fda.cleared|hipaa.compliant|fedramp.authorized/, type: 'REGULATORY_STATUS_CLAIM' }\n];\nconst flagged = redFlags.filter(rf => rf.pattern.test(claim.claim_text || ''));\nconst isFederal = claim.customer_type === 'FEDERAL_AGENCY';\nreturn [{\n  json: {\n    claim_id: claim.claim_id,\n    product_name: claim.product_name,\n    claim_text: claim.claim_text,\n    flags: flagged.map(f => f.type),\n    requires_substantiation: flagged.length > 0,\n    requires_omg_m2410_review: isFederal,\n    customer_type: claim.customer_type,\n    submitted_at: new Date().toISOString(),\n    ftc_section: 'FTC Section 5 / 15 USC \u00a745 UDAP \u2014 deceptive AI performance claims'\n  }\n}];"
      },
      "name": "Scan AI Claims for Red Flags",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "flag-check",
              "leftValue": "={{ $json.requires_substantiation }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "Requires Substantiation?",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#legal-ai-claims",
          "mode": "name"
        },
        "text": "=*FTC UDAP AI Claim Review Required*\nProduct: {{ $json.product_name }}\nClaim: {{ $json.claim_text }}\nFlags: {{ $json.flags.join(', ') }}\nOMB M-24-10 Review Required: {{ $json.requires_omg_m2410_review }}\nRef: FTC Section 5 \u2014 AI performance claim substantiation required",
        "otherOptions": {}
      },
      "name": "Legal Review Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        850,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO ai_claims_log (claim_id, product_name, claim_text, flags, requires_substantiation, customer_type, submitted_at) VALUES ('{{ $json.claim_id }}', '{{ $json.product_name }}', '{{ $json.claim_text }}', '{{ $json.flags.join(',') }}', {{ $json.requires_substantiation }}, '{{ $json.customer_type }}', NOW())",
        "options": {}
      },
      "name": "Log Claims Review",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        850,
        400
      ]
    }
  ],
  "connections": {
    "Webhook: AI Marketing Claim Submitted": {
      "main": [
        [
          {
            "node": "Scan AI Claims for Red Flags",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Scan AI Claims for Red Flags": {
      "main": [
        [
          {
            "node": "Requires Substantiation?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Requires Substantiation?": {
      "main": [
        [
          {
            "node": "Legal Review Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Claims Review",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Workflow 5: EU AI Act High-Risk System Post-Market Monitoring and Incident Reporting

What it does: Webhook trigger fires when an incident is detected in a high-risk AI system. The Code node classifies severity (SERIOUS_INCIDENT, NEAR_MISS, PERFORMANCE_DEGRADATION), sets the reporting window (15 days for serious incidents under Art.73), and maps the system's sector to the applicable supervisory authority (EASA for aviation, EMSA for maritime, ERA for rail, EBA for financial, EMA for medical devices). Serious incidents trigger an immediate Slack alert to #regulatory-incidents with the 15-day deadline and authority name. All incidents log to ai_incident_log.

The 15-day clock nobody watches: EU AI Act Art.73 requires that serious incidents involving high-risk AI systems be reported to the relevant market surveillance authority within 15 days of the provider becoming aware. "Becoming aware" starts when the incident is logged in your platform — not when your legal team reviews it. If your incident logging system and your regulatory reporting system are separate, you have a gap.

{
  "name": "EU AI Act High-Risk System Post-Market Monitoring and Incident Reporting",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "ai-incident-report",
        "responseMode": "responseNode",
        "options": {}
      },
      "name": "Webhook: AI Incident Detected",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        250,
        300
      ],
      "webhookId": "ai-incident-webhook"
    },
    {
      "parameters": {
        "jsCode": "const incident = $input.first().json;\nconst severity = incident.severity || 'UNKNOWN';\nconst REPORTING_WINDOWS = {\n  SERIOUS_INCIDENT: 15,\n  NEAR_MISS: 3,\n  PERFORMANCE_DEGRADATION: 30\n};\nconst windowDays = REPORTING_WINDOWS[severity] || 30;\nconst reportingDeadline = new Date(Date.now() + windowDays * 24 * 60 * 60 * 1000).toISOString();\nconst SUPERVISORY_AUTHORITIES = {\n  aviation: 'EASA', maritime: 'EMSA', rail: 'ERA', financial: 'EBA', medical: 'EMA', default: 'NATIONAL_MARKET_SURVEILLANCE_AUTHORITY'\n};\nconst authority = SUPERVISORY_AUTHORITIES[incident.sector] || SUPERVISORY_AUTHORITIES.default;\nreturn [{\n  json: {\n    incident_id: incident.incident_id,\n    system_id: incident.system_id,\n    system_name: incident.system_name,\n    severity: severity,\n    sector: incident.sector,\n    reporting_window_days: windowDays,\n    reporting_deadline: reportingDeadline,\n    supervisory_authority: authority,\n    description: incident.description,\n    detected_at: new Date().toISOString(),\n    eu_ai_act_ref: 'Regulation 2024/1689 Art.73 \u2014 serious incident 15-day reporting'\n  }\n}];"
      },
      "name": "Classify Incident + Set Reporting Deadline",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        450,
        300
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "serious",
              "leftValue": "={{ $json.severity }}",
              "rightValue": "SERIOUS_INCIDENT",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "name": "Serious Incident?",
      "type": "n8n-nodes-base.filter",
      "typeVersion": 2.2,
      "position": [
        650,
        300
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#regulatory-incidents",
          "mode": "name"
        },
        "text": "=*EU AI Act Art.73 Serious Incident \u2014 15-Day Reporting Clock STARTED*\nSystem: {{ $json.system_name }} ({{ $json.system_id }})\nSeverity: {{ $json.severity }}\nSector: {{ $json.sector }}\nAuthority: {{ $json.supervisory_authority }}\nReporting Deadline: {{ $json.reporting_deadline }}\nDescription: {{ $json.description }}\nRef: EU AI Act Art.73 \u2014 notify {{ $json.supervisory_authority }} within 15 days",
        "otherOptions": {}
      },
      "name": "15-Day Reporting Alert",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        850,
        200
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO ai_incident_log (incident_id, system_id, system_name, severity, sector, reporting_window_days, reporting_deadline, supervisory_authority, description, detected_at) VALUES ('{{ $json.incident_id }}', '{{ $json.system_id }}', '{{ $json.system_name }}', '{{ $json.severity }}', '{{ $json.sector }}', {{ $json.reporting_window_days }}, '{{ $json.reporting_deadline }}', '{{ $json.supervisory_authority }}', '{{ $json.description }}', NOW())",
        "options": {}
      },
      "name": "Log Incident",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        850,
        400
      ]
    }
  ],
  "connections": {
    "Webhook: AI Incident Detected": {
      "main": [
        [
          {
            "node": "Classify Incident + Set Reporting Deadline",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Classify Incident + Set Reporting Deadline": {
      "main": [
        [
          {
            "node": "Serious Incident?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Serious Incident?": {
      "main": [
        [
          {
            "node": "15-Day Reporting Alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log Incident",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

Customer Tier Reference

Customer Tier Company Profile Primary AI/ML Compliance Pain n8n Priority
MLOPS_PLATFORM_SAAS MLflow/Kubeflow/SageMaker-type platforms NIST AI RMF 2.0 model risk tracking, ISO 42001:2023 governance audit trail Workflow 3
GENERATIVE_AI_PLATFORM_SAAS LLM API/foundation model providers (GPT-type, image gen, multimodal) EU AI Act Art.51 GPAI registration, Art.55 systemic risk evaluation >10^25 FLOPs Workflow 1
AI_GOVERNANCE_SAAS AI risk management, model inventory, bias detection platforms ISO 42001:2023 Clause 6.1 risk assessment, NIST AI RMF GOVERN function, OMB M-24-10 Workflow 3
AI_COMPUTER_VISION_SAAS Face recognition, object detection, video analytics SaaS EU AI Act Annex III high-risk (biometric categorization, emotion recognition), GDPR Art.22 Workflow 2
NLP_TEXT_AI_SAAS Sentiment analysis, text classification, content moderation, chatbot platforms FTC UDAP AI performance claims, EU AI Act Art.53 technical docs, GDPR Art.22 Workflow 4
AI_DECISION_SAAS Credit scoring, hiring screening, fraud detection, underwriting AI GDPR Art.22 automated decisions with legal effect — human review MANDATORY, CCPA Workflow 2
AI_PLATFORM_STARTUP Seed/Series A AI SaaS entering EU or US federal market EU AI Act conformity assessment before market entry, FTC substantiation before launch Workflow 1 + 4

SQL Schema

-- GPAI model registry and compliance log
CREATE TABLE gpai_model_registry (
  model_id VARCHAR PRIMARY KEY,
  model_name VARCHAR NOT NULL,
  flops_estimate NUMERIC,
  gpai_registration_status VARCHAR DEFAULT 'PENDING',
  technical_doc_complete BOOLEAN DEFAULT FALSE,
  systemic_risk_evaluated BOOLEAN DEFAULT FALSE,
  is_active BOOLEAN DEFAULT TRUE
);
CREATE TABLE gpai_compliance_log (
  id SERIAL PRIMARY KEY,
  model_id VARCHAR NOT NULL,
  model_name VARCHAR,
  is_systemic_risk BOOLEAN,
  flags TEXT,
  compliance_status VARCHAR,
  checked_at TIMESTAMPTZ DEFAULT NOW()
);

-- GDPR Art.22 automated decision log
CREATE TABLE art22_decision_log (
  id SERIAL PRIMARY KEY,
  decision_id VARCHAR UNIQUE,
  data_subject_id VARCHAR,
  decision_type VARCHAR,
  decision_outcome VARCHAR,
  model_id VARCHAR,
  art22_applies BOOLEAN,
  explanation_required BOOLEAN,
  dsar_deadline TIMESTAMPTZ,
  processing_ts TIMESTAMPTZ DEFAULT NOW()
);

-- AI incident log
CREATE TABLE ai_incident_log (
  id SERIAL PRIMARY KEY,
  incident_id VARCHAR UNIQUE,
  system_id VARCHAR,
  system_name VARCHAR,
  severity VARCHAR,
  sector VARCHAR,
  reporting_window_days INTEGER,
  reporting_deadline TIMESTAMPTZ,
  supervisory_authority VARCHAR,
  description TEXT,
  detected_at TIMESTAMPTZ DEFAULT NOW()
);
Enter fullscreen mode Exit fullscreen mode

Templates

The workflows above are part of the FlowKit n8n automation template library. All templates at stripeai.gumroad.com — individual templates $12-$29, full bundle $97. Import-ready JSON with SQL schema and configuration guide.

Follow FlowKit on Dev.to at dev.to/flowkithq for more compliance-focused n8n workflow guides covering 350+ SaaS verticals.

Top comments (0)