AutomationFlowsSlack & Telegram › Monitor Twilio Debugger Alerts and Post a Grouped Slack Digest

Monitor Twilio Debugger Alerts and Post a Grouped Slack Digest

Monitor Twilio debugger alerts and post a grouped Slack digest. Uses httpRequest, googleSheets, slack. Scheduled trigger; 13 nodes.

Cron / scheduled trigger★★★★☆ complexity13 nodesHTTP RequestGoogle SheetsSlack
Slack & Telegram Trigger: Cron / scheduled Nodes: 13 Complexity: ★★★★☆ Added:

This workflow follows the Google Sheets → HTTP Request 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
{
  "name": "Monitor Twilio debugger alerts and post a grouped Slack digest",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 60
            }
          ]
        }
      },
      "id": "a95d83e1-9c8d-49bf-96a7-65e617c3fdfa",
      "name": "Check Twilio on a Schedule",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.3,
      "position": [
        -64,
        752
      ]
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "lookback-minutes",
              "name": "lookbackMinutes",
              "value": 60,
              "type": "number"
            },
            {
              "id": "start-date",
              "name": "startDate",
              "value": "={{ $now.minus({ minutes: 60 }).toUTC().toISO() }}",
              "type": "string"
            },
            {
              "id": "page-size",
              "name": "pageSize",
              "value": 100,
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "id": "983c92b5-a896-429d-88a2-d9e983c50789",
      "name": "Compute Alert Window",
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        176,
        752
      ]
    },
    {
      "parameters": {
        "url": "https://monitor.twilio.com/v1/Alerts",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "twilioApi",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "StartDate",
              "value": "={{ $json.startDate }}"
            },
            {
              "name": "PageSize",
              "value": "={{ $json.pageSize }}"
            }
          ]
        },
        "options": {
          "response": {
            "response": {
              "responseFormat": "json"
            }
          }
        }
      },
      "id": "ca09b664-59b4-4f5e-8e64-e4b09c98a47d",
      "name": "Fetch Twilio Debugger Alerts",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.4,
      "position": [
        560,
        752
      ],
      "credentials": {
        "twilioApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "loose",
            "version": 2
          },
          "conditions": [
            {
              "id": "alerts-not-empty",
              "leftValue": "={{ $json.alerts }}",
              "operator": {
                "type": "array",
                "operation": "notEmpty"
              },
              "rightValue": ""
            }
          ],
          "combinator": "and"
        },
        "looseTypeValidation": true,
        "options": {}
      },
      "id": "8430d40a-82dd-4c7c-a4b4-41b16f3c7eaa",
      "name": "Any Alerts Returned?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        800,
        752
      ]
    },
    {
      "parameters": {
        "jsCode": "const response = $input.first().json;\nconst alerts = Array.isArray(response.alerts) ? response.alerts : [];\n\nconst groups = {};\nconst rows = [];\n\nfor (const alert of alerts) {\n  const errorCode = String(alert.error_code === undefined || alert.error_code === null ? 'unknown' : alert.error_code);\n  const logLevel = String(alert.log_level || 'unknown');\n  const key = errorCode + '|' + logLevel;\n\n  rows.push({\n    timestamp: alert.date_generated || '',\n    errorCode: errorCode,\n    logLevel: logLevel,\n    resourceSid: alert.resource_sid || '',\n    requestUrl: alert.request_url || '',\n    alertSid: alert.sid || ''\n  });\n\n  if (!groups[key]) {\n    groups[key] = { errorCode: errorCode, logLevel: logLevel, count: 0, sampleMessage: '', moreInfo: alert.more_info || '' };\n  }\n  groups[key].count = groups[key].count + 1;\n  if (!groups[key].sampleMessage) {\n    groups[key].sampleMessage = String(alert.alert_text || '').slice(0, 140);\n  }\n}\n\nconst grouped = Object.values(groups).sort(function (a, b) { return b.count - a.count; });\n\nconst severity = {};\nfor (const group of grouped) {\n  severity[group.logLevel] = (severity[group.logLevel] || 0) + group.count;\n}\n\nconst severityLine = Object.keys(severity).sort().map(function (level) {\n  return level + ': ' + severity[level];\n}).join(', ');\n\nconst topLines = grouped.slice(0, 5).map(function (group) {\n  return '- ' + group.errorCode + ' (' + group.logLevel + ') x' + group.count + ' ' + group.sampleMessage;\n}).join('\\n');\n\nconst digest = '*Twilio debugger digest*\\n' +\n  'Total alerts: ' + alerts.length + '\\n' +\n  'Severity: ' + (severityLine || 'none') + '\\n' +\n  'Distinct groups: ' + grouped.length + '\\n\\n' +\n  'Top error codes:\\n' + (topLines || '- none');\n\nreturn rows.map(function (row) {\n  return {\n    json: {\n      timestamp: row.timestamp,\n      errorCode: row.errorCode,\n      logLevel: row.logLevel,\n      resourceSid: row.resourceSid,\n      requestUrl: row.requestUrl,\n      alertSid: row.alertSid,\n      totalAlerts: alerts.length,\n      distinctGroups: grouped.length,\n      severityBreakdown: severityLine,\n      digest: digest\n    }\n  };\n});"
      },
      "id": "91defb78-3c74-45b1-b8e4-5088d784309e",
      "name": "Group Alerts by Code and Severity",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1248,
        736
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "REPLACE_WITH_YOUR_SPREADSHEET"
        },
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "REPLACE_WITH_YOUR_SHEET_TAB"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "timestamp": "={{ $json.timestamp }}",
            "error_code": "={{ $json.errorCode }}",
            "log_level": "={{ $json.logLevel }}",
            "resource_sid": "={{ $json.resourceSid }}",
            "request_url": "={{ $json.requestUrl }}",
            "alert_sid": "={{ $json.alertSid }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "displayName": "timestamp",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "error_code",
              "displayName": "error_code",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "log_level",
              "displayName": "log_level",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "resource_sid",
              "displayName": "resource_sid",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "request_url",
              "displayName": "request_url",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            },
            {
              "id": "alert_sid",
              "displayName": "alert_sid",
              "required": false,
              "defaultMatch": false,
              "display": true,
              "type": "string",
              "canBeUsedToMatch": true
            }
          ]
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        }
      },
      "id": "1a032299-a2e1-4b0e-9d34-d87a1143ed08",
      "name": "Append Alert Rows to Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        1808,
        736
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "name",
          "value": "REPLACE_WITH_YOUR_SLACK_CHANNEL"
        },
        "text": "={{ $json.digest }}",
        "otherOptions": {
          "includeLinkToWorkflow": false,
          "mrkdwn": true
        }
      },
      "id": "b56e0617-6edb-47ff-964d-b8a4cec68746",
      "name": "Post Grouped Digest to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        1808,
        944
      ],
      "executeOnce": true,
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "## Monitor Twilio debugger alerts and post a grouped Slack digest\n\n### How it works\n\n1. `Check Twilio on a Schedule` fires on the interval you set, hourly by default.\n2. `Compute Alert Window` builds an ISO-8601 start date of now minus the lookback minutes, plus a page size.\n3. `Fetch Twilio Debugger Alerts` GETs the Twilio Monitor Alerts API over HTTP Basic Auth, filtered to that window.\n4. `Any Alerts Returned?` ends the run when the alerts array is empty, so a quiet hour stays silent.\n5. `Group Alerts by Code and Severity` flattens each alert into a row, then collapses them by error code and log level.\n6. `Append Alert Rows to Sheet` writes one row per alert, and `Post Grouped Digest to Slack` posts one message per run.\n\n### Setup steps\n\n- [ ] Add an HTTP Basic Auth credential with your Twilio Account SID as the user and your Auth Token as the password, then assign it to `Fetch Twilio Debugger Alerts`.\n- [ ] Add a Google Sheets credential and a Slack credential for the two output nodes.\n- [ ] Pick the spreadsheet and tab, and give the tab this header row: timestamp, error_code, log_level, resource_sid, request_url, alert_sid.\n- [ ] Pick the channel in `Post Grouped Digest to Slack`.\n- [ ] Set the interval in `Check Twilio on a Schedule`, then match `lookbackMinutes` in `Compute Alert Window` so the window covers the gap between runs.\n\n### Customization\n\nRaise the page size for a busy account, filter the Code node to one log level if warnings are noise, or drop the Sheets branch and keep the Slack digest on its own.",
        "height": 704,
        "width": 992
      },
      "id": "c5341e41-9192-4f7b-bb5c-832c2f837360",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -160,
        -192
      ]
    },
    {
      "parameters": {
        "content": "## Required credential and read-only by design\n\nThis calls Twilio's Monitor Alerts API over raw HTTP, so it needs an HTTP Basic Auth credential built from your Account SID and Auth Token. The native Twilio node cannot supply it. The workflow only reads. It never sends a message.",
        "height": 240,
        "width": 448,
        "color": 3
      },
      "id": "9b88efc0-1018-4ba5-8b99-7974182d2e49",
      "name": "Credential and Safety Warning",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        896,
        -192
      ]
    },
    {
      "parameters": {
        "content": "## Set the alert window\n\nA schedule trigger fires on your interval, then one Set node builds the ISO-8601 start date and page size for the Twilio query.",
        "height": 384,
        "width": 560,
        "color": 7
      },
      "id": "4da464d3-79be-4783-8d92-199ee9ecc0b2",
      "name": "Stage Alert Window",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -160,
        576
      ]
    },
    {
      "parameters": {
        "content": "## Fetch alerts and stop when there are none\n\nThe HTTP Request node GETs the Monitor Alerts API with that window, and an IF node ends the run when the alerts array comes back empty.",
        "height": 384,
        "width": 560,
        "color": 7
      },
      "id": "d63787f0-0376-4056-a56c-a5e0a952a3cb",
      "name": "Stage Fetch and Guard",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        464,
        576
      ]
    },
    {
      "parameters": {
        "content": "## Group by error code and severity\n\nA Code node flattens every alert into a row, then collapses the set into one entry per error code and log level with a count and one sample message.",
        "height": 384,
        "width": 432,
        "color": 7
      },
      "id": "7ec35146-65e8-44f6-ae99-da3daff88893",
      "name": "Stage Grouping",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1088,
        544
      ]
    },
    {
      "parameters": {
        "content": "## Log the rows and post one digest\n\nGoogle Sheets appends one row per alert as the audit trail, and Slack gets a single grouped digest built from the counts.",
        "height": 608,
        "width": 496,
        "color": 7
      },
      "id": "658e5c10-4e34-4f68-b9de-131edf39205a",
      "name": "Stage Outputs",
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1600,
        544
      ]
    }
  ],
  "connections": {
    "Check Twilio on a Schedule": {
      "main": [
        [
          {
            "node": "Compute Alert Window",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compute Alert Window": {
      "main": [
        [
          {
            "node": "Fetch Twilio Debugger Alerts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Twilio Debugger Alerts": {
      "main": [
        [
          {
            "node": "Any Alerts Returned?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Any Alerts Returned?": {
      "main": [
        [
          {
            "node": "Group Alerts by Code and Severity",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Group Alerts by Code and Severity": {
      "main": [
        [
          {
            "node": "Append Alert Rows to Sheet",
            "type": "main",
            "index": 0
          },
          {
            "node": "Post Grouped Digest to Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1"
  }
}

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

Monitor Twilio debugger alerts and post a grouped Slack digest. Uses httpRequest, googleSheets, slack. Scheduled trigger; 13 nodes.

Source: https://github.com/exekyute/n8n-exekyute-templates/blob/main/pending-review/n8n-twilio-alert-monitor/workflow.json — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

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

Slack & Telegram

This workflow continuously monitors the Meta Ads Library for new creatives from a specific competitor pages, logs them into Google Sheets, and sends a concise Telegram notification with the number of

HTTP Request, Telegram, Google Sheets +1
Slack & Telegram

Enhance financial oversight with this automated n8n workflow. Triggered every 5 minutes, it fetches real-time bank transactions via an API, enriches and transforms the data, and applies smart logic to

HTTP Request, Email Send, Google Sheets +1
Slack & Telegram

This workflow automates competitive price intelligence using Bright Data's enterprise web scraping API. On a scheduled basis (default: daily at 9 AM), the system loops through configured competitor pr

HTTP Request, Google Sheets, Slack +1
Slack & Telegram

&gt; n8n, Binance API, Google Sheets, Slack, Telegram, Jira & Email

HTTP Request, Google Sheets, Slack +3
Slack & Telegram

SEO managers, content marketers, bloggers, and growth teams who want to automatically catch declining content performance before it's too late — without manually checking Google Search Console every w

HTTP Request, Google Sheets, Slack +1