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

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

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

Event trigger★★★★☆ complexityAI-powered21 nodesSlack TriggerHTTP RequestAnthropic ChatAgentGoogle SheetsGmailSlack
AI & RAG Trigger: Event Nodes: 21 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 Slack reply intents (SHIP/REVISE/CONFIRM). Routes to Gmail send, revision workflow, or acknowledgment. Includes fix to persist revised drafts to Google Sheet before SHIP can pull them.",
  "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
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "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
      ],
      "credentials": {
        "slackOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const messages = $input.first().json.messages || [];\nconst replyMessage = $('Slack Trigger').first().json.text || '';\nconst threadTs = $('Slack Trigger').first().json.thread_ts;\n\n// Concatenate all bot messages at start of thread (handles split messages)\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
      ],
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "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": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "SHIP",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "SHIP"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "REVISE",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ],
                "combinator": "and"
              },
              "renameOutput": true,
              "outputKey": "REVISE"
            },
            {
              "conditions": {
                "options": {
                  "caseSensitive": true,
                  "leftValue": "",
                  "typeValidation": "strict"
                },
                "conditions": [
                  {
                    "leftValue": "={{ $json.output }}",
                    "rightValue": "CONFIRM",
                    "operator": {
                      "type": "string",
                      "operation": "contains"
                    }
                  }
                ],
                "combinator": "and"
              },
              "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": "YOUR_GOOGLE_SHEET_ID"
        },
        "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
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "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  html = html.replace(/<p><br>\\n<\\/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
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Email Drafts"
        },
        "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
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Slack Trigger').first().json.channel }}"
        },
        "text": "\u2705 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
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        },
        "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": "77c24336-ec68-4472-800f-451f9fcd96d5",
      "name": "Get Draft for Revision",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        208,
        208
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "workflowId": {
          "__rl": true,
          "value": "YOUR_SUB_WORKFLOW_ID",
          "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": {
        "jsCode": "// Assemble Revision SITREP for Slack\nconst subOutput = $input.first().json;\n\nconst holler = subOutput.holler_briefing || {\n  tldr: 'Revision processed',\n  customer_vibe: 'Unknown',\n  heat_level: '\ud83d\udd25 Unknown',\n  the_call: subOutput.bishop_status === 'PASS' ? 'SHIP_IT' : 'NEEDS_REVIEW',\n  call_reasoning: 'See Bishop evaluation',\n  what_changed: 'See draft comparison',\n  personality_closer: 'Stay spicy!'\n};\n\nconst threadTs = $('Parse Thread Data').first().json.thread_ts;\n\nconst message = [\n  `\ud83c\udf57 *HOLLER REVISION SITREP* | _Exec ID: ${subOutput.execution_id} \u2022 Revision #${subOutput.revision_count}_ \ud83c\udf57`,\n  '',\n  holler.tldr || 'Revision processed',\n  '',\n  `*Your feedback:* \"${(subOutput.human_feedback || '').substring(0, 150)}${subOutput.human_feedback?.length > 150 ? '...' : ''}\"`,\n  `*What changed:* ${holler.what_changed || 'See draft below'}`,\n  `*Customer vibe:* ${holler.customer_vibe || 'Unknown'}`,\n  `*The heat level:* ${holler.heat_level || '\ud83d\udd25 Unknown'}`,\n  '',\n  '-------------------------------------------',\n  '',\n  '\ud83d\udce7 *ORIGINAL CUSTOMER EMAIL*',\n  '',\n  `*From:* ${subOutput.original_email?.sender || 'Unknown'}`,\n  `*Subject:* ${subOutput.original_email?.subject || 'Unknown'}`,\n  '',\n  (subOutput.original_email?.body || 'No body').substring(0, 500),\n  '',\n  '-------------------------------------------',\n  '',\n  `\u2709\ufe0f *REVISED DRAFT* (v${subOutput.revision_count}) - Score: ${subOutput.bishop_score}/100`,\n  '',\n  `*Subject:* ${subOutput.revised_draft.subject}`,\n  '',\n  subOutput.revised_draft.body,\n  '',\n  '-------------------------------------------',\n  '',\n  `\ud83d\udc54 *BISHOP'S VERDICT:* ${subOutput.bishop_status === 'PASS' ? 'PASS \u2705' : 'FAIL \u26a0\ufe0f'} (${subOutput.bishop_score}/100)`,\n  '',\n  subOutput.evaluation_details?.summary || 'No summary available',\n  '',\n  '-------------------------------------------',\n  '',\n  `*THE CALL:* ${holler.the_call === 'SHIP_IT' ? '\u2705 SHIP IT' : '\u26a0\ufe0f NEEDS REVIEW'}`,\n  '',\n  holler.call_reasoning || 'See evaluation above',\n  '',\n  '---',\n  '',\n  holler.personality_closer || 'Stay spicy! \ud83c\udf57'\n].join('\\n');\n\nreturn [{\n  json: {\n    slack_message: message,\n    thread_ts: threadTs,\n    revised_draft: subOutput.revised_draft,\n    bishop_score: subOutput.bishop_score,\n    bishop_status: subOutput.bishop_status,\n    revision_count: subOutput.revision_count,\n    execution_id: subOutput.execution_id\n  }\n}];"
      },
      "id": "d698abb8-c742-4c4a-a5c1-856c937ce344",
      "name": "Assemble Revision SITREP",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        544,
        208
      ]
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Email Drafts"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "execution_id": "={{ $json.execution_id }}",
            "draft_subject": "={{ $json.revised_draft.subject }}",
            "draft_body": "={{ $json.revised_draft.body }}",
            "qa_score": "={{ $json.bishop_score }}",
            "qa_status": "={{ $json.bishop_status }}",
            "revision_count": "={{ $json.revision_count }}",
            "status": "pending_approval",
            "updated_at": "={{ $now.toISO() }}"
          },
          "matchingColumns": [
            "execution_id"
          ]
        },
        "options": {}
      },
      "id": "update-sheet-revision-node",
      "name": "Update Sheet with Revision",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        768,
        208
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notes": "CRITICAL FIX: This node persists the revised draft to Google Sheet BEFORE posting to Slack. This ensures that when SHIP is triggered, it pulls the correct (revised) version."
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Slack Trigger').first().json.channel }}"
        },
        "text": "={{ $json.slack_message }}",
        "otherOptions": {}
      },
      "id": "ae084ea7-0fb4-442b-9029-ed8af14271c4",
      "name": "Post New Draft to Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        992,
        208
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "update",
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "YOUR_GOOGLE_SHEET_ID"
        },
        "sheetName": {
          "__rl": true,
          "value": "gid=0",
          "mode": "list",
          "cachedResultName": "Email Drafts"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "execution_id": "={{ $('Parse Thread Data').item.json.execution_id }}",
            "status": "confirmed",
            "updated_at": "={{ $now.toISO() }}"
          },
          "matchingColumns": [
            "execution_id"
          ]
        },
        "options": {}
      },
      "id": "099002ee-7cb1-43e8-bc0a-2f3e7db37bd3",
      "name": "Update Sheet Confirmed",
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.5,
      "position": [
        208,
        400
      ],
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Slack Trigger').first().json.channel }}"
        },
        "text": "\ud83d\udc4d Acknowledged",
        "otherOptions": {
          "includeLinkToWorkflow": true
        }
      },
      "id": "06958136-0b6f-4c08-8e7e-d8da2406489f",
      "name": "Ack in Slack",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        432,
        400
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "leftValue": "={{ $json.thread_ts }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            },
            {
              "id": "condition2",
              "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
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 2
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "condition1",
              "leftValue": "={{ $json.execution_id }}",
              "rightValue": "",
              "operator": {
                "type": "string",
                "operation": "notEmpty"
              }
            }
          ]
        },
        "options": {}
      },
      "id": "cff2a112-f78b-404b-a411-bcbd3a1e8d75",
      "name": "Check Parse Success",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [
        -800,
        352
      ]
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $('Slack Trigger').first().json.channel }}"
        },
        "text": "\u26a0\ufe0f Could not process your response. Please reply to a draft message from Holler.",
        "otherOptions": {
          "includeLinkToWorkflow": false
        }
      },
      "id": "629f6651-0159-49a8-9bf9-801580b7a2d7",
      "name": "Error Response",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.3,
      "position": [
        -512,
        448
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    }
  ],
  "connections": {
    "Slack Trigger": {
      "main": [
        [
          {
            "node": "Filter Holler Replies",
            "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
          }
        ]
      ]
    },
    "Send Email": {
      "main": [
        [
          {
            "node": "Update Sheet Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Sheet Status": {
      "main": [
        [
          {
            "node": "Confirm in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Sheet Confirmed": {
      "main": [
        [
          {
            "node": "Ack in Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Holler Replies": {
      "main": [
        [
          {
            "node": "Get Thread Context",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Parse Success": {
      "main": [
        [
          {
            "node": "Intent Classifier",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Draft for Revision": {
      "main": [
        [
          {
            "node": "Call SUB Workflow",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Call SUB Workflow": {
      "main": [
        [
          {
            "node": "Assemble Revision SITREP",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Assemble Revision SITREP": {
      "main": [
        [
          {
            "node": "Update Sheet with Revision",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Sheet with Revision": {
      "main": [
        [
          {
            "node": "Post New Draft to Slack",
            "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
          }
        ]
      ]
    }
  },
  "settings": {
    "executionOrder": "v1",
    "callerPolicy": "workflowsFromSameOwner",
    "availableInMCP": false
  },
  "tags": [
    "HITL",
    "Week-3",
    "Approval",
    "Hattie-B"
  ],
  "meta": {
    "fixedAt": "2026-01-30",
    "fixDescription": "Added 'Update Sheet with Revision' node to persist revised drafts before posting to Slack. This prevents the bug where SHIP would pull stale v1 data instead of the revised v2 draft."
  }
}

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

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

Source: https://github.com/8Dvibes/mindvalley-ai-mastery-students/blob/main/workflows/W2-Approval-Handler-FIXED.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; 13 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