DEV Community

Alex Kane
Alex Kane

Posted on

n8n for LegalTech Companies: 5 Automations That Scale Ops and Speed Up Onboarding (Free Workflow JSON)

If you're building a LegalTech product — a CLM platform, contract analytics tool, e-discovery SaaS, or legal document automation company — your engineering team is probably familiar with n8n. But the ops side of your business (customer success, product, finance) is likely still duct-taped together with manual Slack messages and spreadsheets.

This post shows 5 n8n automations that LegalTech companies use to scale ops without headcount. Every workflow includes import-ready JSON so you can deploy in minutes.

Why self-hosted n8n is a natural fit for LegalTech: Your product handles sensitive legal data — contracts, litigation documents, privileged communications. Routing your own customer data through Zapier or Make.com cloud introduces unnecessary data exposure risk. n8n runs on your infra. Audit log is a git-committed JSON file.


1. New Customer Onboarding Sequence

The problem: CS managers manually email new customers, forget Day 3 check-ins, and lose track of onboarding progress across 20+ accounts.

The solution: A multi-touch onboarding sequence triggered automatically when a new customer is added to your CRM or Google Sheets.

{
  "name": "LegalTech Customer Onboarding",
  "nodes": [
    {
      "parameters": { "event": "rowAdded", "sheetId": "{{ YOUR_SHEET_ID }}", "range": "Customers!A:H" },
      "name": "New Customer Trigger", "type": "n8n-nodes-base.googleSheetsTrigger", "position": [240, 300]
    },
    {
      "parameters": {
        "toEmail": "={{ $json.contact_email }}",
        "subject": "Welcome to {{ YOUR_PRODUCT }} — Let's Get You Set Up",
        "message": "Hi {{ $json.first_name }},\n\nWelcome! Your account is live.\n\nYour dedicated CSM {{ $json.csm_name }} will reach out within 24h.\n\nMeanwhile, start here: {{ YOUR_DOCS_URL }}\n\nBest,\nThe {{ YOUR_PRODUCT }} Team"
      },
      "name": "Send Welcome Email", "type": "n8n-nodes-base.gmail", "position": [480, 300]
    },
    {
      "parameters": { "channel": "#cs-new-customers", "text": "=New customer: {{ $json.company_name }} ({{ $json.plan }})\nCSM: {{ $json.csm_name }}\nContact: {{ $json.contact_email }}" },
      "name": "Slack CS Alert", "type": "n8n-nodes-base.slack", "position": [480, 480]
    },
    {
      "parameters": { "amount": 3, "unit": "days" },
      "name": "Wait 3 Days", "type": "n8n-nodes-base.wait", "position": [720, 300]
    },
    {
      "parameters": {
        "toEmail": "={{ $('New Customer Trigger').item.json.contact_email }}",
        "subject": "Day 3 Check-In — How's Onboarding Going?",
        "message": "Hi {{ $('New Customer Trigger').item.json.first_name }},\n\nYou've been with us 3 days — quick check-in.\n\nHave you completed your first document workflow? If you need any help, reply here or book time: {{ YOUR_CAL_URL }}\n\nBest,\n{{ $('New Customer Trigger').item.json.csm_name }}"
      },
      "name": "Day 3 Check-In", "type": "n8n-nodes-base.gmail", "position": [960, 300]
    },
    {
      "parameters": { "amount": 4, "unit": "days" },
      "name": "Wait 4 More Days", "type": "n8n-nodes-base.wait", "position": [1200, 300]
    },
    {
      "parameters": {
        "toEmail": "={{ $('New Customer Trigger').item.json.contact_email }}",
        "subject": "Week 1 Complete — Here's What to Do Next",
        "message": "Hi {{ $('New Customer Trigger').item.json.first_name }},\n\nWeek 1 done! Here are 3 features most teams unlock in Week 2:\n\n1. AI Contract Review\n2. Multi-User Workflows\n3. CRM Integration\n\nFull guide: {{ YOUR_DOCS_URL }}/week2\n\nAny questions, just reply.\n\nBest,\n{{ $('New Customer Trigger').item.json.csm_name }}"
      },
      "name": "Week 1 Email", "type": "n8n-nodes-base.gmail", "position": [1440, 300]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Result: Every new customer gets a consistent 7-day onboarding sequence without CS manual effort. CSM is notified immediately. Onboarding completion rates typically improve 30–40%.


2. API Usage & Quota Alert

The problem: Customers hit their API limits unexpectedly, see errors, blame you, and churn. You find out when they file a support ticket.

The solution: Proactively monitor usage and alert customers (and your CS team) before they hit walls.

{
  "name": "API Usage Quota Monitor",
  "nodes": [
    {
      "parameters": { "rule": { "interval": [{ "field": "hours", "intervalValue": 1 }] } },
      "name": "Every Hour", "type": "n8n-nodes-base.scheduleTrigger", "position": [240, 300]
    },
    {
      "parameters": {
        "url": "https://api.yourproduct.com/internal/usage",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBearerAuth"
      },
      "name": "Fetch Usage Stats", "type": "n8n-nodes-base.httpRequest", "position": [480, 300]
    },
    {
      "parameters": {
        "jsCode": "const customers = $input.all().map(i => i.json);
const alerts = [];
for (const c of customers) {
  const pct = c.api_calls_used / c.api_calls_limit;
  if (pct >= 0.95) alerts.push({...c, alert_level: 'CRITICAL', pct: Math.round(pct*100)});
  else if (pct >= 0.80) alerts.push({...c, alert_level: 'WARNING', pct: Math.round(pct*100)});
}
return alerts.map(a => ({json: a}));"
      },
      "name": "Filter High Usage", "type": "n8n-nodes-base.code", "position": [720, 300]
    },
    {
      "parameters": {
        "conditions": { "string": [{ "value1": "={{ $json.alert_level }}", "operation": "equals", "value2": "CRITICAL" }] }
      },
      "name": "Is Critical?", "type": "n8n-nodes-base.if", "position": [960, 300]
    },
    {
      "parameters": { "channel": "#cs-alerts", "text": "=🚨 CRITICAL: {{ $json.company_name }} at {{ $json.pct }}% quota ({{ $json.api_calls_used }}/{{ $json.api_calls_limit }}). CSM: {{ $json.csm_name }}. Consider proactive upgrade offer." },
      "name": "Slack Critical Alert", "type": "n8n-nodes-base.slack", "position": [1200, 200]
    },
    {
      "parameters": { "channel": "#cs-alerts", "text": "=⚠️ WARNING: {{ $json.company_name }} at {{ $json.pct }}% quota. CSM: {{ $json.csm_name }}. Monitor closely." },
      "name": "Slack Warning", "type": "n8n-nodes-base.slack", "position": [1200, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Result: CS gets a Slack alert before customers hit limits. Critical accounts get proactive upgrade conversations instead of angry support tickets.


3. Customer Health Score Monitor

The problem: You have 200+ accounts, 3 CSMs, and no systematic way to identify which customers are about to churn before it's too late.

The solution: Calculate a composite health score daily using real product signals and route at-risk accounts to Slack.

{
  "name": "Customer Health Score Monitor",
  "nodes": [
    {
      "parameters": { "rule": { "interval": [{ "field": "hours", "triggerAtHour": 8, "intervalValue": 24 }] } },
      "name": "Daily 8AM", "type": "n8n-nodes-base.scheduleTrigger", "position": [240, 300]
    },
    {
      "parameters": { "operation": "readOrSearch", "sheetId": "{{ YOUR_SHEET_ID }}", "range": "Customers!A:J" },
      "name": "Read Customer Data", "type": "n8n-nodes-base.googleSheets", "position": [480, 300]
    },
    {
      "parameters": {
        "jsCode": "const now = new Date();
const flagged = [];
for (const item of $input.all()) {
  const c = item.json;
  const daysSinceLogin = Math.floor((now - new Date(c.last_login_date)) / 86400000);
  const weeklyAPICalls = Number(c.weekly_api_calls) || 0;
  const openTickets = Number(c.open_support_tickets) || 0;
  // Score: 0-100 (lower = worse)
  let score = 100;
  if (daysSinceLogin > 14) score -= 30;
  else if (daysSinceLogin > 7) score -= 15;
  if (weeklyAPICalls < 10) score -= 20;
  else if (weeklyAPICalls < 50) score -= 10;
  if (openTickets > 3) score -= 25;
  else if (openTickets > 1) score -= 10;
  const status = score <= 40 ? 'RED' : score <= 65 ? 'AMBER' : 'GREEN';
  if (status !== 'GREEN') {
    flagged.push({json: { company: c.company_name, csm: c.csm_name, score, status, daysSinceLogin, weeklyAPICalls, openTickets }});
  }
}
return flagged;"
      },
      "name": "Calculate Health Scores", "type": "n8n-nodes-base.code", "position": [720, 300]
    },
    {
      "parameters": {
        "conditions": { "string": [{ "value1": "={{ $json.status }}", "operation": "equals", "value2": "RED" }] }
      },
      "name": "Red Accounts", "type": "n8n-nodes-base.if", "position": [960, 300]
    },
    {
      "parameters": { "channel": "#cs-churn-risk", "text": "=🔴 CHURN RISK: {{ $json.company }} (score: {{ $json.score }}/100)\nCSM: {{ $json.csm }}\nLast login: {{ $json.daysSinceLogin }}d ago | API calls/wk: {{ $json.weeklyAPICalls }} | Open tickets: {{ $json.openTickets }}" },
      "name": "Red Alert Slack", "type": "n8n-nodes-base.slack", "position": [1200, 200]
    },
    {
      "parameters": { "channel": "#cs-watch-list", "text": "=🟡 WATCH: {{ $json.company }} (score: {{ $json.score }}/100) — CSM: {{ $json.csm }}" },
      "name": "Amber Alert Slack", "type": "n8n-nodes-base.slack", "position": [1200, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Result: CS team sees RED accounts in #cs-churn-risk every morning, can act before renewal conversations become win-back attempts.


4. Support Ticket Auto-Classification & Routing

The problem: Every support ticket lands in one queue. Tier 1 spends 20 minutes triaging before routing. Legal-specific tickets (court filing questions, jurisdiction issues) go to the wrong team.

The solution: Auto-classify and route using Claude Haiku.

{
  "name": "LegalTech Support Auto-Triage",
  "nodes": [
    {
      "parameters": { "event": "ticketCreated" },
      "name": "Zendesk Webhook", "type": "n8n-nodes-base.webhook",
      "webhookId": "your-webhook-id", "position": [240, 300]
    },
    {
      "parameters": {
        "model": "claude-haiku-20240307",
        "messages": {
          "values": [{
            "role": "user",
            "content": "=Classify this LegalTech support ticket into ONE category:\n- TECHNICAL (API errors, integration bugs, performance)\n- BILLING (invoices, plan changes, payments)\n- FEATURE_REQUEST (new functionality, enhancement)\n- LEGAL_DOMAIN (jurisdiction, court rules, filing requirements — needs a legal professional)\n- ONBOARDING (setup, workflow questions, how-to)\n\nTicket: {{ $json.subject }}\n{{ $json.description }}\n\nRespond with ONLY the category name."
          }]
        }
      },
      "name": "Claude Classify", "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic", "position": [480, 300]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            { "conditions": { "string": [{ "value1": "={{ $json.text }}", "operation": "contains", "value2": "TECHNICAL" }] }, "renameOutput": true, "outputKey": "technical" },
            { "conditions": { "string": [{ "value1": "={{ $json.text }}", "operation": "contains", "value2": "LEGAL_DOMAIN" }] }, "renameOutput": true, "outputKey": "legal_domain" },
            { "conditions": { "string": [{ "value1": "={{ $json.text }}", "operation": "contains", "value2": "BILLING" }] }, "renameOutput": true, "outputKey": "billing" }
          ]
        }
      },
      "name": "Route by Category", "type": "n8n-nodes-base.switch", "position": [720, 300]
    },
    {
      "parameters": { "channel": "#support-engineering", "text": "=🔧 TECHNICAL: {{ $('Zendesk Webhook').item.json.subject }}\nFrom: {{ $('Zendesk Webhook').item.json.requester_email }}\nTicket: {{ $('Zendesk Webhook').item.json.ticket_url }}" },
      "name": "Engineering Slack", "type": "n8n-nodes-base.slack", "position": [960, 200]
    },
    {
      "parameters": { "channel": "#support-legal-domain", "text": "=⚖️ LEGAL DOMAIN QUESTION: {{ $('Zendesk Webhook').item.json.subject }}\nNeeds: legal-trained CSM\nTicket: {{ $('Zendesk Webhook').item.json.ticket_url }}" },
      "name": "Legal Domain Slack", "type": "n8n-nodes-base.slack", "position": [960, 400]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Result: Legal domain questions get routed to your legally-trained CSMs instead of an engineer who doesn't know the difference between PACER and eCourts. Technical bugs go straight to engineering. Triage time drops from 20 minutes to under 60 seconds.


5. Weekly Product & Revenue Briefing

The problem: Leadership asks "how are we doing?" every Monday. Product manager pulls data from 4 spreadsheets, writes a Slack message, forgets to include churn. Repeat.

The solution: Auto-generate a formatted weekly briefing from your data sources every Monday morning.

{
  "name": "LegalTech Weekly Briefing",
  "nodes": [
    {
      "parameters": { "rule": { "interval": [{ "field": "weeks", "triggerAtDay": 1, "triggerAtHour": 8 }] } },
      "name": "Monday 8AM", "type": "n8n-nodes-base.scheduleTrigger", "position": [240, 300]
    },
    {
      "parameters": { "operation": "readOrSearch", "sheetId": "{{ YOUR_SHEET_ID }}", "range": "Metrics!A:Z" },
      "name": "Read Metrics", "type": "n8n-nodes-base.googleSheets", "position": [480, 300]
    },
    {
      "parameters": {
        "jsCode": "const rows = $input.all().map(i => i.json);
const latest = rows[rows.length - 1];
const prev = rows[rows.length - 2] || latest;
const pct = (a, b) => b > 0 ? ((a - b) / b * 100).toFixed(1) + '%' : 'N/A';
const arrow = (a, b) => a >= b ? '↑' : '↓';
const mrr = Number(latest.mrr) || 0;
const prevMrr = Number(prev.mrr) || 0;
const newTrials = Number(latest.new_trials) || 0;
const churnedAccounts = Number(latest.churned_accounts) || 0;
const activeCustomers = Number(latest.active_customers) || 0;
const prevActive = Number(prev.active_customers) || 0;
const html = `<h2>FlowKit Weekly Briefing — ${latest.week_ending}</h2>
<table border='1' cellpadding='8' style='border-collapse:collapse'>
<tr><th>Metric</th><th>This Week</th><th>Last Week</th><th>Change</th></tr>
<tr><td>MRR</td><td>$${mrr.toLocaleString()}</td><td>$${prevMrr.toLocaleString()}</td><td>${arrow(mrr,prevMrr)} ${pct(mrr,prevMrr)}</td></tr>
<tr><td>Active Customers</td><td>${activeCustomers}</td><td>${prevActive}</td><td>${arrow(activeCustomers,prevActive)} ${pct(activeCustomers,prevActive)}</td></tr>
<tr><td>New Trials</td><td>${newTrials}</td><td>—</td><td>—</td></tr>
<tr><td>Churned</td><td>${churnedAccounts}</td><td>—</td><td>—</td></tr>
</table>`;
return [{json: {html, week: latest.week_ending, mrr, activeCustomers, newTrials, churnedAccounts}}];"
      },
      "name": "Build Report", "type": "n8n-nodes-base.code", "position": [720, 300]
    },
    {
      "parameters": {
        "toEmail": "ceo@yourcompany.com",
        "subject": "=Weekly Product & Revenue Briefing — {{ $json.week }}",
        "message": "={{ $json.html }}",
        "options": { "appendAttribution": false }
      },
      "name": "Email Leadership", "type": "n8n-nodes-base.gmail", "position": [960, 300]
    },
    {
      "parameters": { "channel": "#leadership", "text": "=📊 Weekly Briefing: MRR ${{ $json.mrr.toLocaleString() }} | Active: {{ $json.activeCustomers }} | Trials: {{ $json.newTrials }} | Churned: {{ $json.churnedAccounts }}" },
      "name": "Slack One-Liner", "type": "n8n-nodes-base.slack", "position": [960, 480]
    }
  ]
}
Enter fullscreen mode Exit fullscreen mode

Result: Monday 8AM, CEO gets a data-driven briefing without anyone manually pulling numbers. Consistent format, every week, with WoW trends.


Why LegalTech Companies Should Self-Host n8n

Concern Zapier/Make n8n (self-hosted)
Customer PII routing Routes through US cloud Stays in your VPC
SOC 2 / ISO 27001 audit "We use Zapier" is a finding Git-versioned JSON = clean audit trail
Custom legal domain logic Limited code step Full JavaScript/Python in Code node
Pricing at scale $0.02–$0.05 per Zap × 50K ops = $1K+/mo Self-hosted = effectively free
Data egress risk for EU customers GDPR complexity GDPR-compliant by design (no egress)

Get These Workflows Pre-Built

The 5 workflows above are adapted from the FlowKit n8n Template Store. Individual templates start at $12. The Complete Bundle (15 templates) is $97.

If you're building a LegalTech product and want to talk through how to adapt these for your stack — reply to this post or reach out at openstripeai@gmail.com.


Written by Alex Kane at FlowKit — ready-to-use n8n automation templates for business teams.

Top comments (0)