AutomationFlowsAI & RAG › [2] Slack Approval → Ship/revise/confirm Handler (fixed)

[2] Slack Approval → Ship/revise/confirm Handler (fixed)

[2] Slack Approval → Ship/Revise/Confirm Handler (FIXED). Uses slackTrigger, httpRequest, lmChatAnthropic, agent. Event-driven trigger; 13 nodes.

Event trigger★★★★☆ complexityAI-powered13 nodesSlack TriggerHTTP RequestAnthropic ChatAgentGoogle SheetsGmailSlack
AI & RAG Trigger: Event Nodes: 13 Complexity: ★★★★☆ AI nodes: yes Added:

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

The workflow JSON

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

Download .json
{
  "id": "wyuE6DJqNXhX3K7B",
  "name": "[2] Slack Approval \u2192 Ship/Revise/Confirm Handler (FIXED)",
  "description": "Handles human responses to Holler's SITREP messages in Slack. Classifies intent as SHIP, REVISE, or CONFIRM and routes accordingly.",
  "active": true,
  "isArchived": false,
  "nodes": [
    {
      "parameters": {
        "trigger": [
          "message"
        ],
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "C0A0MBQ2L8P"
        },
        "options": {
          "resolveIds": true
        }
      },
      "id": "b55152b7-7d0d-4833-a469-404b4f349cb9",
      "name": "Slack Trigger",
      "type": "n8n-nodes-base.slackTrigger",
      "typeVersion": 1,
      "position": [
        -1696,
        352
      ]
    },
    {
      "parameters": {
        "url": "https://slack.com/api/conversations.replies",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "slackOAuth2Api",
        "sendQuery": true,
        "queryParameters": {
          "parameters": [
            {
              "name": "channel",
              "value": "={{ $json.channel }}"
            },
            {
              "name": "ts",
              "value": "={{ $json.thread_ts }}"
            }
          ]
        },
        "options": {}
      },
      "id": "a44632d1-751e-416a-b87b-693b5e1bdf49",
      "name": "Get Thread Context",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.3,
      "position": [
        -1248,
        352
      ]
    },
    {
      "parameters": {
        "jsCode": "const messages = $input.first().json.messages || [];\nconst replyMessage = $('Slack Trigger').first().json.text || '';\nconst threadTs = $('Slack Trigger').first().json.thread_ts;\n\nconst hollerBotId = 'U0A0GJN18JK';\nlet parentContent = '';\nfor (const msg of messages) {\n  if (msg.bot_id || msg.user === hollerBotId || !msg.user) {\n    parentContent += (msg.text || '') + '\\n';\n  } else {\n    if (msg.ts !== $('Slack Trigger').first().json.ts) {\n      break;\n    }\n  }\n}\n\nif (!parentContent.trim()) {\n  parentContent = messages[0]?.text || '';\n}\n\nconst execIdMatch = parentContent.match(/Exec(?:ution)? ID[:\\s]*(\\d+)/i);\nconst executionId = execIdMatch ? execIdMatch[1].trim() : null;\n\nconst fromMatch = parentContent.match(/\\*From:\\*\\s*([^\\n]+)/);\nconst subjectMatch = parentContent.match(/\\*Subject:\\*\\s*([^\\n]+)/);\n\nreturn [{\n  json: {\n    execution_id: executionId,\n    reply_text: replyMessage,\n    thread_ts: threadTs,\n    from_email: fromMatch ? fromMatch[1].trim() : '',\n    subject: subjectMatch ? subjectMatch[1].trim() : '',\n    parent_message: parentContent\n  }\n}];"
      },
      "id": "817eecc3-7dd1-4da0-9f55-9f3b61e898fc",
      "name": "Parse Thread Data",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -1024,
        352
      ]
    },
    {
      "parameters": {
        "model": {
          "__rl": true,
          "value": "claude-sonnet-4-5-20250929",
          "mode": "list"
        },
        "options": {}
      },
      "id": "a47ee7ab-0171-4cca-90d6-e5e020457b23",
      "name": "Claude Sonnet 4",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "typeVersion": 1.3,
      "position": [
        -512,
        272
      ]
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.reply_text }}",
        "options": {
          "systemMessage": "You are an intent classifier for email approval replies. Analyze the reply and return EXACTLY one word:\n\nSHIP - if approving/sending (e.g., \"ship it\", \"send it\", \"approved\", \"looks good\", \"go ahead\")\nREVISE - if requesting changes (e.g., \"revise\", \"change X\", \"make it shorter\", any specific feedback)\nCONFIRM - if just acknowledging (e.g., \"thanks\", \"got it\", \"confirmed\")\n\nOutput only: SHIP, REVISE, or CONFIRM"
        }
      },
      "id": "e499f392-d39a-40f0-944e-d71520e9f14a",
      "name": "Intent Classifier",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3,
      "position": [
        -576,
        48
      ]
    },
    {
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "SHIP",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ]
              },
              "renameOutput": true,
              "outputKey": "SHIP"
            },
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "REVISE",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ]
              },
              "renameOutput": true,
              "outputKey": "REVISE"
            },
            {
              "conditions": {
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "CONFIRM",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ]
              },
              "renameOutput": true,
              "outputKey": "CONFIRM"
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "ignoreCase": true,
          "renameFallbackOutput": "CONFIRM"
        }
      },
      "id": "b8cf9eed-fe37-401e-88eb-6bd305e6790c",
      "name": "Route by Intent",
      "type": "n8n-nodes-base.switch",
      "typeVersion": 3.3,
      "position": [
        -224,
        112
      ]
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1xTng5h4vCWzFRtEvs05FX1lwguB6Mob-2G_LTgicn4I"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Email Drafts"
        },
        "filtersUI": {
          "values": [
            {
              "lookupColumn": "execution_id",
              "lookupValue": "={{ $('Parse Thread Data').item.json.execution_id }}"
            }
          ]
        },
        "options": {
          "returnFirstMatch": true
        }
      },
      "id": "fe59998f-6fdd-417f-96ca-2a06ce9050c0",
      "name": "Get Draft from Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "const draftBody = $input.first().json.draft_body || '';\n\nfunction markdownToHtml(text) {\n  let html = text;\n  html = html.replace(/\\r\\n/g, '\\n');\n  html = html.replace(/\\n\\n+/g, '</p><p>');\n  html = html.replace(/\\n/g, '<br>\\n');\n  html = html.replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>');\n  html = html.replace(/__([^_]+)__/g, '<strong>$1</strong>');\n  if (!html.startsWith('<p>')) html = '<p>' + html;\n  if (!html.endsWith('</p>')) html = html + '</p>';\n  html = html.replace(/<p><\\/p>/g, '');\n  return html;\n}\n\nconst htmlBody = markdownToHtml(draftBody);\nconst originalData = $input.first().json;\n\nreturn [{ json: { ...originalData, draft_body_html: htmlBody, draft_body_original: draftBody } }];"
      },
      "id": "format-email-body-node",
      "name": "Format Email Body",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        112,
        0
      ]
    },
    {
      "parameters": {
        "operation": "reply",
        "messageId": "={{ $json.gmail_message_id }}",
        "message": "={{ $json.draft_body_html }}",
        "options": {}
      },
      "id": "70787849-c1b4-41bb-bb34-bf5717447b4d",
      "name": "Send Email",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        336,
        0
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1xTng5h4vCWzFRtEvs05FX1lwguB6Mob-2G_LTgicn4I"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "execution_id": "={{ $('Parse Thread Data').item.json.execution_id }}",
            "status": "sent",
            "sent_at": "={{ $now.toISO() }}",
            "updated_at": "={{ $now.toISO() }}"
          },
          "matchingColumns": [
            "execution_id"
          ]
        },
        "options": {}
      },
      "id": "00bfa8b7-05e4-4077-807f-bd8e47137a89",
      "name": "Update Sheet Status",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        560,
        0
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Slack Trigger').first().json.channel }}"
        },
        "text": "Email sent successfully!",
        "otherOptions": {}
      },
      "id": "b1116276-41e9-40f6-ab7b-6447dd47756a",
      "name": "Confirm in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        928,
        -16
      ]
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "t8sUvZ8xzoqNfYH5",
          "mode": "id"
        },
        "workflowInputs": {
          "mappingMode": "defineBelow",
          "value": {
            "execution_id": "={{ $('Parse Thread Data').item.json.execution_id }}",
            "revision_count": "={{ ($('Get Draft for Revision').first().json.revision_count || 0) + 1 }}",
            "human_feedback": "={{ $('Parse Thread Data').item.json.reply_text }}",
            "original_email": "={{ { subject: $('Get Draft for Revision').first().json.original_subject, sender: $('Get Draft for Revision').first().json.sender_email, body: $('Get Draft for Revision').first().json.original_body } }}",
            "previous_draft": "={{ $('Get Draft for Revision').first().json.draft_body }}",
            "cinnamon_analysis": "={{ $('Get Draft for Revision').first().json.cinnamon_analysis }}",
            "hatch_analysis": "={{ $('Get Draft for Revision').first().json.hatch_analysis }}"
          }
        },
        "options": {}
      },
      "id": "e315674e-9545-47fd-9b8a-98166674090c",
      "name": "Call SUB Workflow",
      "type": "n8n-nodes-base.executeWorkflow",
      "typeVersion": 1.3,
      "position": [
        432,
        208
      ]
    },
    {
      "parameters": {
        "conditions": {
          "conditions": [
            {
              "leftValue": "={{ $json.thread_ts }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            },
            {
              "leftValue": "={{ $json.thread_ts }}",
              "rightValue": "={{ $json.ts }}",
              "operator": {
                "type": "string",
                "operation": "notEquals"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "199f6d7c-4edf-4e40-902c-eaabb1468464",
      "name": "Filter Holler Replies",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -1472,
        352
      ]
    }
  ],
  "connections": {
    "Slack Trigger": {
      "main": [
        [
          {
            "node": "Filter Holler Replies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Holler Replies": {
      "main": [
        [
          {
            "node": "Get Thread Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Thread Context": {
      "main": [
        [
          {
            "node": "Parse Thread Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Thread Data": {
      "main": [
        [
          {
            "node": "Check Parse Success",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Claude Sonnet 4": {
      "ai_languageModel": [
        [
          {
            "node": "Intent Classifier",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Intent Classifier": {
      "main": [
        [
          {
            "node": "Route by Intent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Intent": {
      "main": [
        [
          {
            "node": "Get Draft from Sheet",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Get Draft for Revision",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Sheet Confirmed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Draft from Sheet": {
      "main": [
        [
          {
            "node": "Format Email Body",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Email Body": {
      "main": [
        [
          {
            "node": "Send Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Email": {
      "main": [
        [
          {
            "node": "Update Sheet Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Sheet Status": {
      "main": [
        [
          {
            "node": "Tag Original Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Tag Original Email": {
      "main": [
        [
          {
            "node": "Confirm in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call SUB Workflow": {
      "main": [
        [
          {
            "node": "Assemble Revision SITREP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "meta": null
}
Pro

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

About this workflow

[2] Slack Approval → Ship/Revise/Confirm Handler (FIXED). Uses slackTrigger, httpRequest, lmChatAnthropic, agent. Event-driven trigger; 13 nodes.

Source: https://github.com/8Dvibes/mindvalley-ai-mastery-students/blob/main/workflows/02-W2-Approval-Handler.json — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

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

AI & RAG

Chat with a multi-agent system to write a blog. The orchestrator advances through research, headlines, hooks, outline, intro, draft, and final polish–one phase per reply—outputting options and asking

Agent, Tool Workflow, Memory Buffer Window +9
AI & RAG

[2] Slack Approval → Ship/Revise/Confirm Handler (FIXED). Uses slackTrigger, httpRequest, lmChatAnthropic, agent. Event-driven trigger; 21 nodes.

Slack Trigger, HTTP Request, Anthropic Chat +4
AI & RAG

This is a base template for anyone trying to develop a Slack bot AI Agent. This base allows for multiple inputs (Voice, Picture, Video, and Text inputs) to be processed by an AI model of their choosin

Agent, OpenAI, Memory Buffer Window +6
AI & RAG

Streamline your HR recruitment process with this intelligent automation that reads candidate emails and resumes, analyzes them using GPT-4, and automatically shortlists or rejects applicants based on

Gmail, Gmail Trigger, HTTP Request +7
AI & RAG

A complete n8n automation that discovers TikTok influencers using Bright Data, evaluates their fit using Claude AI, and sends personalized outreach emails. Designed for marketing teams and brands that

Anthropic Chat, Google Sheets, Gmail +3