AutomationFlowsSlack & Telegram › Log Slack Invoice Approvals to Google Sheets

Log Slack Invoice Approvals to Google Sheets

Original n8n title: Log Invoice Approval Decisions From Slack to Google Sheets

ByFelix @easybits on n8n.io

Listens for button clicks from the Invoice → Slack Approval workflow. When someone clicks Approve, Reject, or Flag on an invoice in Slack, this workflow captures that decision, logs it to Google Sheets, and sends a confirmation notification. Webhook Trigger – Receives POST…

Webhook trigger★★★★☆ complexity17 nodesGoogle SheetsSlack
Slack & Telegram Trigger: Webhook Nodes: 17 Complexity: ★★★★☆ Added:

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

This workflow follows the Google Sheets → Slack 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": "Invoice Approval Handler (Slack Listener)",
  "tags": [
    {
      "name": "Finance"
    },
    {
      "name": "Invoice Automation"
    },
    {
      "name": "Slack"
    }
  ],
  "nodes": [
    {
      "id": "f024271f-524f-4ab5-b7fb-43ed93e2bea3",
      "name": "Receive Slack Button Click",
      "type": "n8n-nodes-base.webhook",
      "position": [
        -64,
        416
      ],
      "parameters": {
        "path": "invoice-approval-handler",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 2
    },
    {
      "id": "3c8f8381-a479-4e37-a35a-32f185762422",
      "name": "Parse Slack Payload",
      "type": "n8n-nodes-base.set",
      "position": [
        208,
        416
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "a493fcd6-0bf3-4887-bd69-4026c14c3d22",
              "name": "payload",
              "type": "object",
              "value": "={{ JSON.parse($json.body.payload) }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "e22d06ad-d82d-433d-8360-3089e8ad35e4",
      "name": "Extract Decision & Invoice Data",
      "type": "n8n-nodes-base.set",
      "position": [
        480,
        416
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "ecc7c2a7-85a2-4bb6-8213-06b409ab9281",
              "name": "decision",
              "type": "string",
              "value": "={{ $json.payload.actions[0].value }}"
            },
            {
              "id": "d6f8aad0-508f-4a38-99ed-00eb76bcd7f8",
              "name": "decided_by",
              "type": "string",
              "value": "={{ $json.payload.user.name }}"
            },
            {
              "id": "277dbaef-143b-4603-85d4-b69f1284b3d9",
              "name": "decided_by_id",
              "type": "string",
              "value": "={{ $json.payload.user.id }}"
            },
            {
              "id": "44951b7f-73c9-48df-b8ce-189bbcaa2112",
              "name": "channel_id",
              "type": "string",
              "value": "={{ $json.payload.channel.id }}"
            },
            {
              "id": "224e0814-6d1f-4ff8-90d5-a08bb05da837",
              "name": "message_ts",
              "type": "string",
              "value": "={{ $json.payload.message.ts }}"
            },
            {
              "id": "1d96a304-f9ca-43e1-b1c2-590b8ce92c21",
              "name": "supplier_name",
              "type": "string",
              "value": "={{ $json.payload.message.blocks[1].fields[0].text.split('\\n')[1] }}"
            },
            {
              "id": "99f3f0a9-b595-4057-ac33-2421cc5b6ca5",
              "name": "invoice_number",
              "type": "string",
              "value": "={{ $json.payload.message.blocks[1].fields[1].text.split('\\n')[1] }}"
            },
            {
              "id": "fb44a6ec-6441-4c8e-9143-85fe7577211c",
              "name": "amount",
              "type": "string",
              "value": "={{ $json.payload.message.blocks[1].fields[2].text.split('\\n')[1] }}"
            },
            {
              "id": "3b17ccc8-108a-4586-b6de-2b1685b21539",
              "name": "invoice_date",
              "type": "string",
              "value": "={{ $json.payload.message.blocks[1].fields[3].text.split('\\n')[1] }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "899c3038-7397-441e-990e-8ef38977fa97",
      "name": "Route: Approved / Rejected / Flagged",
      "type": "n8n-nodes-base.switch",
      "position": [
        752,
        400
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Approved",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.decision }}",
                    "rightValue": "approved"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Rejected",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.decision }}",
                    "rightValue": "rejected"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Flagged",
              "conditions": {
                "options": {
                  "version": 2,
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.decision }}",
                    "rightValue": "flagged"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3.2
    },
    {
      "id": "dfe0a576-d0f1-4b6e-affb-ec93ab80597f",
      "name": "Log to Sheets: Approved",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1024,
        240
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.invoice_date }}",
            "Amount": "={{ $json.amount }}",
            "Supplier Name": "={{ $json.supplier_name }}",
            "Invoice Number": "={{ $json.invoice_number }}"
          },
          "schema": [
            {
              "id": "Supplier Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Supplier Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Approved"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "9fb05679-ed5b-44b2-a72a-e2f0f88ea622",
      "name": "Log to Sheets: Rejected",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1024,
        416
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.invoice_date }}",
            "Amount": "={{ $json.amount }}",
            "Supplier Name": "={{ $json.supplier_name }}",
            "Invoice Number": "={{ $json.invoice_number }}"
          },
          "schema": [
            {
              "id": "Supplier Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Supplier Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Rejected"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "a2d9b4fe-16e0-4514-aa9c-daf65ee080ad",
      "name": "Log to Sheets: Flagged",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1024,
        592
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.invoice_date }}",
            "Amount": "={{ $json.amount }}",
            "Supplier Name": "={{ $json.supplier_name }}",
            "Invoice Number": "={{ $json.invoice_number }}"
          },
          "schema": [
            {
              "id": "Supplier Name",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Supplier Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Invoice Number",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Invoice Number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Amount",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Amount",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": []
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Flagged"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "f444c5fb-0d76-413d-b170-4dd085d668c8",
      "name": "Slack DM: Approved \u2705",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        240
      ],
      "parameters": {
        "text": "=\u2705 *Invoice Approved & Ready to Pay*\n\n*Supplier:* {{ $json['Supplier Name'] }}\n*Invoice #:* {{ $json['Invoice Number'] }}\n*Amount:* {{ $json.Amount }}\n*Date:* {{ $json.Date }}\n*Approved by:* {{ $('Route: Approved / Rejected / Flagged').item.json.decided_by }}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_USER_ID"
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "58e53f7a-c8f1-4ddd-b8ad-f16691d55cab",
      "name": "Slack DM: Rejected \u274c",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        416
      ],
      "parameters": {
        "text": "=\u274c *Invoice Rejected*\n\n*Supplier:* {{ $json['Supplier Name'] }}\n*Invoice #:* {{ $json['Invoice Number'] }}\n*Amount:* {{ $json.Amount }}\n*Date:* {{ $json.Date }}\n*Rejected by:* {{ $('Route: Approved / Rejected / Flagged').item.json.decided_by }}",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_USER_ID"
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "5473fdea-f831-4da8-8c0d-94fcae527931",
      "name": "Slack DM: Flagged \ud83d\udea9",
      "type": "n8n-nodes-base.slack",
      "position": [
        1296,
        592
      ],
      "parameters": {
        "text": "=\ud83d\udea9 *Invoice Flagged for Review*\n\n*Supplier:* {{ $json['Supplier Name'] }}\n*Invoice #:* {{ $json['Invoice Number'] }}\n*Amount:* {{ $json.Amount }}\n*Date:* {{ $json.Date }}\n*Flagged by:* {{ $('Route: Approved / Rejected / Flagged').item.json.decided_by }}\n\n\u26a0\ufe0f Please review this invoice manually.",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_USER_ID"
        },
        "select": "user",
        "otherOptions": {}
      },
      "typeVersion": 2.3
    },
    {
      "id": "45e5c100-b3c5-430d-b5cb-33c8ba1b7f8a",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -144,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 272,
        "content": "### \ud83d\udd14 Slack Webhook\nReceives button click events from Slack Interactivity"
      },
      "typeVersion": 1
    },
    {
      "id": "6ebf1842-3c96-425a-9cf5-454a491bb489",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        128,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 272,
        "content": "### \ud83d\udce6 Parse Payload\nConverts Slack's URL-encoded payload into JSON object"
      },
      "typeVersion": 1
    },
    {
      "id": "f536f100-b96e-45dd-aa23-8b2a36d7063f",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        400,
        320
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 272,
        "content": "### \ud83d\udccb Extract Decision Data\nPulls decision, user, and invoice details from Slack message"
      },
      "typeVersion": 1
    },
    {
      "id": "0c8770a8-1c00-455d-acb0-b6b6f3f48c5b",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        288
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 336,
        "content": "### \ud83d\udd00 Route by Decision\nBranches flow: Approved \u2192 Rejected \u2192 Flagged"
      },
      "typeVersion": 1
    },
    {
      "id": "3e58c7fc-8301-490f-acaa-85a013c82ef1",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        944,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 608,
        "content": "### \ud83d\udcca Log to Sheets\nAppends invoice data to the appropriate Google Sheets tab"
      },
      "typeVersion": 1
    },
    {
      "id": "783c33e9-68a3-4082-9184-a2a4db6f04e4",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1216,
        144
      ],
      "parameters": {
        "color": 7,
        "width": 256,
        "height": 608,
        "content": "### \ud83d\udcac Send Confirmation\nNotifies the approver via Slack DM"
      },
      "typeVersion": 1
    },
    {
      "id": "32f0f5bd-897b-49dc-b85f-71dcfe5505a6",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -832,
        -160
      ],
      "parameters": {
        "width": 672,
        "height": 1264,
        "content": "# \ud83d\udce5 Invoice Approval Handler\n(Slack Button Listener)\n\n## What This Workflow Does\nListens for button clicks from the **Invoice \u2192 Slack Approval** workflow. When someone clicks Approve, Reject, or Flag on an invoice in Slack, this workflow captures that decision, logs it to **Google Sheets**, and sends a confirmation notification.\n\n## How It Works\n1. **Webhook Trigger** \u2013 Receives POST request from Slack when a button is clicked\n2. **Parse Payload** \u2013 Extracts the JSON payload from Slack's request body\n3. **Extract Decision Data** \u2013 Pulls decision, user info, and invoice details from the message\n4. **Route by Decision** \u2013 Branches to Approved, Rejected, or Flagged path\n5. **Log to Sheets** \u2013 Appends invoice data to the appropriate sheet tab\n6. **Notify via Slack** \u2013 Sends confirmation DM to the approver\n\n## Decision Routes\n- \u2705 **Approved** \u2192 Logs to \"Approved\" sheet \u2192 DM confirmation\n- \u274c **Rejected** \u2192 Logs to \"Rejected\" sheet \u2192 DM confirmation\n- \ud83d\udea9 **Flagged** \u2192 Logs to \"Flagged\" sheet \u2192 DM for manual review\n\n---\n\n## Setup Guide\n\n### 1. Create Google Sheet\n1. Create a new Google Sheet with 3 tabs: `Approved`, `Rejected`, `Flagged`\n2. Add these column headers to each tab:\n   - Supplier Name\n   - Invoice Number\n   - Amount\n   - Date\n3. Copy the **Sheet ID** from the URL\n\n### 2. Connect the Nodes in n8n\n1. Add your **Google Sheets OAuth2** credential to all three logging nodes\n2. Update the **Document ID** in each Google Sheets node to your Sheet ID\n3. Add your **Slack API** credential to all three notification nodes\n4. Update the **User ID** in the notification nodes (or change to channel)\n\n### 3. Configure Slack Interactivity\n1. Go to **api.slack.com/apps** \u2192 your app \u2192 **Interactivity & Shortcuts**\n2. Set the Request URL to this workflow's webhook URL\n3. Save Changes\n\n### 4. Activate & Test\n1. Click **Active** in the top-right corner of n8n\n2. Trigger the Invoice Approval workflow to send a Slack message\n3. Click a button in Slack\n4. Check Google Sheets and Slack for results"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "connections": {
    "Parse Slack Payload": {
      "main": [
        [
          {
            "node": "Extract Decision & Invoice Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Sheets: Flagged": {
      "main": [
        [
          {
            "node": "Slack DM: Flagged \ud83d\udea9",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Sheets: Approved": {
      "main": [
        [
          {
            "node": "Slack DM: Approved \u2705",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log to Sheets: Rejected": {
      "main": [
        [
          {
            "node": "Slack DM: Rejected \u274c",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Receive Slack Button Click": {
      "main": [
        [
          {
            "node": "Parse Slack Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Decision & Invoice Data": {
      "main": [
        [
          {
            "node": "Route: Approved / Rejected / Flagged",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route: Approved / Rejected / Flagged": {
      "main": [
        [
          {
            "node": "Log to Sheets: Approved",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log to Sheets: Rejected",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Log to Sheets: Flagged",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Pro

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

About this workflow

Listens for button clicks from the Invoice → Slack Approval workflow. When someone clicks Approve, Reject, or Flag on an invoice in Slack, this workflow captures that decision, logs it to Google Sheets, and sends a confirmation notification. Webhook Trigger – Receives POST…

Source: https://n8n.io/workflows/14515/ — 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 is a complete, production-ready solution for recovering abandoned carts in Shopify stores using a multi-channel, multi-touch approach. It automates personalized follow-ups via Email, SMS

HTTP Request, Shopify, SendGrid +5
Slack & Telegram

Turn every sales meeting into a coaching opportunity. This workflow automatically analyzes tldv meeting recordings using OpenAI (GPT-4) to provide instant, actionable feedback to your sales team.

HTTP Request, Slack, Google Sheets
Slack & Telegram

Automated video processing system that monitors S3 for new uploads, generates thumbnails and preview clips, extracts metadata, transcodes to multiple formats, and distributes to CDN with webhook notif

HTTP Request, Google Sheets, Slack
Slack & Telegram

Eliminate manual data entry from your accounts payable process. This workflow transforms raw invoice scans into structured financial records by combining UploadToURL for hosting, AWS Textract for OCR

N8N Nodes Uploadtourl, HTTP Request, Google Sheets +1
Slack & Telegram

Connect Fireflies and WayinVideo to this workflow once and every recorded sales call automatically generates a set of training clips delivered to your Slack channel. The moment Fireflies finishes tran

HTTP Request, Google Sheets, Slack