AutomationFlowsAI & RAG › Optimize Fleet Routes and Anomaly Alerts with Gpt-4, Slack and Postgres

Optimize Fleet Routes and Anomaly Alerts with Gpt-4, Slack and Postgres

ByCheng Siong Chin @cschin on n8n.io

This workflow automates veterinary clinic operations and client communications for animal hospitals and veterinary practices managing appointments, inventory, and patient care. It solves the dual challenge of maintaining medical supply levels while delivering personalized pet…

Webhook trigger★★★★★ complexityAI-powered34 nodesHTTP RequestAgentOpenAI ChatOutput Parser StructuredPostgresSlackEmail Send
AI & RAG Trigger: Webhook Nodes: 34 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #12792 — we link there as the canonical source.

This workflow follows the Agent → Emailsend recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "id": "8SvDV96yNsIGengN",
  "name": "Real-Time Fleet Telemetry Intelligence and Dispatch Automation",
  "tags": [],
  "nodes": [
    {
      "id": "627f2408-4fcb-4440-b671-f926988b5bf7",
      "name": "Telemetry Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -640,
        288
      ],
      "parameters": {
        "path": "fleet-telemetry",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode",
        "authentication": "headerAuth"
      },
      "credentials": {
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "725a9a5f-bf3c-4146-9558-d1be7be0aa1a",
      "name": "Scheduled Data Sync",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -416,
        480
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes"
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "e883c68e-b77a-4b8d-9241-cd82a71c1940",
      "name": "Workflow Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        -416,
        288
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "trafficApiUrl",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Traffic API endpoint URL__>"
            },
            {
              "id": "id-2",
              "name": "weatherApiUrl",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Weather API endpoint URL__>"
            },
            {
              "id": "id-3",
              "name": "maxSpeedThreshold",
              "type": "number",
              "value": 80
            },
            {
              "id": "id-4",
              "name": "fuelEfficiencyThreshold",
              "type": "number",
              "value": 15
            },
            {
              "id": "id-5",
              "name": "idleTimeThreshold",
              "type": "number",
              "value": 300
            },
            {
              "id": "id-6",
              "name": "complianceHoursLimit",
              "type": "number",
              "value": 11
            },
            {
              "id": "id-7",
              "name": "slackChannelNormal",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Slack channel for normal alerts__>"
            },
            {
              "id": "id-8",
              "name": "slackChannelCritical",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Slack channel for critical alerts__>"
            },
            {
              "id": "id-9",
              "name": "opsTeamEmail",
              "type": "string",
              "value": "<__PLACEHOLDER_VALUE__Operations team email address__>"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "a2d05c79-2348-4e76-b8b4-56567fbda40c",
      "name": "Merge Trigger Sources",
      "type": "n8n-nodes-base.merge",
      "position": [
        -192,
        384
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "c2ec33d3-8714-414b-be32-464d811d8a63",
      "name": "Normalize Telemetry Data",
      "type": "n8n-nodes-base.code",
      "position": [
        32,
        384
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Normalize incoming telemetry data from various fleet systems\n// into a unified schema\n\nconst inputData = $input.item.json;\n\n// Initialize normalized telemetry object with standard fields\nconst normalizedTelemetry = {\n  vehicleId: inputData.vehicleId || inputData.vehicle_id || inputData.VehicleID || inputData.id || null,\n  timestamp: inputData.timestamp || inputData.time || inputData.eventTime || new Date().toISOString(),\n  location: {\n    lat: inputData.latitude || inputData.lat || inputData.location?.lat || inputData.gps?.latitude || null,\n    lng: inputData.longitude || inputData.lng || inputData.location?.lng || inputData.gps?.longitude || null\n  },\n  speed: inputData.speed || inputData.velocity || inputData.speedKmh || inputData.speed_kmh || 0,\n  fuelLevel: inputData.fuelLevel || inputData.fuel_level || inputData.fuel || inputData.fuelPercent || null,\n  engineStatus: inputData.engineStatus || inputData.engine_status || inputData.status || inputData.engineState || 'unknown',\n  driverId: inputData.driverId || inputData.driver_id || inputData.DriverID || inputData.operator || null,\n  odometer: inputData.odometer || inputData.mileage || inputData.totalDistance || inputData.odometer_km || 0,\n  temperature: inputData.temperature || inputData.temp || inputData.engineTemp || inputData.engine_temperature || null,\n  eventType: inputData.eventType || inputData.event_type || inputData.type || inputData.event || 'telemetry_update'\n};\n\n// Return normalized data\nreturn normalizedTelemetry;"
      },
      "typeVersion": 2
    },
    {
      "id": "72accfed-afcd-44c6-ba40-e31c374ee7d9",
      "name": "Validate Data Quality",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        384
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Validate telemetry data quality\nconst item = $input.item.json;\n\n// Initialize validation result\nconst validationErrors = [];\nlet isValid = true;\n\n// Check for required fields\nif (!item.vehicleId) {\n  validationErrors.push('Missing required field: vehicleId');\n  isValid = false;\n}\n\nif (!item.timestamp) {\n  validationErrors.push('Missing required field: timestamp');\n  isValid = false;\n}\n\nif (!item.location) {\n  validationErrors.push('Missing required field: location');\n  isValid = false;\n}\n\n// Validate data types\nif (item.vehicleId && typeof item.vehicleId !== 'string') {\n  validationErrors.push('Invalid data type for vehicleId: expected string');\n  isValid = false;\n}\n\nif (item.timestamp && isNaN(Date.parse(item.timestamp))) {\n  validationErrors.push('Invalid data type for timestamp: expected valid date');\n  isValid = false;\n}\n\nif (item.location && typeof item.location !== 'object') {\n  validationErrors.push('Invalid data type for location: expected object');\n  isValid = false;\n}\n\n// Check for reasonable value ranges\nif (item.speed !== undefined) {\n  const speed = parseFloat(item.speed);\n  if (isNaN(speed) || speed < 0 || speed > 200) {\n    validationErrors.push('Speed out of valid range (0-200): ' + item.speed);\n    isValid = false;\n  }\n}\n\nif (item.fuelLevel !== undefined) {\n  const fuelLevel = parseFloat(item.fuelLevel);\n  if (isNaN(fuelLevel) || fuelLevel < 0 || fuelLevel > 100) {\n    validationErrors.push('Fuel level out of valid range (0-100): ' + item.fuelLevel);\n    isValid = false;\n  }\n}\n\n// Return item with validation results\nreturn {\n  ...item,\n  isValid: isValid,\n  validationErrors: validationErrors.length > 0 ? validationErrors : undefined\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "87c646f7-eaca-44f9-81e8-c6eb7bfd7ac9",
      "name": "Remove Duplicate Events",
      "type": "n8n-nodes-base.removeDuplicates",
      "position": [
        480,
        384
      ],
      "parameters": {
        "compare": "selectedFields",
        "options": {},
        "fieldsToCompare": "vehicleId, timestamp"
      },
      "typeVersion": 2
    },
    {
      "id": "ffcceca6-bcd1-4e90-a764-b7ac08c346e4",
      "name": "Fetch Traffic & Weather Data",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        704,
        304
      ],
      "parameters": {
        "url": "={{ $('Workflow Configuration').first().json.trafficApiUrl }}?lat={{ $json.location.lat }}&lng={{ $json.location.lng }}",
        "options": {
          "timeout": 10000,
          "batching": {
            "batch": {
              "batchSize": 10
            }
          },
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        },
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "apiKey",
              "value": "<__PLACEHOLDER_VALUE__Traffic/Weather API key__>"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "2a23a207-2c57-4f77-998f-c0e2155c95e5",
      "name": "Merge Telemetry with External Data",
      "type": "n8n-nodes-base.merge",
      "position": [
        928,
        384
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "joinMode": "enrichInput1",
        "fieldsToMatchString": "vehicleId"
      },
      "typeVersion": 3.2
    },
    {
      "id": "b06dc0ed-6106-4c6c-9033-54299c5fedcc",
      "name": "Route Optimization Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1152,
        384
      ],
      "parameters": {
        "text": "=Vehicle: {{ $json.vehicleId }}, Current Location: {{ $json.location }}, Destination: {{ $json.destination }}, Traffic: {{ $json.trafficConditions }}, Weather: {{ $json.weatherConditions }}",
        "options": {
          "systemMessage": "You are a fleet route optimization AI agent. Analyze vehicle telemetry, GPS location, traffic conditions, and weather data to optimize delivery routes.\n\nYour task is to:\n1. Calculate the optimal route considering traffic, weather, and delivery time windows\n2. Estimate accurate ETA based on current conditions\n3. Identify potential delays or route improvements\n4. Consider fuel efficiency and driver hours of service compliance\n5. Return structured route optimization recommendations\n\nProvide actionable route adjustments and ETA predictions."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "6c29ba5f-8a13-443c-b72d-19542f20edd8",
      "name": "OpenAI GPT-4 Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1152,
        608
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "gpt-4o"
        },
        "options": {
          "maxTokens": 2000,
          "temperature": 0.3
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "c8554c21-b60d-4cc7-84a9-91619d1f9c9b",
      "name": "Route Optimization Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1280,
        608
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"optimizedRoute\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Recommended route waypoints\"\n\t\t},\n\t\t\"estimatedETA\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Predicted arrival time\"\n\t\t},\n\t\t\"delayMinutes\": {\n\t\t\t\"type\": \"number\",\n\t\t\t\"description\": \"Expected delay in minutes\"\n\t\t},\n\t\t\"fuelSavings\": {\n\t\t\t\"type\": \"number\",\n\t\t\t\"description\": \"Estimated fuel savings percentage\"\n\t\t},\n\t\t\"routeConfidence\": {\n\t\t\t\"type\": \"number\",\n\t\t\t\"description\": \"Confidence score 0-100\"\n\t\t},\n\t\t\"recommendations\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Route optimization recommendations\"\n\t\t}\n\t}\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "c787c0d6-6691-4841-81b0-0f4a91a4d5aa",
      "name": "Anomaly Detection Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1504,
        384
      ],
      "parameters": {
        "text": "=Vehicle: {{ $json.vehicleId }}, Speed: {{ $json.speed }}, Fuel: {{ $json.fuelLevel }}, Engine: {{ $json.engineStatus }}, Driver Hours: {{ $json.driverHours }}, Temperature: {{ $json.temperature }}",
        "options": {
          "systemMessage": "You are a fleet anomaly detection AI agent. Analyze vehicle telemetry data to identify safety issues, mechanical problems, compliance violations, and operational anomalies.\n\nYour task is to:\n1. Detect speed violations, harsh braking, or erratic driving patterns\n2. Identify potential mechanical failures (engine issues, fuel anomalies, temperature problems)\n3. Flag hours of service compliance violations\n4. Detect unauthorized stops or route deviations\n5. Assess severity level: NORMAL, WARNING, or CRITICAL\n6. Return structured anomaly detection results\n\nProvide clear anomaly classifications with severity and recommended actions."
        },
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 3.1
    },
    {
      "id": "47a8effa-fb4e-49be-981b-8abf8863bc1c",
      "name": "OpenAI GPT-4 Model for Anomaly",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1504,
        608
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "gpt-4o"
        },
        "options": {
          "maxTokens": 1500,
          "temperature": 0.2
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "ac3745f0-29be-455a-9b23-41f0fa067eb1",
      "name": "Anomaly Detection Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        1632,
        608
      ],
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"anomalyDetected\": {\n\t\t\t\"type\": \"boolean\",\n\t\t\t\"description\": \"Whether anomaly was detected\"\n\t\t},\n\t\t\"anomalyType\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Type of anomaly: speed, mechanical, compliance, route, safety\"\n\t\t},\n\t\t\"severityLevel\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Severity: NORMAL, WARNING, CRITICAL\"\n\t\t},\n\t\t\"description\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Detailed anomaly description\"\n\t\t},\n\t\t\"recommendedAction\": {\n\t\t\t\"type\": \"string\",\n\t\t\t\"description\": \"Recommended corrective action\"\n\t\t},\n\t\t\"requiresManualReview\": {\n\t\t\t\"type\": \"boolean\",\n\t\t\t\"description\": \"Whether manual review is needed\"\n\t\t}\n\t}\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "b00f5bbd-e60e-4df9-80d1-1f3279961be0",
      "name": "Apply Business Rules",
      "type": "n8n-nodes-base.code",
      "position": [
        1856,
        384
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Apply Business Rules to Fleet Telemetry Data\n\n// Get workflow configuration if available\nconst config = $('Workflow Configuration').first()?.json || {};\n\n// Get current item data\nconst item = $input.item.json;\n\n// Initialize business rules validation\nlet businessRulesPassed = true;\nlet priority = 0;\nconst ruleViolations = [];\n\n// 1. Check Dispatch Capacity Limits\nconst maxDispatchCapacity = config.maxDispatchCapacity || 100;\nconst currentDispatchCount = item.currentDispatchCount || 0;\n\nif (currentDispatchCount >= maxDispatchCapacity) {\n  businessRulesPassed = false;\n  ruleViolations.push('Dispatch capacity limit exceeded');\n  priority += 50; // High priority for capacity issues\n}\n\n// 2. Validate DOT Compliance Regulations\nconst dotCompliant = item.dotCompliant !== false; // Default to true if not specified\nconst vehicleInspectionCurrent = item.vehicleInspectionCurrent !== false;\n\nif (!dotCompliant || !vehicleInspectionCurrent) {\n  businessRulesPassed = false;\n  ruleViolations.push('DOT compliance violation detected');\n  priority += 75; // Very high priority for compliance\n}\n\n// 3. Enforce Driver Hours of Service Limits\nconst maxDriverHours = config.maxDriverHoursOfService || 11; // DOT standard\nconst driverHoursWorked = item.driverHoursWorked || 0;\nconst driverRestHours = item.driverRestHours || 0;\n\nif (driverHoursWorked >= maxDriverHours) {\n  businessRulesPassed = false;\n  ruleViolations.push('Driver hours of service limit exceeded');\n  priority += 100; // Critical priority for safety\n}\n\nif (driverRestHours < 10 && driverHoursWorked > 8) {\n  ruleViolations.push('Insufficient driver rest period');\n  priority += 60;\n}\n\n// 4. Calculate Priority Score Based on Delivery Windows\nconst deliveryDeadline = item.deliveryDeadline ? new Date(item.deliveryDeadline) : null;\nconst currentTime = new Date();\n\nif (deliveryDeadline) {\n  const hoursUntilDeadline = (deliveryDeadline - currentTime) / (1000 * 60 * 60);\n  \n  if (hoursUntilDeadline < 2) {\n    priority += 90; // Urgent delivery\n  } else if (hoursUntilDeadline < 4) {\n    priority += 60; // High priority\n  } else if (hoursUntilDeadline < 8) {\n    priority += 30; // Medium priority\n  } else {\n    priority += 10; // Normal priority\n  }\n  \n  if (hoursUntilDeadline < 0) {\n    businessRulesPassed = false;\n    ruleViolations.push('Delivery deadline already passed');\n    priority += 100;\n  }\n}\n\n// 5. Apply Rate Limiting for API Calls\nconst apiCallTimestamp = Date.now();\nconst lastApiCall = item.lastApiCallTimestamp || 0;\nconst minApiCallInterval = config.minApiCallIntervalMs || 1000; // 1 second default\n\nif (apiCallTimestamp - lastApiCall < minApiCallInterval) {\n  ruleViolations.push('API rate limit - call too frequent');\n  // Don't fail business rules, but log the violation\n}\n\n// 6. Additional Business Logic\nif (item.anomalyDetected === true) {\n  priority += 40; // Increase priority for anomalies\n}\n\nif (item.severity === 'critical') {\n  priority += 80;\n} else if (item.severity === 'high') {\n  priority += 50;\n} else if (item.severity === 'medium') {\n  priority += 25;\n}\n\n// Cap priority at 100\npriority = Math.min(priority, 100);\n\n// Return enriched data with business rules results\nreturn {\n  ...item,\n  businessRulesPassed,\n  priority,\n  ruleViolations,\n  businessRulesAppliedAt: new Date().toISOString(),\n  lastApiCallTimestamp: apiCallTimestamp\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "97fe74be-96a4-4b50-bdd3-d0200036061e",
      "name": "Route by Severity",
      "type": "n8n-nodes-base.switch",
      "position": [
        2080,
        352
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Normal Operations",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.severityLevel }}",
                    "rightValue": "NORMAL"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Needs Review",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.severityLevel }}",
                    "rightValue": "WARNING"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Critical Alert",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.severityLevel }}",
                    "rightValue": "CRITICAL"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Unclassified"
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "b6e656d2-2496-4dfb-a7cc-1d9002aaf619",
      "name": "Wait for Manual Review",
      "type": "n8n-nodes-base.wait",
      "position": [
        2528,
        576
      ],
      "parameters": {
        "resume": "webhook",
        "options": {},
        "resumeAmount": 24,
        "limitWaitTime": true
      },
      "typeVersion": 1.1
    },
    {
      "id": "a7af45ad-d41b-4214-b854-2e86d223bc24",
      "name": "Store Telemetry Records",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2752,
        192
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "name",
          "value": "fleet_telemetry"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "speed": "={{ $json.speed }}",
            "location": "={{ $json.location }}",
            "fuelLevel": "={{ $json.fuelLevel }}",
            "timestamp": "={{ $json.timestamp }}",
            "vehicleId": "={{ $json.vehicleId }}",
            "anomalyType": "={{ $json.anomalyType }}",
            "engineStatus": "={{ $json.engineStatus }}",
            "estimatedETA": "={{ $json.estimatedETA }}",
            "severityLevel": "={{ $json.severityLevel }}",
            "optimizedRoute": "={{ $json.optimizedRoute }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {
          "outputColumns": [
            "vehicleId",
            "timestamp",
            "location",
            "speed",
            "fuelLevel",
            "engineStatus",
            "optimizedRoute",
            "estimatedETA",
            "anomalyType",
            "severityLevel"
          ]
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "6dd229bb-6cf8-4b54-90b8-b0d3aa12d36c",
      "name": "Store Incident Records",
      "type": "n8n-nodes-base.postgres",
      "position": [
        2752,
        576
      ],
      "parameters": {
        "table": {
          "__rl": true,
          "mode": "name",
          "value": "incident_records"
        },
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "timestamp": "={{ $json.timestamp }}",
            "vehicleId": "={{ $json.vehicleId }}",
            "reviewedAt": "={{ $json.reviewedAt }}",
            "reviewedBy": "={{ $json.reviewedBy }}",
            "description": "={{ $json.description }}",
            "incidentType": "={{ $json.incidentType }}",
            "reviewStatus": "={{ $json.reviewStatus }}",
            "severityLevel": "={{ $json.severityLevel }}"
          },
          "schema": [],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {
          "outputColumns": [
            "vehicleId",
            "timestamp",
            "incidentType",
            "severityLevel",
            "description",
            "reviewStatus",
            "reviewedBy",
            "reviewedAt"
          ]
        }
      },
      "typeVersion": 2.6
    },
    {
      "id": "13a1b415-47f8-4915-940b-1bed19dfc7c3",
      "name": "Generate Performance Report",
      "type": "n8n-nodes-base.postgres",
      "position": [
        3200,
        384
      ],
      "parameters": {
        "query": "SELECT vehicle_id, COUNT(*) as total_events, AVG(speed) as avg_speed, SUM(CASE WHEN severity_level = 'CRITICAL' THEN 1 ELSE 0 END) as critical_incidents, AVG(fuel_level) as avg_fuel FROM fleet_telemetry WHERE timestamp > NOW() - INTERVAL '1 day' GROUP BY vehicle_id ORDER BY critical_incidents DESC",
        "options": {},
        "operation": "executeQuery"
      },
      "typeVersion": 2.6
    },
    {
      "id": "1be20c7b-d4f8-40ba-bf96-e8db19b9bd9c",
      "name": "Notify Dispatchers via Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        2976,
        192
      ],
      "parameters": {
        "text": "=\ud83d\ude9b Fleet Update: Vehicle {{ $json.vehicleId }} - Normal operations. ETA: {{ $json.estimatedETA }}. Route optimized with {{ $json.fuelSavings }}% fuel savings.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.slackChannelNormal }}"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "deebd058-caaa-4938-8837-372cd858d55e",
      "name": "Email Operations Team",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        2976,
        576
      ],
      "parameters": {
        "html": "=<h2>Incident Review Required</h2><p><strong>Vehicle:</strong> {{ $json.vehicleId }}</p><p><strong>Incident Type:</strong> {{ $json.anomalyType }}</p><p><strong>Severity:</strong> {{ $json.severityLevel }}</p><p><strong>Description:</strong> {{ $json.description }}</p><p><strong>Recommended Action:</strong> {{ $json.recommendedAction }}</p><p>Please review and take appropriate action.</p>",
        "options": {},
        "subject": "=\u26a0\ufe0f Fleet Incident Requires Review - Vehicle {{ $json.vehicleId }}",
        "toEmail": "={{ $('Workflow Configuration').first().json.opsTeamEmail }}",
        "fromEmail": "<__PLACEHOLDER_VALUE__From Email Address__>"
      },
      "typeVersion": 2.1
    },
    {
      "id": "a824e34a-048e-49e4-95f8-13287182104e",
      "name": "Alert Critical Incidents",
      "type": "n8n-nodes-base.slack",
      "position": [
        2304,
        384
      ],
      "parameters": {
        "text": "=\ud83d\udea8 CRITICAL ALERT: Vehicle {{ $json.vehicleId }} - {{ $json.anomalyType }}. {{ $json.description }}. Immediate action required: {{ $json.recommendedAction }}",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Workflow Configuration').first().json.slackChannelCritical }}"
        },
        "otherOptions": {},
        "authentication": "oAuth2"
      },
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "bd75cb8f-5da9-48ec-bccb-fa53cb51c991",
      "name": "Prepare Customer Notification",
      "type": "n8n-nodes-base.set",
      "position": [
        2528,
        384
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "id-1",
              "name": "customerMessage",
              "type": "string",
              "value": "=Your shipment on vehicle {{ $json.vehicleId }} has encountered {{ $json.anomalyType }}. We are working to resolve this and will update you shortly."
            },
            {
              "id": "id-2",
              "name": "notificationChannel",
              "type": "string",
              "value": "sms"
            },
            {
              "id": "id-3",
              "name": "requiresRerouting",
              "type": "boolean",
              "value": "={{ $json.severityLevel === 'CRITICAL' && ($json.anomalyType === 'mechanical' || $json.anomalyType === 'route') }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "25343b2f-27bf-4fcb-8b22-58aa9d6821dc",
      "name": "Check if Re-routing Required",
      "type": "n8n-nodes-base.if",
      "position": [
        2752,
        384
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "id-1",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.requiresRerouting }}"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "675860b0-298d-4ee0-8d8c-6c268a096d9b",
      "name": "Trigger Re-routing Action",
      "type": "n8n-nodes-base.code",
      "position": [
        2976,
        384
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Trigger Re-routing Action\n// Identify alternative vehicles, calculate new routes, update dispatch system\n\nconst item = $input.item.json;\n\n// Extract incident details\nconst incidentId = item.incidentId || item.id || 'INC-' + Date.now();\nconst affectedVehicleId = item.vehicleId || item.vehicle_id;\nconst location = item.location || { lat: 0, lon: 0 };\nconst severity = item.severity || 'medium';\nconst reason = item.reason || item.anomaly_type || 'route_optimization_required';\n\n// Identify alternative vehicles\n// In production, this would query a vehicle availability database\nconst availableVehicles = [\n  { id: 'VEH-ALT-001', distance: 2.5, eta: 15, capacity: 'high' },\n  { id: 'VEH-ALT-002', distance: 3.8, eta: 22, capacity: 'medium' },\n  { id: 'VEH-ALT-003', distance: 1.9, eta: 12, capacity: 'high' }\n];\n\n// Select best alternative vehicle (closest with adequate capacity)\nconst selectedVehicle = availableVehicles.sort((a, b) => a.eta - b.eta)[0];\n\n// Calculate new route\nconst newRoute = {\n  vehicleId: selectedVehicle.id,\n  origin: selectedVehicle.currentLocation || { lat: location.lat + 0.01, lon: location.lon + 0.01 },\n  destination: location,\n  estimatedDistance: selectedVehicle.distance,\n  estimatedDuration: selectedVehicle.eta,\n  waypoints: [\n    { lat: location.lat + 0.005, lon: location.lon + 0.005, order: 1 },\n    { lat: location.lat + 0.002, lon: location.lon + 0.002, order: 2 }\n  ]\n};\n\n// Update dispatch system (simulated)\nconst dispatchUpdate = {\n  action: 'reassign',\n  originalVehicle: affectedVehicleId,\n  newVehicle: selectedVehicle.id,\n  incidentId: incidentId,\n  priority: severity === 'critical' ? 'urgent' : 'normal',\n  status: 'dispatched',\n  updatedAt: new Date().toISOString()\n};\n\n// Log re-routing event\nconst reroutingLog = {\n  eventId: 'REROUTE-' + Date.now(),\n  timestamp: new Date().toISOString(),\n  incidentId: incidentId,\n  reason: reason,\n  originalAssignment: {\n    vehicleId: affectedVehicleId,\n    status: 'reassigned'\n  },\n  newAssignment: {\n    vehicleId: selectedVehicle.id,\n    eta: selectedVehicle.eta,\n    route: newRoute\n  },\n  dispatchUpdate: dispatchUpdate,\n  metadata: {\n    alternativesConsidered: availableVehicles.length,\n    selectionCriteria: 'shortest_eta',\n    severity: severity\n  }\n};\n\n// Return re-routing confirmation\nconst confirmation = {\n  success: true,\n  reroutingId: reroutingLog.eventId,\n  incidentId: incidentId,\n  newVehicleId: selectedVehicle.id,\n  updatedETA: selectedVehicle.eta,\n  estimatedArrival: new Date(Date.now() + selectedVehicle.eta * 60000).toISOString(),\n  route: newRoute,\n  log: reroutingLog,\n  message: `Successfully re-routed incident ${incidentId} to vehicle ${selectedVehicle.id} with ETA of ${selectedVehicle.eta} minutes`\n};\n\nreturn {\n  json: {\n    ...item,\n    reroutingConfirmation: confirmation,\n    reroutingLog: reroutingLog,\n    newVehicleId: selectedVehicle.id,\n    updatedETA: selectedVehicle.eta,\n    reroutingTimestamp: new Date().toISOString()\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "26d790fd-f6e5-4897-98f7-87f1fa94bb7a",
      "name": "Respond to Webhook",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3424,
        384
      ],
      "parameters": {
        "options": {
          "responseCode": 200
        },
        "respondWith": "json",
        "responseBody": "={\n  \"status\": \"success\",\n  \"message\": \"Fleet telemetry processed\",\n  \"recordsProcessed\": {{ $json.total_events }},\n  \"timestamp\": \"{{ $now }}\"\n}"
      },
      "typeVersion": 1.5
    },
    {
      "id": "4c7ff381-7b79-4cd5-a9a9-0fa4a38bbb0b",
      "name": "Data Ingestion Layer",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        -320
      ],
      "parameters": {
        "color": 4,
        "width": 516,
        "height": 344,
        "content": "## Prerequisites\nVeterinary practice management software with API/webhook capabilities, AI service API access\n## Use Cases\nMulti-location veterinary hospitals coordinating inventory across sites\n## Customization\nModify AI prompts for species-specific care instructions\n## Benefits\nReduces supply management time by 75%, prevents critical medication stockouts"
      },
      "typeVersion": 1
    },
    {
      "id": "6b742c2f-7c28-43c3-86f0-9822cc9e59dc",
      "name": "AI Intelligence Layer",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        272,
        -256
      ],
      "parameters": {
        "width": 420,
        "height": 280,
        "content": "## Setup Steps\n1. Configure webhook or schedule trigger for veterinary management system inventory data sync\n2. Add AI model API keys for inventory quality validation\n3. Connect supplier email system with template configurations for automated purchase orders\n4. Set up client communication channels with appointment and care instruction templates\n5. Integrate customer database for pet records and appointment history "
      },
      "typeVersion": 1
    },
    {
      "id": "51532f2e-d669-4fef-88e0-db785ab0623f",
      "name": "Notification & Action Layer",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -656,
        -208
      ],
      "parameters": {
        "width": 852,
        "height": 216,
        "content": "## How It Works\nThis workflow automates veterinary clinic operations and client communications for animal hospitals and veterinary practices managing appointments, inventory, and patient care. It solves the dual challenge of maintaining medical supply levels while delivering personalized pet care updates and appointment coordination. The system processes scheduled inventory data through AI-powered quality validation and restocking recommendations, then branches into two intelligent pathways: supplier coordination via email for replenishment, and client engagement through personalized appointment reminders, follow-up care instructions, and satisfaction surveys distributed via email and messaging platforms. This eliminates manual inventory tracking, reduces appointment no-shows, and ensures consistent post-visit care communication."
      },
      "typeVersion": 1
    },
    {
      "id": "965a2457-b1b1-4d4b-83b8-268dc95b8343",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1840,
        64
      ],
      "parameters": {
        "color": 7,
        "width": 1808,
        "height": 768,
        "content": "\n## Multi-Channel Distribution\n**Why:** Coordinated delivery through supplier emails, client appointment reminders, follow-up care instructions, and automated satisfaction surveys ensures comprehensive practice management coverage."
      },
      "typeVersion": 1
    },
    {
      "id": "ce4c4059-60fa-4421-a5d1-8b16c4dc1948",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1088,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 704,
        "height": 752,
        "content": "## Dual AI Processing Streams\n**Why:** Parallel processing generates supplier-specific restocking recommendations and client-personalized appointment communications, optimizing both supply chain and patient experience simultaneously."
      },
      "typeVersion": 1
    },
    {
      "id": "4cbd2338-57ff-4dad-a198-ac6420637c56",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -752,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 1824,
        "height": 640,
        "content": "## Scheduled Inventory Assessment\n**Why:** Automated data sync triggers AI-powered quality checks and stock level analysis, identifying critical supply shortages before they impact patient care."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "94884904-75f0-4750-a3ef-1e011a17c2f5",
  "connections": {
    "Route by Severity": {
      "main": [
        [
          {
            "node": "Store Telemetry Records",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait for Manual Review",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Alert Critical Incidents",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4 Model": {
      "ai_languageModel": [
        [
          {
            "node": "Route Optimization Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Scheduled Data Sync": {
      "main": [
        [
          {
            "node": "Merge Trigger Sources",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Apply Business Rules": {
      "main": [
        [
          {
            "node": "Route by Severity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email Operations Team": {
      "main": [
        [
          {
            "node": "Generate Performance Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Trigger Sources": {
      "main": [
        [
          {
            "node": "Normalize Telemetry Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Data Quality": {
      "main": [
        [
          {
            "node": "Remove Duplicate Events",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Incident Records": {
      "main": [
        [
          {
            "node": "Email Operations Team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Manual Review": {
      "main": [
        [
          {
            "node": "Store Incident Records",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workflow Configuration": {
      "main": [
        [
          {
            "node": "Merge Trigger Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Anomaly Detection Agent": {
      "main": [
        [
          {
            "node": "Apply Business Rules",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Remove Duplicate Events": {
      "main": [
        [
          {
            "node": "Fetch Traffic & Weather Data",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge Telemetry with External Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store Telemetry Records": {
      "main": [
        [
          {
            "node": "Notify Dispatchers via Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Alert Critical Incidents": {
      "main": [
        [
          {
            "node": "Prepare Customer Notification",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Telemetry Data": {
      "main": [
        [
          {
            "node": "Validate Data Quality",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route Optimization Agent": {
      "main": [
        [
          {
            "node": "Anomaly Detection Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Telemetry Webhook Trigger": {
      "main": [
        [
          {
            "node": "Workflow Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Trigger Re-routing Action": {
      "main": [
        [
          {
            "node": "Generate Performance Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate Performance Report": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Re-routing Required": {
      "main": [
        [
          {
            "node": "Trigger Re-routing Action",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Traffic & Weather Data": {
      "main": [
        [
          {
            "node": "Merge Telemetry with External Data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Notify Dispatchers via Slack": {
      "main": [
        [
          {
            "node": "Generate Performance Report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Customer Notification": {
      "main": [
        [
          {
            "node": "Check if Re-routing Required",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI GPT-4 Model for Anomaly": {
      "ai_languageModel": [
        [
          {
            "node": "Anomaly Detection Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Anomaly Detection Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Anomaly Detection Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Route Optimization Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Route Optimization Agent",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Merge Telemetry with External Data": {
      "main": [
        [
          {
            "node": "Route Optimization Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow automates veterinary clinic operations and client communications for animal hospitals and veterinary practices managing appointments, inventory, and patient care. It solves the dual challenge of maintaining medical supply levels while delivering personalized pet…

Source: https://n8n.io/workflows/12792/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow transforms natural language queries into research reports through a five-stage AI pipeline. When triggered via webhook (typically from Google Sheets using the companion [](https://gist.g

Redis, Agent, Output Parser Structured +7
AI & RAG

This workflow automates customer feedback processing by analyzing sentiment, identifying key issues, generating personalized responses, and escalating critical cases to support teams when required. De

Redis, Postgres, Agent +7
AI & RAG

This workflow automates inventory management and customer engagement for e-commerce businesses and retail operations managing multiple product categories. It solves the critical challenge of maintaini

Agent, OpenAI Chat, Output Parser Structured +3
AI & RAG

Automates scholarship tracking by scraping university sites, assessing eligibility via AI, and publishing results to WordPress or Slack. Eliminates manual searches for students, counselors, and educat

HTTP Request, OpenAI Chat, Agent +4
AI & RAG

The system collects real-time wearable health data, normalizes it, and uses AI to analyze trends and risk scores. It detects anomalies by comparing with historical patterns and automatically triggers

Postgres, Agent, OpenAI Chat +7