{
  "id": "YVrB6Y4FQPgeABQY",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Route low-stock inventory alerts to Slack",
  "tags": [],
  "nodes": [
    {
      "id": "b561da51-9632-49aa-ae15-124b7d35dd3f",
      "name": "Template Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -64,
        -48
      ],
      "parameters": {
        "color": 4,
        "width": 680,
        "height": 1012,
        "content": "## \ud83d\udce6 Route Low-Stock Inventory Alerts to Slack\n\n## Who's it for\nSmall retailers, D2C brands, or restaurants tracking inventory in a Google Sheet who want their team notified in Slack when something's running low or has completely run out, with the supplier's contact info right there so reordering doesn't require a separate lookup.\n\n## How it works\nOnce a day, the workflow checks your inventory sheet and classifies every item as healthy, low stock, or out of stock. Items that already got an alert today are skipped, so the channel doesn't get the same item repeated every run. Out-of-stock items get an urgent Slack alert, low-stock items get a less urgent one, both include the supplier's contact so whoever sees it can act immediately. Every alert sent updates the sheet so it isn't repeated.\n\n## How to set up\n1. Connect your Google Sheets credentials and point the workflow at your Inventory sheet.\n2. Connect your Slack credentials and note the channel ID you want alerts posted to.\n3. Make sure your sheet has these columns: row_id, item_name, current_stock, reorder_threshold, unit, supplier_name, supplier_contact, last_alert_date.\n4. Open the Set Configuration node and fill in your Sheet ID and Slack channel ID.\n5. Set your preferred check time in the Schedule Trigger.\n6. Activate the workflow.\n\n## Requirements\n- Google Sheets account\n- Slack workspace with a bot token\n\n## How to customize\nAdjust reorder_threshold per item in your sheet to control what counts as \"low\" for each product. Edit the alert message templates to match how your team likes to communicate."
      },
      "typeVersion": 1
    },
    {
      "id": "6b9c217e-57ef-4b63-9af9-8ccecc6e592e",
      "name": "Section - Trigger and Setup",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        688,
        304
      ],
      "parameters": {
        "color": 7,
        "width": 680,
        "height": 340,
        "content": "## 1\ufe0f\u20e3 2\ufe0f\u20e3 3\ufe0f\u20e3 Trigger + Configuration + Fetch\nRuns daily, pulls every inventory row. Required columns: row_id, item_name, current_stock, reorder_threshold, unit, supplier_name, supplier_contact, last_alert_date."
      },
      "typeVersion": 1
    },
    {
      "id": "d24e1aaa-7c02-46cd-b000-b1cd57050566",
      "name": "Section - Classify and Filter",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1408,
        272
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 360,
        "content": "## 4\ufe0f\u20e3 5\ufe0f\u20e3 Classify + Filter\nEach item gets a status (healthy, low_stock, out_of_stock). The filter drops healthy items and anything already alerted today, so the channel doesn't get the same item repeated on every run."
      },
      "typeVersion": 1
    },
    {
      "id": "b7b7f125-a054-49f7-9321-37a9c644b9f3",
      "name": "Section - Urgency Branch",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1952,
        208
      ],
      "parameters": {
        "color": 7,
        "width": 700,
        "height": 604,
        "content": "## 6\ufe0f\u20e3 Branch by Urgency\nOut of stock gets a more urgent-looking alert than low stock, both include the supplier's contact so someone can act on it right away without a separate lookup."
      },
      "typeVersion": 1
    },
    {
      "id": "b454cb16-b50f-444d-a325-206fc415d960",
      "name": "Section - Mark Alerted",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2688,
        288
      ],
      "parameters": {
        "color": 7,
        "width": 320,
        "height": 376,
        "content": "## 7\ufe0f\u20e3 Log the Alert\nBoth branches land here. Updates last_alert_date so this item won't be alerted on again until tomorrow."
      },
      "typeVersion": 1
    },
    {
      "id": "22584e96-293e-4ebc-bb9c-ec2930eedf5c",
      "name": "Every Morning",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        720,
        480
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "93adffb8-46b5-4b6e-acb9-144e99d6fba6",
      "name": "Set Configuration",
      "type": "n8n-nodes-base.set",
      "position": [
        960,
        480
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "cfg-1",
              "name": "sheet_id",
              "type": "string",
              "value": "REPLACE_WITH_GOOGLE_SHEET_ID"
            },
            {
              "id": "cfg-2",
              "name": "inventory_sheet_name",
              "type": "string",
              "value": "Inventory"
            },
            {
              "id": "cfg-3",
              "name": "slack_channel_id",
              "type": "string",
              "value": "REPLACE_WITH_SLACK_CHANNEL_ID"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "f3d47c7c-0fd7-4a46-b109-ade98d287ea5",
      "name": "Fetch Inventory",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1232,
        480
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.inventory_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "8a674404-9224-4e0b-b156-0de5e1ab95ed",
      "name": "Compute Stock Status",
      "type": "n8n-nodes-base.code",
      "position": [
        1472,
        480
      ],
      "parameters": {
        "jsCode": "const todayStr = new Date().toISOString().slice(0, 10);\n\nreturn $input.all().map(item => {\n  const m = item.json;\n  const stock = Number(m.current_stock);\n  const threshold = Number(m.reorder_threshold);\n\n  let status = 'healthy';\n  if (stock <= 0) {\n    status = 'out_of_stock';\n  } else if (stock <= threshold) {\n    status = 'low_stock';\n  }\n\n  const alreadyAlertedToday = m.last_alert_date === todayStr;\n\n  return {\n    json: {\n      ...m,\n      status,\n      already_alerted_today: alreadyAlertedToday,\n      today_date: todayStr\n    }\n  };\n});"
      },
      "typeVersion": 2
    },
    {
      "id": "4b7f15e3-dd6a-4ee1-8fe0-f782e97ccc65",
      "name": "Filter Needs Alert",
      "type": "n8n-nodes-base.filter",
      "position": [
        1728,
        480
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0190e727-d9e2-4be6-a1ec-1bbebdad45ce",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "healthy"
            },
            {
              "id": "00d77e20-4080-4a3b-9e43-2fc87d96c155",
              "operator": {
                "type": "boolean",
                "operation": "notEquals"
              },
              "leftValue": "={{ $json.already_alerted_today }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "acab49e5-ef77-465d-a3d6-570d1ee7fa62",
      "name": "Is Out of Stock?",
      "type": "n8n-nodes-base.if",
      "position": [
        2032,
        480
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "8aa8039d-0a7f-4c6b-8c36-f29d9b88d64b",
              "operator": {
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "={{ $json.status }}",
              "rightValue": "out_of_stock"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "68ae24fa-9ace-4678-b812-764b3ee83315",
      "name": "Send Urgent Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        2336,
        384
      ],
      "parameters": {
        "text": "=\ud83d\udd34 OUT OF STOCK: {{ $json.item_name }} (0 {{ $json.unit }} left). Reorder from {{ $json.supplier_name }} ({{ $json.supplier_contact }}) today.",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.slack_channel_id }}"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9682a090-7895-45f0-8517-1db837f1fb97",
      "name": "Send Low Stock Slack Alert",
      "type": "n8n-nodes-base.slack",
      "position": [
        2352,
        608
      ],
      "parameters": {
        "text": "=\ud83d\udfe1 Running low: {{ $json.item_name }} ({{ $json.current_stock }} {{ $json.unit }} left, reorder threshold is {{ $json.reorder_threshold }}). Supplier: {{ $json.supplier_name }} ({{ $json.supplier_contact }}).",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.slack_channel_id }}"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9cd25876-0c93-4540-ade6-7f830d316337",
      "name": "Update Sheet - Mark Alerted",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2736,
        480
      ],
      "parameters": {
        "columns": {
          "value": {
            "row_id": "={{ $json.row_id }}",
            "last_alert_date": "={{ $json.today_date }}"
          },
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "row_id"
          ]
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "={{ $('Set Configuration').item.json.inventory_sheet_name }}"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Set Configuration').item.json.sheet_id }}"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": false,
    "executionOrder": "v1"
  },
  "versionId": "004ffeb8-cf89-47d4-b90a-1e020f867995",
  "nodeGroups": [],
  "connections": {
    "Every Morning": {
      "main": [
        [
          {
            "node": "Set Configuration",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Inventory": {
      "main": [
        [
          {
            "node": "Compute Stock Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Out of Stock?": {
      "main": [
        [
          {
            "node": "Send Urgent Slack Alert",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Send Low Stock Slack Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Configuration": {
      "main": [
        [
          {
            "node": "Fetch Inventory",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Needs Alert": {
      "main": [
        [
          {
            "node": "Is Out of Stock?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Compute Stock Status": {
      "main": [
        [
          {
            "node": "Filter Needs Alert",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Urgent Slack Alert": {
      "main": [
        [
          {
            "node": "Update Sheet - Mark Alerted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Low Stock Slack Alert": {
      "main": [
        [
          {
            "node": "Update Sheet - Mark Alerted",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}