{"workflow":{"id":12803,"name":"Track Azure API and Service Bus failures with Application Insights correlation","views":23,"recentViews":0,"totalViews":23,"createdAt":"2026-01-18T22:14:52.009Z","description":"# Track Azure API failures with Application Insights correlation\n\n## Template Name\nTrack Azure API failures with App Insights, APIM, and Service Bus correlation\n\n## Description\n\nTroubleshoot failed API calls by correlating Application Insights telemetry with API Management logs and Service Bus messages. Query failures from the last 24 hours to 30 days, identify root causes, and generate detailed failure reports with full context.\n\n## Who's it for\n\nDevOps Engineers, Site Reliability Engineers, API developers, Support teams, and Platform engineers troubleshooting production incidents.\n\n## How it works\n\n1. **Set Configuration**: Stores credentials and query parameters\n2. **Query Application Insights**: Single node retrieves APIM requests, Service Bus traces, and exceptions via OAuth2\n3. **Correlate and Analyze Data**: Links requests to SB messages and exceptions via operation IDs\n4. **Generate Report**: Creates detailed failure analysis with root cause data\n5. **Output**: Markdown/HTML reports, Excel export, or JSON API response\n\n## Set up steps\n\n### Prerequisites\n\n- Application Insights resource in Azure\n- APIM and Service Bus logging to App Insights\n- Service Principal with \"Monitoring Reader\" role\n\n### Setup\n\n**1. Create Azure Service Principal**\n\nAzure CLI:\n```bash\n# Create service principal\naz ad sp create-for-rbac --name \"n8n-appinsights-tracker\" \\\n  --role \"Monitoring Reader\" \\\n  --scopes /subscriptions/{subscription-id}/resourceGroups/{resource-group}/providers/Microsoft.Insights/components/{app-insights-name}\n```\n\nSave the output:\n- `appId` (client ID)\n- `password` (client secret)\n- `tenant` (tenant ID)\n\nAlso get your Application Insights App ID:\n```bash\naz monitor app-insights component show --app {name} -g {rg} --query appId -o tsv\n```\n\n**2. Configure Workflow**\n\nOpen \"Set Configuration\" node and update:\n- `appId` - Application Insights Application ID\n- `clientId` - Service Principal client ID (from step 1)\n- `clientSecret` - Service Principal password (from step 1)\n- `tenantId` - Azure AD tenant ID (from step 1)\n- `timeRange` - 24h, 7d, or 30d\n- `includeSuccessful` - false (failures only) or true (all requests)\n\n**3. Verify Dependencies**\n\nEnsure diagnostic logging is configured:\n- **APIM**: Diagnostics → Application Insights enabled\n- **Service Bus**: Diagnostic settings → Send to App Insights\n- **Custom Dimensions**: Capture MessageId, EntityName for Service Bus\n\n**4. Test Workflow**\n\n- Click Manual Trigger\n- Review \"Generate Report\" node output\n- Verify correlated data appears\n\n**5. Enable Output Options (Optional)**\n\n- **Excel**: Enable \"Export to Excel\" for downloadable reports\n- **Webhook**: Enable \"Respond to Webhook\" for API integration\n\n## Requirements\n\n### Azure Requirements\n- Azure Application Insights resource\n- Service Principal with \"Monitoring Reader\" role\n- APIM and Service Bus configured to log to Application Insights\n\n### n8n Requirements\n- n8n instance (cloud or self-hosted version 1.0+)\n- Ability to configure credentials in Set Configuration node\n\n## How to customize\n\n### Time Range Filters\n\nModify `timeRange` in \"Set Configuration\":\n- `24h` - Last 24 hours (default)\n- `7d` - Last 7 days  \n- `30d` - Last 30 days\n\n### Filter by API or Operation\n\nEdit KQL queries in \"Query Application Insights\" Code node. Find the `apimQuery` variable and modify:\n\n```javascript\nconst apimQuery = `\nrequests\n| where timestamp &gt; ago(${timeRange})\n| where name contains \"specific-api-name\"\n| where customDimensions['apim-operation-name'] == \"GetOrders\"\n| where resultCode &gt;= 400\n| take 500\n| project timestamp, name, url, resultCode, duration, operation_Id, customDimensions\n`;\n```\n\n### Filter by Status Code\n\nModify the `where resultCode` condition:\n\n```javascript\n| where resultCode == 500  // Only 500 errors\n| where resultCode &gt;= 400 and resultCode &lt; 500  // 4xx errors\n```\n\n### Include Custom Dimensions\n\nExtend the project statement in any query:\n\n```javascript\n| extend customField = tostring(customDimensions['YourCustomField'])\n| project ..., customField\n```\n\n### Adjust Result Limits\n\nChange `take 500` in each query to retrieve more/fewer results:\n\n```javascript\n| take 1000  // Get 1000 results\n```\n\n### Add Additional Queries\n\nAdd new queries in the Code node, for example dependency tracking:\n\n```javascript\nconst dependencyQuery = `\ndependencies\n| where timestamp &gt; ago(${timeRange})\n| where success == false\n| extend operationId = tostring(operation_Id)\n| take 500\n| project timestamp, name, type, target, duration, success, operation_Id\n`;\n\nconst dependencyResponse = await fetch(\n  `https://api.applicationinsights.io/v1/apps/${appId}/query?query=${encodeURIComponent(dependencyQuery)}`,\n  { headers: { 'Authorization': `Bearer ${accessToken}` } }\n);\n```\n\n## Troubleshooting\n\n**\"Query failed\" or 401 error**: Verify Service Principal has \"Monitoring Reader\" role, check clientId/clientSecret/tenantId in Set Configuration node\n\n**\"Token acquisition failed\"**: Confirm credentials are correct, verify Service Principal is not expired\n\n**\"No data returned\"**: Check time range, verify APIM/SB logs to App Insights, confirm diagnostic settings enabled, ensure Application Insights App ID is correct\n\n**\"Operation IDs don't correlate\"**: Ensure custom dimensions are captured, verify telemetry initializers configured in APIM and Service Bus\n\n**\"Missing Service Bus data\"**: Enable Service Bus diagnostic logs, add MessageId to custom dimensions in logging configuration\n\n## Use Cases\n\n### Incident Response\nQuery last 24h of failures during incident to identify affected APIs and root causes\n\n### Pattern Analysis\nUse 7d or 30d range to identify recurring error patterns and systemic issues\n\n### Performance Investigation\nSort by duration to find slow API calls and optimize bottlenecks\n\n### Customer Support\nSearch by operation ID from customer complaint to trace full request lifecycle\n\n### Compliance Reporting\nExport to Excel for audit trail of failed transactions\n\n## Data Structure\n\n### Summary Object\n```json\n{\n  \"totalRequests\": 150,\n  \"failedRequests\": 12,\n  \"successfulRequests\": 138,\n  \"requestsWithExceptions\": 8,\n  \"requestsWithServiceBus\": 45,\n  \"averageDuration\": 234.5,\n  \"timeRange\": \"24h\"\n}\n```\n\n### Failed Request Object\n```json\n{\n  \"timestamp\": \"2026-01-19T10:30:00Z\",\n  \"apiName\": \"POST /api/orders\",\n  \"url\": \"https://api.example.com/orders\",\n  \"resultCode\": 500,\n  \"duration\": 1523,\n  \"operationId\": \"abc-123-def\",\n  \"apimServiceName\": \"prod-apim\",\n  \"apimOperationName\": \"CreateOrder\",\n  \"serviceBusMessageIds\": [\"msg-456\", \"msg-789\"],\n  \"exceptionMessages\": [\"NullReferenceException: Object not set\"],\n  \"hasException\": true,\n  \"isFailure\": true\n}\n```\n\n## KQL Query Examples\n\n### Failed requests with exceptions\n```kusto\nrequests\n| where timestamp &gt; ago(24h)\n| where resultCode &gt;= 400\n| join kind=inner (\n    exceptions\n    | where timestamp &gt; ago(24h)\n) on operation_Id\n| project timestamp, name, resultCode, operation_Id, outerMessage\n```\n\n### Service Bus message failures\n```kusto\ntraces\n| where timestamp &gt; ago(24h)\n| where message contains \"Failed to process message\"\n| extend messageId = tostring(customDimensions['MessageId'])\n| project timestamp, message, messageId\n```\n\n### APIM throttling analysis\n```kusto\nrequests\n| where timestamp &gt; ago(7d)\n| where resultCode == 429\n| summarize count() by bin(timestamp, 1h), tostring(customDimensions['apim-subscription-id'])\n```\n\n## Integration Examples\n\n### Python - Query API\n```python\nimport requests\n\nurl = \"https://your-n8n.com/webhook/app-insights-tracker\"\nresponse = requests.get(url)\ndata = response.json()\n\nprint(f\"Failed Requests: {data['data']['summary']['failedRequests']}\")\nfor error in data['data']['topErrors']:\n    print(f\"  {error['error']}: {error['count']} times\")\n```\n\n### PowerShell - Alert on Failures\n```powershell\n$data = Invoke-RestMethod -Uri \"https://your-n8n.com/webhook/app-insights-tracker\"\n$failures = $data.data.summary.failedRequests\n\nif ($failures -gt 10) {\n    Send-MailMessage -To \"oncall@company.com\" `\n        -Subject \"ALERT: $failures API failures detected\" `\n        -Body $data.data.report\n}\n```\n\n### Scheduled Monitoring\nRun workflow every hour with Schedule Trigger to continuously monitor for failures and alert when thresholds exceeded.\n\n## Resources\n\n[Application Insights API](https://learn.microsoft.com/azure/azure-monitor/app/api-custom-events-metrics) | [KQL Reference](https://learn.microsoft.com/azure/data-explorer/kusto/query/) | [APIM Logging](https://learn.microsoft.com/azure/api-management/api-management-howto-app-insights)\n\n---\n\n**Category**: Monitoring, Observability, DevOps  \n**Difficulty**: Intermediate  \n**Setup Time**: 10 minutes  \n**n8n Version**: 1.0+\n","workflow":{"name":"Track API failures with Application Insights correlation","tags":[],"nodes":[{"id":"sticky-main-overview","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[240,240],"parameters":{"color":4,"width":480,"height":460,"content":"## How it works\n\nThis workflow queries Azure Application Insights to track failed API calls across APIM, Service Bus, and exceptions. It makes three KQL queries to the Application Insights API, then correlates the results using operationId to show which API calls failed, what exceptions occurred, and which Service Bus messages were involved.\n\n## Setup steps\n\n1. **Create service principal**: Run `az ad sp create-for-rbac --name \"n8n-appinsights\" --role \"Monitoring Reader\" --scopes /subscriptions/{subscription-id}`\n\n2. **Configure workflow**: Update 'Set Configuration' with your Application Insights Application ID and Azure AD tenant ID.\n\n3. **Add credentials**: The workflow uses Azure credentials which must be configured in your n8n instance."},"typeVersion":1},{"id":"sticky-config","name":"Sticky Note - Config","type":"n8n-nodes-base.stickyNote","position":[800,240],"parameters":{"color":7,"width":340,"height":180,"content":"## Configuration\n\nSet your Application Insights Application ID and time range filter. Ensure OAuth2 credentials are configured in n8n. Time range options: 24h, 7d, 30d."},"typeVersion":1},{"id":"sticky-processing","name":"Sticky Note - Processing","type":"n8n-nodes-base.stickyNote","position":[1660,240],"parameters":{"color":7,"width":340,"height":180,"content":"## Processing & Reporting\n\nCorrelates data using operationId, calculates statistics, identifies top errors and slow requests, then generates Markdown and HTML reports."},"typeVersion":1},{"id":"trigger-manual","name":"Manual Trigger","type":"n8n-nodes-base.manualTrigger","position":[780,460],"parameters":{},"typeVersion":1},{"id":"config-settings","name":"Set Configuration","type":"n8n-nodes-base.set","position":[1000,460],"parameters":{"options":{},"assignments":{"assignments":[{"id":"appInsightsAppId","name":"appInsightsAppId","type":"string","value":"YOUR_APP_INSIGHTS_APP_ID"},{"id":"tenantId","name":"tenantId","type":"string","value":"YOUR_TENANT_ID"},{"id":"clientId","name":"clientId","type":"string","value":"YOUR_CLIENT_ID"},{"id":"clientSecret","name":"clientSecret","type":"string","value":"YOUR_CLIENT_SECRET"},{"id":"timeRange","name":"timeRange","type":"string","value":"24h"},{"id":"includeSuccessful","name":"includeSuccessful","type":"boolean","value":false}]}},"typeVersion":3.3},{"id":"sticky-data-collection","name":"Sticky Note - Data Collection","type":"n8n-nodes-base.stickyNote","position":[1220,240],"parameters":{"color":7,"width":340,"height":180,"content":"## Data Collection\n\nMakes three Application Insights API calls in one node: APIM requests, Service Bus traces, and exceptions. Handles OAuth2 authentication internally."},"typeVersion":1},{"id":"query-all-data","name":"Query Application Insights","type":"n8n-nodes-base.code","position":[1220,460],"parameters":{"jsCode":"const config = $input.item.json;\nconst appId = config.appInsightsAppId;\nconst tenantId = config.tenantId;\nconst clientId = config.clientId;\nconst clientSecret = config.clientSecret;\nconst timeRange = config.timeRange;\nconst includeSuccessful = config.includeSuccessful;\n\n// Get OAuth2 token\nconst tokenResponse = await fetch(\n  `https://login.microsoftonline.com/${tenantId}/oauth2/v2.0/token`,\n  {\n    method: 'POST',\n    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n    body: new URLSearchParams({\n      client_id: clientId,\n      client_secret: clientSecret,\n      scope: 'https://api.applicationinsights.io/.default',\n      grant_type: 'client_credentials'\n    })\n  }\n);\n\nconst tokenData = await tokenResponse.json();\nconst accessToken = tokenData.access_token;\n\nif (!accessToken) {\n  throw new Error('Failed to obtain access token: ' + JSON.stringify(tokenData));\n}\n\nconst headers = {\n  'Authorization': `Bearer ${accessToken}`,\n  'Content-Type': 'application/json'\n};\n\nconst baseUrl = `https://api.applicationinsights.io/v1/apps/${appId}/query`;\n\n// Query 1: APIM Requests\nconst apimQuery = `requests\n| where timestamp > ago(${timeRange})\n${includeSuccessful ? '' : '| where resultCode >= 400'}\n| extend operationId = tostring(operation_Id)\n| extend apimServiceName = tostring(customDimensions['apim-service-name'])\n| extend apimOperationName = tostring(customDimensions['apim-operation-name'])\n| extend apimSubscriptionId = tostring(customDimensions['apim-subscription-id'])\n| project timestamp, name, url, resultCode, duration, operationId, apimServiceName, apimOperationName, apimSubscriptionId, customDimensions, client_Type, client_City, client_CountryOrRegion\n| order by timestamp desc\n| take 500`;\n\nconst apimResponse = await fetch(baseUrl, {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({ query: apimQuery })\n});\nconst apimData = await apimResponse.json();\n\n// Query 2: Service Bus Traces  \nconst sbQuery = `traces\n| where timestamp > ago(${timeRange})\n| where message contains 'ServiceBus' or customDimensions has 'MessageId'\n| extend operationId = tostring(operation_Id)\n| extend messageId = tostring(customDimensions['MessageId'])\n| extend entityName = tostring(customDimensions['EntityName'])\n| extend endpoint = tostring(customDimensions['Endpoint'])\n| project timestamp, message, severityLevel, operationId, messageId, entityName, endpoint, customDimensions\n| order by timestamp desc\n| take 500`;\n\nconst sbResponse = await fetch(baseUrl, {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({ query: sbQuery })\n});\nconst sbData = await sbResponse.json();\n\n// Query 3: Exceptions\nconst exceptionsQuery = `exceptions\n| where timestamp > ago(${timeRange})\n| extend operationId = tostring(operation_Id)\n| project timestamp, type, outerMessage, innermostMessage, outerMethod, innermostMethod, operationId, problemId, severityLevel, customDimensions, details\n| order by timestamp desc\n| take 500`;\n\nconst exceptionsResponse = await fetch(baseUrl, {\n  method: 'POST',\n  headers,\n  body: JSON.stringify({ query: exceptionsQuery })\n});\nconst exceptionsData = await exceptionsResponse.json();\n\nreturn [{\n  json: {\n    apimData: apimData.tables?.[0] || {},\n    sbData: sbData.tables?.[0] || {},\n    exceptionsData: exceptionsData.tables?.[0] || {}\n  }\n}];"},"typeVersion":2},{"id":"correlate-data","name":"Correlate and Analyze Data","type":"n8n-nodes-base.code","position":[1440,460],"parameters":{"jsCode":"const data = $input.first().json;\nconst apimData = data.apimData;\nconst sbData = data.sbData;\nconst exceptionsData = data.exceptionsData;\n\nfunction parseAppInsightsTable(table) {\n  if (!table || !table.columns || !table.rows) return [];\n  const columns = table.columns.map(c => c.name);\n  return table.rows.map(row => {\n    const obj = {};\n    columns.forEach((col, idx) => { obj[col] = row[idx]; });\n    return obj;\n  });\n}\n\nconst apimRequests = parseAppInsightsTable(apimData);\nconst sbTraces = parseAppInsightsTable(sbData);\nconst exceptions = parseAppInsightsTable(exceptionsData);\n\nconst sbByOperationId = {};\nsbTraces.forEach(trace => {\n  if (trace.operationId) {\n    if (!sbByOperationId[trace.operationId]) sbByOperationId[trace.operationId] = [];\n    sbByOperationId[trace.operationId].push(trace);\n  }\n});\n\nconst exceptionsByOperationId = {};\nexceptions.forEach(ex => {\n  if (ex.operationId) {\n    if (!exceptionsByOperationId[ex.operationId]) exceptionsByOperationId[ex.operationId] = [];\n    exceptionsByOperationId[ex.operationId].push(ex);\n  }\n});\n\nconst correlatedData = apimRequests.map(request => ({\n  timestamp: request.timestamp,\n  apiName: request.name,\n  url: request.url,\n  resultCode: request.resultCode,\n  duration: request.duration,\n  operationId: request.operationId,\n  apimServiceName: request.apimServiceName,\n  apimOperationName: request.apimOperationName,\n  apimSubscriptionId: request.apimSubscriptionId,\n  clientType: request.client_Type,\n  clientCity: request.client_City,\n  clientCountry: request.client_CountryOrRegion,\n  serviceBusTraces: sbByOperationId[request.operationId] || [],\n  serviceBusMessageIds: (sbByOperationId[request.operationId] || []).map(t => t.messageId).filter(Boolean),\n  exceptions: exceptionsByOperationId[request.operationId] || [],\n  exceptionMessages: (exceptionsByOperationId[request.operationId] || []).map(e => e.outerMessage).filter(Boolean),\n  hasException: !!exceptionsByOperationId[request.operationId],\n  hasServiceBusTrace: !!sbByOperationId[request.operationId],\n  isFailure: request.resultCode >= 400\n}));\n\nconst summary = {\n  totalRequests: correlatedData.length,\n  failedRequests: correlatedData.filter(r => r.isFailure).length,\n  successfulRequests: correlatedData.filter(r => !r.isFailure).length,\n  requestsWithExceptions: correlatedData.filter(r => r.hasException).length,\n  requestsWithServiceBus: correlatedData.filter(r => r.hasServiceBusTrace).length,\n  averageDuration: correlatedData.reduce((sum, r) => sum + (r.duration || 0), 0) / correlatedData.length,\n  timeRange: $('Set Configuration').item.json.timeRange,\n  analysisTimestamp: new Date().toISOString()\n};\n\nconst errorCounts = {};\ncorrelatedData.filter(r => r.isFailure).forEach(r => {\n  const key = `${r.resultCode} - ${r.apiName}`;\n  errorCounts[key] = (errorCounts[key] || 0) + 1;\n});\n\nconst topErrors = Object.entries(errorCounts)\n  .map(([error, count]) => ({ error, count }))\n  .sort((a, b) => b.count - a.count)\n  .slice(0, 10);\n\nconst topSlowRequests = [...correlatedData]\n  .sort((a, b) => (b.duration || 0) - (a.duration || 0))\n  .slice(0, 10)\n  .map(r => ({ apiName: r.apiName, duration: r.duration, resultCode: r.resultCode, timestamp: r.timestamp, operationId: r.operationId }));\n\nreturn [{ json: { summary, topErrors, topSlowRequests, correlatedData, rawData: { apimRequestCount: apimRequests.length, serviceBusTraceCount: sbTraces.length, exceptionCount: exceptions.length } } }];"},"typeVersion":2},{"id":"generate-report","name":"Generate Report","type":"n8n-nodes-base.code","position":[1660,560],"parameters":{"jsCode":"const data = $input.first().json;\nconst summary = data.summary;\nconst topErrors = data.topErrors;\nconst topSlowRequests = data.topSlowRequests;\n\nconst markdownReport = `# Azure API Failure Analysis Report\\n\\n**Analysis Period:** ${summary.timeRange}\\n**Generated:** ${new Date(summary.analysisTimestamp).toLocaleString()}\\n\\n---\\n\\n## Summary\\n\\n- **Total Requests:** ${summary.totalRequests}\\n- **Failed Requests:** ${summary.failedRequests} (${((summary.failedRequests/summary.totalRequests)*100).toFixed(1)}%)\\n- **Successful Requests:** ${summary.successfulRequests}\\n- **Requests with Exceptions:** ${summary.requestsWithExceptions}\\n- **Requests with Service Bus Traces:** ${summary.requestsWithServiceBus}\\n- **Average Duration:** ${summary.averageDuration.toFixed(2)}ms\\n\\n---\\n\\n## Top 10 Errors\\n\\n${topErrors.length > 0 ? topErrors.map((e, i) => `${i + 1}. **${e.error}** - ${e.count} occurrences`).join('\\\\n') : '_No errors found_'}\\n\\n---\\n\\n## Top 10 Slowest Requests\\n\\n${topSlowRequests.length > 0 ? topSlowRequests.map((r, i) => `${i + 1}. **${r.apiName}** - ${r.duration.toFixed(2)}ms - Status ${r.resultCode}`).join('\\\\n') : '_No slow requests identified_'}\\n\\n---\\n\\n_Report generated by n8n Azure App Insights Tracker_\\n`;\n\nconst htmlReport = `<!DOCTYPE html>\\n<html>\\n<head>\\n  <title>Azure API Failure Analysis</title>\\n  <style>\\n    body { font-family: 'Segoe UI', Tahoma, sans-serif; margin: 20px; background: #f5f5f5; }\\n    .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\\n    h1 { color: #0078D4; border-bottom: 3px solid #0078D4; padding-bottom: 10px; }\\n    h2 { color: #106EBE; margin-top: 30px; }\\n    .summary-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; }\\n    .summary-card { background: #f0f6ff; padding: 15px; border-radius: 6px; border-left: 4px solid #0078D4; }\\n    .summary-card .label { font-size: 12px; color: #666; text-transform: uppercase; }\\n    .summary-card .value { font-size: 24px; font-weight: bold; color: #0078D4; margin-top: 5px; }\\n    .error-item, .slow-item { background: #fff4f4; padding: 10px; margin: 8px 0; border-left: 4px solid #d13438; border-radius: 4px; }\\n    .slow-item { background: #fff8e1; border-left-color: #f9a825; }\\n    table { width: 100%; border-collapse: collapse; margin: 20px 0; }\\n    th { background: #0078D4; color: white; padding: 12px; text-align: left; }\\n    td { padding: 10px; border-bottom: 1px solid #ddd; }\\n    tr:hover { background: #f5f5f5; }\\n    .failure { color: #d13438; font-weight: bold; }\\n  </style>\\n</head>\\n<body>\\n  <div class=\\\"container\\\">\\n    <h1>Azure API Failure Analysis Report</h1>\\n    <p><strong>Analysis Period:</strong> ${summary.timeRange} | <strong>Generated:</strong> ${new Date(summary.analysisTimestamp).toLocaleString()}</p>\\n    <div class=\\\"summary-grid\\\">\\n      <div class=\\\"summary-card\\\"><div class=\\\"label\\\">Total Requests</div><div class=\\\"value\\\">${summary.totalRequests}</div></div>\\n      <div class=\\\"summary-card\\\"><div class=\\\"label\\\">Failed</div><div class=\\\"value\\\" style=\\\"color: #d13438;\\\">${summary.failedRequests}</div></div>\\n      <div class=\\\"summary-card\\\"><div class=\\\"label\\\">Success Rate</div><div class=\\\"value\\\" style=\\\"color: #107c10;\\\">${((summary.successfulRequests/summary.totalRequests)*100).toFixed(1)}%</div></div>\\n      <div class=\\\"summary-card\\\"><div class=\\\"label\\\">Avg Duration</div><div class=\\\"value\\\">${summary.averageDuration.toFixed(0)}ms</div></div>\\n    </div>\\n    <h2>Top Errors</h2>\\n    ${topErrors.map(e => `<div class=\\\"error-item\\\"><strong>${e.error}</strong> - ${e.count} occurrences</div>`).join('')}\\n    <h2>Top Slowest Requests</h2>\\n    ${topSlowRequests.map(r => `<div class=\\\"slow-item\\\"><strong>${r.apiName}</strong> - ${r.duration.toFixed(0)}ms - Status ${r.resultCode}</div>`).join('')}\\n  </div>\\n</body>\\n</html>`;\n\nreturn [{ json: { ...data, markdownReport, htmlReport } }];"},"typeVersion":2},{"id":"check-has-data","name":"Check If Data Exists","type":"n8n-nodes-base.if","position":[1880,560],"parameters":{"options":{},"conditions":{"options":{"leftValue":"","caseSensitive":true,"typeValidation":"strict"},"combinator":"and","conditions":[{"id":"has-data","operator":{"type":"number","operation":"gt"},"leftValue":"={{ $json.correlatedData.length }}","rightValue":"0"}]}},"typeVersion":2},{"id":"output-report","name":"Output Report","type":"n8n-nodes-base.set","position":[2100,460],"parameters":{"options":{},"assignments":{"assignments":[{"id":"report","name":"report","type":"string","value":"={{ $json.markdownReport }}"},{"id":"htmlReport","name":"htmlReport","type":"string","value":"={{ $json.htmlReport }}"},{"id":"summary","name":"summary","type":"object","value":"={{ $json.summary }}"},{"id":"topErrors","name":"topErrors","type":"array","value":"={{ $json.topErrors }}"},{"id":"failedRequests","name":"failedRequests","type":"array","value":"={{ $json.correlatedData.filter(r => r.isFailure) }}"}]}},"typeVersion":3.3},{"id":"no-data-found","name":"No Data Found","type":"n8n-nodes-base.set","position":[2100,660],"parameters":{"options":{},"assignments":{"assignments":[{"id":"message","name":"message","type":"string","value":"No data found for the specified time range and filters. Check your App Insights configuration."}]}},"typeVersion":3.3},{"id":"export-excel","name":"Export to Excel","type":"n8n-nodes-base.spreadsheetFile","disabled":true,"position":[2320,360],"parameters":{"options":{"fileName":"=azure-api-failures-{{ $now.format('yyyy-MM-dd-HHmmss') }}.xlsx","headerRow":true},"operation":"toFile","fileFormat":"xlsx"},"typeVersion":2},{"id":"respond-webhook","name":"Respond to Webhook","type":"n8n-nodes-base.respondToWebhook","disabled":true,"position":[2320,560],"parameters":{"options":{},"respondWith":"json","responseBody":"={{ { status: 'success', data: { summary: $json.summary, topErrors: $json.topErrors, failedRequests: $json.failedRequests, report: $json.report }, timestamp: $now.toISO() } }}"},"typeVersion":1.1},{"id":"sticky-outputs","name":"Sticky Note - Outputs","type":"n8n-nodes-base.stickyNote","position":[2100,240],"parameters":{"color":7,"width":340,"height":180,"content":"## Output Options\n\nExport to Excel or return JSON via webhook. Both nodes are disabled by default—enable as needed."},"typeVersion":1}],"pinData":{},"settings":{"executionOrder":"v1"},"updatedAt":"2026-01-19T00:00:00.000Z","versionId":"2","staticData":null,"connections":{"Output Report":{"main":[[{"node":"Export to Excel","type":"main","index":0},{"node":"Respond to Webhook","type":"main","index":0}]]},"Manual Trigger":{"main":[[{"node":"Set Configuration","type":"main","index":0}]]},"Generate Report":{"main":[[{"node":"Check If Data Exists","type":"main","index":0}]]},"Set Configuration":{"main":[[{"node":"Query Application Insights","type":"main","index":0}]]},"Check If Data Exists":{"main":[[{"node":"Output Report","type":"main","index":0}],[{"node":"No Data Found","type":"main","index":0}]]},"Correlate and Analyze Data":{"main":[[{"node":"Generate Report","type":"main","index":0}]]},"Query Application Insights":{"main":[[{"node":"Correlate and Analyze Data","type":"main","index":0}]]}},"triggerCount":0},"lastUpdatedBy":1,"workflowInfo":{"nodeCount":15,"nodeTypes":{"n8n-nodes-base.if":{"count":1},"n8n-nodes-base.set":{"count":3},"n8n-nodes-base.code":{"count":3},"n8n-nodes-base.stickyNote":{"count":5},"n8n-nodes-base.manualTrigger":{"count":1},"n8n-nodes-base.spreadsheetFile":{"count":1},"n8n-nodes-base.respondToWebhook":{"count":1}}},"status":"published","readyToDemo":null,"user":{"name":"kartik ramachandran","username":"kramatic85","bio":"Solution architect with 20 yrs of SDLC experience ","verified":false,"links":[""],"avatar":"https://gravatar.com/avatar/b0b70727b44047f91f87a86b89ae73f15de67179065cc18d9c7fe809a843f3b2?r=pg&d=retro&size=200"},"nodes":[{"id":20,"icon":"fa:map-signs","name":"n8n-nodes-base.if","codex":{"data":{"alias":["Router","Filter","Condition","Logic","Boolean","Branch"],"details":"The IF node can be used to implement binary conditional logic in your workflow. You can set up one-to-many conditions to evaluate each item of data being inputted into the node. That data will either evaluate to TRUE or FALSE and route out of the node accordingly.\n\nThis node has multiple types of conditions: Bool, String, Number, and Date & Time.","resources":{"generic":[{"url":"https://n8n.io/blog/learn-to-automate-your-factorys-incident-reporting-a-step-by-step-guide/","icon":"🏭","label":"Learn to Automate Your Factory's Incident Reporting: A Step by Step Guide"},{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/why-business-process-automation-with-n8n-can-change-your-daily-life/","icon":"🧬","label":"Why business process automation with n8n can change your daily life"},{"url":"https://n8n.io/blog/create-a-toxic-language-detector-for-telegram/","icon":"🤬","label":"Create a toxic language detector for Telegram in 4 step"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/how-to-build-a-low-code-self-hosted-url-shortener/","icon":"🔗","label":"How to build a low-code, self-hosted URL shortener in 3 steps"},{"url":"https://n8n.io/blog/automate-your-data-processing-pipeline-in-9-steps-with-n8n/","icon":"⚙️","label":"Automate your data processing pipeline in 9 steps"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/automation-for-maintainers-of-open-source-projects/","icon":"🏷️","label":"How to automatically manage contributions to open-source projects"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/why-this-product-manager-loves-workflow-automation-with-n8n/","icon":"🧠","label":"Why this Product Manager loves workflow automation with n8n"},{"url":"https://n8n.io/blog/sending-automated-congratulations-with-google-sheets-twilio-and-n8n/","icon":"🙌","label":"Sending Automated Congratulations with Google Sheets, Twilio, and n8n "},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.if/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Flow"]}}},"group":"[\"transform\"]","defaults":{"name":"If","color":"#408000"},"iconData":{"icon":"map-signs","type":"icon"},"displayName":"If","typeVersion":2,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":38,"icon":"fa:pen","name":"n8n-nodes-base.set","codex":{"data":{"alias":["Set","JS","JSON","Filter","Transform","Map"],"resources":{"generic":[{"url":"https://n8n.io/blog/learn-to-automate-your-factorys-incident-reporting-a-step-by-step-guide/","icon":"🏭","label":"Learn to Automate Your Factory's Incident Reporting: A Step by Step Guide"},{"url":"https://n8n.io/blog/2021-the-year-to-automate-the-new-you-with-n8n/","icon":"☀️","label":"2021: The Year to Automate the New You with n8n"},{"url":"https://n8n.io/blog/automatically-pulling-and-visualizing-data-with-n8n/","icon":"📈","label":"Automatically pulling and visualizing data with n8n"},{"url":"https://n8n.io/blog/database-monitoring-and-alerting-with-n8n/","icon":"📡","label":"Database Monitoring and Alerting with n8n"},{"url":"https://n8n.io/blog/automatically-adding-expense-receipts-to-google-sheets-with-telegram-mindee-twilio-and-n8n/","icon":"🧾","label":"Automatically Adding Expense Receipts to Google Sheets with Telegram, Mindee, Twilio, and n8n"},{"url":"https://n8n.io/blog/no-code-ecommerce-workflow-automations/","icon":"store","label":"6 e-commerce workflows to power up your Shopify s"},{"url":"https://n8n.io/blog/how-to-build-a-low-code-self-hosted-url-shortener/","icon":"🔗","label":"How to build a low-code, self-hosted URL shortener in 3 steps"},{"url":"https://n8n.io/blog/automate-your-data-processing-pipeline-in-9-steps-with-n8n/","icon":"⚙️","label":"Automate your data processing pipeline in 9 steps"},{"url":"https://n8n.io/blog/how-to-get-started-with-crm-automation-and-no-code-workflow-ideas/","icon":"👥","label":"How to get started with CRM automation (with 3 no-code workflow ideas"},{"url":"https://n8n.io/blog/5-tasks-you-can-automate-with-notion-api/","icon":"⚡️","label":"5 tasks you can automate with the new Notion API "},{"url":"https://n8n.io/blog/automate-google-apps-for-productivity/","icon":"💡","label":"15 Google apps you can combine and automate to increase productivity"},{"url":"https://n8n.io/blog/how-uproc-scraped-a-multi-page-website-with-a-low-code-workflow/","icon":" 🕸️","label":"How uProc scraped a multi-page website with a low-code workflow"},{"url":"https://n8n.io/blog/building-an-expense-tracking-app-in-10-minutes/","icon":"📱","label":"Building an expense tracking app in 10 minutes"},{"url":"https://n8n.io/blog/the-ultimate-guide-to-automate-your-video-collaboration-with-whereby-mattermost-and-n8n/","icon":"📹","label":"The ultimate guide to automate your video collaboration with Whereby, Mattermost, and n8n"},{"url":"https://n8n.io/blog/5-workflow-automations-for-mattermost-that-we-love-at-n8n/","icon":"🤖","label":"5 workflow automations for Mattermost that we love at n8n"},{"url":"https://n8n.io/blog/learn-to-build-powerful-api-endpoints-using-webhooks/","icon":"🧰","label":"Learn to Build Powerful API Endpoints Using Webhooks"},{"url":"https://n8n.io/blog/how-a-membership-development-manager-automates-his-work-and-investments/","icon":"📈","label":"How a Membership Development Manager automates his work and investments"},{"url":"https://n8n.io/blog/a-low-code-bitcoin-ticker-built-with-questdb-and-n8n-io/","icon":"📈","label":"A low-code bitcoin ticker built with QuestDB and n8n.io"},{"url":"https://n8n.io/blog/how-to-set-up-a-ci-cd-pipeline-with-no-code/","icon":"🎡","label":"How to set up a no-code CI/CD pipeline with GitHub and TravisCI"},{"url":"https://n8n.io/blog/benefits-of-automation-and-n8n-an-interview-with-hubspots-hugh-durkin/","icon":"🎖","label":"Benefits of automation and n8n: An interview with HubSpot's Hugh Durkin"},{"url":"https://n8n.io/blog/how-goomer-automated-their-operations-with-over-200-n8n-workflows/","icon":"🛵","label":"How Goomer automated their operations with over 200 n8n workflows"},{"url":"https://n8n.io/blog/aws-workflow-automation/","label":"7 no-code workflow automations for Amazon Web Services"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.set/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Data Transformation"]}}},"group":"[\"input\"]","defaults":{"name":"Edit Fields"},"iconData":{"icon":"pen","type":"icon"},"displayName":"Edit Fields (Set)","typeVersion":3,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":41,"icon":"fa:table","name":"n8n-nodes-base.spreadsheetFile","codex":{"data":{"alias":["_Excel","Excel","CSV","Sheet","Spreadsheet","xls","xlsx","ods"],"resources":{"generic":[{"url":"https://n8n.io/blog/build-your-own-virtual-assistant-with-n8n-a-step-by-step-guide/","icon":"👦","label":"Build your own virtual assistant with n8n: A step by step guide"}],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.converttofile/"}]},"categories":["Data & Storage","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Files"]}}},"group":"[\"transform\"]","defaults":{"name":"Spreadsheet File","color":"#2244FF"},"iconData":{"icon":"table","type":"icon"},"displayName":"Spreadsheet File","typeVersion":2,"nodeCategories":[{"id":3,"name":"Data & Storage"},{"id":9,"name":"Core Nodes"}]},{"id":535,"icon":"file:webhook.svg","name":"n8n-nodes-base.respondToWebhook","codex":{"data":{"resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.respondtowebhook/"}]},"categories":["Core Nodes","Utility"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"transform\"]","defaults":{"name":"Respond to Webhook"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0OCIgaGVpZ2h0PSI0OCI+PHBhdGggZmlsbD0iIzM3NDc0ZiIgZD0iTTM1IDM3Yy0yLjIgMC00LTEuOC00LTRzMS44LTQgNC00IDQgMS44IDQgNC0xLjggNC00IDQiLz48cGF0aCBmaWxsPSIjMzc0NzRmIiBkPSJNMzUgNDNjLTMgMC01LjktMS40LTcuOC0zLjdsMy4xLTIuNWMxLjEgMS40IDIuOSAyLjMgNC43IDIuMyAzLjMgMCA2LTIuNyA2LTZzLTIuNy02LTYtNmMtMSAwLTIgLjMtMi45LjdsLTEuNyAxTDIzLjMgMTZsMy41LTEuOSA1LjMgOS40YzEtLjMgMi0uNSAzLS41IDUuNSAwIDEwIDQuNSAxMCAxMFM0MC41IDQzIDM1IDQzIi8+PHBhdGggZmlsbD0iIzM3NDc0ZiIgZD0iTTE0IDQzQzguNSA0MyA0IDM4LjUgNCAzM2MwLTQuNiAzLjEtOC41IDcuNS05LjdsMSAzLjlDOS45IDI3LjkgOCAzMC4zIDggMzNjMCAzLjMgMi43IDYgNiA2czYtMi43IDYtNnYtMmgxNXY0SDIzLjhjLS45IDQuNi01IDgtOS44IDgiLz48cGF0aCBmaWxsPSIjZTkxZTYzIiBkPSJNMTQgMzdjLTIuMiAwLTQtMS44LTQtNHMxLjgtNCA0LTQgNCAxLjggNCA0LTEuOCA0LTQgNCIvPjxwYXRoIGZpbGw9IiMzNzQ3NGYiIGQ9Ik0yNSAxOWMtMi4yIDAtNC0xLjgtNC00czEuOC00IDQtNCA0IDEuOCA0IDQtMS44IDQtNCA0Ii8+PHBhdGggZmlsbD0iI2U5MWU2MyIgZD0ibTE1LjcgMzQtMy40LTIgNS45LTkuN2MtMi0xLjktMy4yLTQuNS0zLjItNy4zIDAtNS41IDQuNS0xMCAxMC0xMHMxMCA0LjUgMTAgMTBjMCAuOS0uMSAxLjctLjMgMi41bC0zLjktMWMuMS0uNS4yLTEgLjItMS41IDAtMy4zLTIuNy02LTYtNnMtNiAyLjctNiA2YzAgMi4xIDEuMSA0IDIuOSA1LjFsMS43IDF6Ii8+PC9zdmc+"},"displayName":"Respond to Webhook","typeVersion":2,"nodeCategories":[{"id":7,"name":"Utility"},{"id":9,"name":"Core Nodes"}]},{"id":565,"icon":"fa:sticky-note","name":"n8n-nodes-base.stickyNote","codex":{"data":{"alias":["Comments","Notes","Sticky"],"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers"]}}},"group":"[\"input\"]","defaults":{"name":"Sticky Note","color":"#FFD233"},"iconData":{"icon":"sticky-note","type":"icon"},"displayName":"Sticky Note","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]},{"id":834,"icon":"file:code.svg","name":"n8n-nodes-base.code","codex":{"data":{"alias":["cpde","Javascript","JS","Python","Script","Custom Code","Function"],"details":"The Code node allows you to execute JavaScript in your workflow.","resources":{"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.code/"}]},"categories":["Development","Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0","subcategories":{"Core Nodes":["Helpers","Data Transformation"]}}},"group":"[\"transform\"]","defaults":{"name":"Code"},"iconData":{"type":"file","fileBuffer":"data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTEyIiBoZWlnaHQ9IjUxMiIgdmlld0JveD0iMCAwIDUxMiA1MTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMF8xMTcxXzQ0MSkiPgo8cGF0aCBkPSJNMTcwLjI4MyA0OEgxOTYuNUMyMDMuMTI3IDQ4IDIwOC41IDQyLjYyNzQgMjA4LjUgMzZWMTJDMjA4LjUgNS4zNzI1OCAyMDMuMTI3IDAgMTk2LjUgMEgxNzAuMjgzQzEyNi4xIDAgOTAuMjgzIDM1LjgxNzIgOTAuMjgzIDgwVjE3NkM5MC4yODMgMjA2LjkyOCA2NS4yMTA5IDIzMiAzNC4yODMgMjMySDIzQzE2LjM3MjYgMjMyIDExIDIzNy4zNzIgMTEgMjQ0VjI2OEMxMSAyNzQuNjI3IDE2LjM3MjQgMjgwIDIyLjk5OTYgMjgwTDM0LjI4MyAyODBDNjUuMjEwOSAyODAgOTAuMjgzIDMwNS4wNzIgOTAuMjgzIDMzNlY0NDBDOTAuMjgzIDQ3OS43NjQgMTIyLjUxOCA1MTIgMTYyLjI4MyA1MTJIMTk2LjVDMjAzLjEyNyA1MTIgMjA4LjUgNTA2LjYyNyAyMDguNSA1MDBWNDc2QzIwOC41IDQ2OS4zNzMgMjAzLjEyNyA0NjQgMTk2LjUgNDY0SDE2Mi4yODNDMTQ5LjAyOCA0NjQgMTM4LjI4MyA0NTMuMjU1IDEzOC4yODMgNDQwVjMzNkMxMzguMjgzIDMwOS4wMjIgMTI4LjAxMSAyODQuNDQzIDExMS4xNjQgMjY1Ljk2MUMxMDYuMTA5IDI2MC40MTYgMTA2LjEwOSAyNTEuNTg0IDExMS4xNjQgMjQ2LjAzOUMxMjguMDExIDIyNy41NTcgMTM4LjI4MyAyMDIuOTc4IDEzOC4yODMgMTc2VjgwQzEzOC4yODMgNjIuMzI2OSAxNTIuNjEgNDggMTcwLjI4MyA0OFoiIGZpbGw9IiNGRjk5MjIiLz4KPHBhdGggZD0iTTMwNSAzNkMzMDUgNDIuNjI3NCAzMTAuMzczIDQ4IDMxNyA0OEgzNDIuOTc5QzM2MC42NTIgNDggMzc0Ljk3OCA2Mi4zMjY5IDM3NC45NzggODBWMTc2QzM3NC45NzggMjAyLjk3OCAzODUuMjUxIDIyNy41NTcgNDAyLjA5OCAyNDYuMDM5QzQwNy4xNTMgMjUxLjU4NCA0MDcuMTUzIDI2MC40MTYgNDAyLjA5OCAyNjUuOTYxQzM4NS4yNTEgMjg0LjQ0MyAzNzQuOTc4IDMwOS4wMjIgMzc0Ljk3OCAzMzZWNDMyQzM3NC45NzggNDQ5LjY3MyAzNjAuNjUyIDQ2NCAzNDIuOTc5IDQ2NEgzMTdDMzEwLjM3MyA0NjQgMzA1IDQ2OS4zNzMgMzA1IDQ3NlY1MDBDMzA1IDUwNi42MjcgMzEwLjM3MyA1MTIgMzE3IDUxMkgzNDIuOTc5QzM4Ny4xNjEgNTEyIDQyMi45NzggNDc2LjE4MyA0MjIuOTc4IDQzMlYzMzZDNDIyLjk3OCAzMDUuMDcyIDQ0OC4wNTEgMjgwIDQ3OC45NzkgMjgwSDQ5MEM0OTYuNjI3IDI4MCA1MDIgMjc0LjYyOCA1MDIgMjY4VjI0NEM1MDIgMjM3LjM3MyA0OTYuNjI4IDIzMiA0OTAgMjMyTDQ3OC45NzkgMjMyQzQ0OC4wNTEgMjMyIDQyMi45NzggMjA2LjkyOCA0MjIuOTc4IDE3NlY4MEM0MjIuOTc4IDM1LjgxNzIgMzg3LjE2MSAwIDM0Mi45NzkgMEgzMTdDMzEwLjM3MyAwIDMwNSA1LjM3MjU4IDMwNSAxMlYzNloiIGZpbGw9IiNGRjk5MjIiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8xMTcxXzQ0MSI+CjxyZWN0IHdpZHRoPSI1MTIiIGhlaWdodD0iNTEyIiBmaWxsPSJ3aGl0ZSIvPgo8L2NsaXBQYXRoPgo8L2RlZnM+Cjwvc3ZnPgo="},"displayName":"Code","typeVersion":2,"nodeCategories":[{"id":5,"name":"Development"},{"id":9,"name":"Core Nodes"}]},{"id":838,"icon":"fa:mouse-pointer","name":"n8n-nodes-base.manualTrigger","codex":{"data":{"resources":{"generic":[],"primaryDocumentation":[{"url":"https://docs.n8n.io/integrations/builtin/core-nodes/n8n-nodes-base.manualworkflowtrigger/"}]},"categories":["Core Nodes"],"nodeVersion":"1.0","codexVersion":"1.0"}},"group":"[\"trigger\"]","defaults":{"name":"When clicking ‘Execute workflow’","color":"#909298"},"iconData":{"icon":"mouse-pointer","type":"icon"},"displayName":"Manual Trigger","typeVersion":1,"nodeCategories":[{"id":9,"name":"Core Nodes"}]}],"categories":[{"id":16,"name":"DevOps"},{"id":49,"name":"AI Summarization"}],"image":[]}}