This workflow follows the Error Trigger → 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 →
{
"name": "Human Approval AI Response",
"nodes": [
{
"parameters": {
"content": "## Human Approval AI Response\n\n**Purpose:** A reusable human-in-the-loop pattern. Incoming messages are drafted by AI, sent to a human for review, then dispatched (or discarded) based on their decision.\n\n**Approval Flow:**\n1. Message arrives via Webhook\n2. OpenAI drafts a response + confidence score\n3. Draft is posted to Slack with Approve / Reject / Edit buttons\n4. Workflow pauses, waiting for a human decision\n5. On resume: route by decision type\n - **Approved** \u2192 Send via Gmail, log to Sheets\n - **Rejected** \u2192 Log rejection, notify requester\n - **Edited** \u2192 Send edited version via Gmail, log to Sheets\n\n**How to adapt this workflow:**\n- Swap the Gmail send for any delivery channel\n- Swap the Webhook trigger for Email, Slack, or Form trigger\n- Adjust confidence threshold for auto-approval\n- Connect to your ticketing system via the log step",
"height": 460,
"width": 420,
"color": 5
},
"id": "sticky-intro",
"name": "Intro Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-520,
-280
]
},
{
"parameters": {
"content": "### Approval Mechanism\nThe Wait node generates a unique resume URL per execution. This URL is posted in Slack. Approvers POST to this URL with:\n```json\n{\n \"decision\": \"approved\" | \"rejected\" | \"edited\",\n \"edited_response\": \"...\" // only for edited\n \"rejection_reason\": \"...\" // only for rejected\n}\n```\nThe Wait node has a 24-hour timeout \u2014 after that the request auto-expires and is logged as timed_out.",
"height": 280,
"width": 380,
"color": 4
},
"id": "sticky-approval",
"name": "Approval Mechanism Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
860,
-280
]
},
{
"parameters": {
"content": "### AI Confidence Levels\n- **high** confidence \u2192 Slack message shows green, suggests quick approval\n- **medium** \u2192 Yellow, recommends review\n- **low** \u2192 Red, strong recommendation to edit before sending\n\nIf `needs_human_review` is false AND confidence is high, you can add an IF node before the Wait to auto-approve. Not recommended for customer-facing responses.",
"height": 220,
"width": 360,
"color": 7
},
"id": "sticky-confidence",
"name": "Confidence Levels Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1300,
-280
]
},
{
"parameters": {
"content": "### Switch Routing\nThe Switch node routes on `$json.body.decision`:\n- Route 0: `approved` \u2192 Gmail send \u2192 Sheets log\n- Route 1: `rejected` \u2192 Sheets log (no send)\n- Route 2: `edited` \u2192 Gmail send edited \u2192 Sheets log\n- Route 3 (fallback): `timed_out` \u2192 Sheets log as expired",
"height": 200,
"width": 320,
"color": 6
},
"id": "sticky-switch",
"name": "Switch Routing Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
1720,
-280
]
},
{
"parameters": {
"httpMethod": "POST",
"path": "ai-response-request",
"responseMode": "responseNode",
"options": {}
},
"id": "webhook-trigger",
"name": "Receive Request",
"type": "n8n-nodes-base.webhook",
"typeVersion": 2,
"position": [
-160,
60
]
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "i1",
"name": "request_id",
"value": "={{ 'REQ-' + Date.now() + '-' + Math.random().toString(36).substr(2, 6).toUpperCase() }}",
"type": "string"
},
{
"id": "i2",
"name": "original_message",
"value": "={{ $json.body.message || $json.body.content || $json.body.text || '' }}",
"type": "string"
},
{
"id": "i3",
"name": "sender_name",
"value": "={{ $json.body.sender_name || $json.body.from_name || 'Unknown Sender' }}",
"type": "string"
},
{
"id": "i4",
"name": "sender_email",
"value": "={{ $json.body.sender_email || $json.body.from_email || '' }}",
"type": "string"
},
{
"id": "i5",
"name": "context",
"value": "={{ $json.body.context || $json.body.subject || '' }}",
"type": "string"
},
{
"id": "i6",
"name": "priority",
"value": "={{ $json.body.priority || 'normal' }}",
"type": "string"
},
{
"id": "i7",
"name": "received_at",
"value": "={{ new Date().toISOString() }}",
"type": "string"
},
{
"id": "i8",
"name": "channel",
"value": "={{ $json.body.channel || 'email' }}",
"type": "string"
}
]
},
"options": {}
},
"id": "set-normalize",
"name": "Normalize Input",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
80,
60
]
},
{
"parameters": {
"method": "POST",
"url": "https://api.openai.com/v1/chat/completions",
"authentication": "genericCredentialType",
"genericAuthType": "httpHeaderAuth",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={\n \"model\": \"gpt-4o\",\n \"temperature\": 0.5,\n \"response_format\": { \"type\": \"json_object\" },\n \"messages\": [\n {\n \"role\": \"system\",\n \"content\": \"You are a professional communications assistant. Draft a response to an incoming message and assess whether a human should review it before sending.\\n\\nReturn a JSON object with exactly these fields:\\n- draft_response (string): A professional, complete response to the message. Match the tone of the original (formal/casual). Do not include placeholders \u2014 write the actual response.\\n- confidence (string): 'high', 'medium', or 'low' \u2014 your confidence the draft is ready to send without edits\\n- needs_human_review (boolean): true if the message is sensitive, ambiguous, complaints, legal/financial, or if you are unsure\\n- reason_for_review (string): Explanation of why review is needed. Empty string if needs_human_review is false.\\n- tone (string): The tone of the draft \u2014 'formal', 'friendly', 'empathetic', 'technical', etc.\\n- suggested_subject (string): If this is an email response, suggest an appropriate subject line\\n- key_points_addressed (array of strings): List of the main points from the original message that the draft addresses\\n\\nReturn ONLY valid JSON.\"\n },\n {\n \"role\": \"user\",\n \"content\": \"Draft a response to this incoming message:\\n\\nSender: {{ $json.sender_name }} <{{ $json.sender_email }}>\\nChannel: {{ $json.channel }}\\nContext/Subject: {{ $json.context }}\\nPriority: {{ $json.priority }}\\n\\nMessage:\\n{{ $json.original_message }}\"\n }\n ]\n}",
"options": {
"timeout": 30000
}
},
"id": "openai-draft",
"name": "OpenAI: Draft Response",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
320,
60
],
"credentials": {
"httpHeaderAuth": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "d1",
"name": "draft_response",
"value": "={{ JSON.parse($json.choices[0].message.content).draft_response }}",
"type": "string"
},
{
"id": "d2",
"name": "confidence",
"value": "={{ JSON.parse($json.choices[0].message.content).confidence || 'medium' }}",
"type": "string"
},
{
"id": "d3",
"name": "needs_human_review",
"value": "={{ JSON.parse($json.choices[0].message.content).needs_human_review !== false }}",
"type": "boolean"
},
{
"id": "d4",
"name": "reason_for_review",
"value": "={{ JSON.parse($json.choices[0].message.content).reason_for_review || '' }}",
"type": "string"
},
{
"id": "d5",
"name": "tone",
"value": "={{ JSON.parse($json.choices[0].message.content).tone || 'professional' }}",
"type": "string"
},
{
"id": "d6",
"name": "suggested_subject",
"value": "={{ JSON.parse($json.choices[0].message.content).suggested_subject || 'Re: Your Message' }}",
"type": "string"
},
{
"id": "d7",
"name": "key_points_addressed",
"value": "={{ JSON.parse($json.choices[0].message.content).key_points_addressed || [] }}",
"type": "array"
},
{
"id": "d8",
"name": "request_id",
"value": "={{ $('Normalize Input').item.json.request_id }}",
"type": "string"
},
{
"id": "d9",
"name": "original_message",
"value": "={{ $('Normalize Input').item.json.original_message }}",
"type": "string"
},
{
"id": "d10",
"name": "sender_name",
"value": "={{ $('Normalize Input').item.json.sender_name }}",
"type": "string"
},
{
"id": "d11",
"name": "sender_email",
"value": "={{ $('Normalize Input').item.json.sender_email }}",
"type": "string"
},
{
"id": "d12",
"name": "context",
"value": "={{ $('Normalize Input').item.json.context }}",
"type": "string"
},
{
"id": "d13",
"name": "received_at",
"value": "={{ $('Normalize Input').item.json.received_at }}",
"type": "string"
},
{
"id": "d14",
"name": "confidence_emoji",
"value": "={{ JSON.parse($json.choices[0].message.content).confidence === 'high' ? ':large_green_circle:' : JSON.parse($json.choices[0].message.content).confidence === 'medium' ? ':large_yellow_circle:' : ':red_circle:' }}",
"type": "string"
}
]
},
"options": {}
},
"id": "set-draft",
"name": "Parse AI Draft",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
560,
60
]
},
{
"parameters": {
"resource": "message",
"operation": "post",
"channel": {
"__rl": true,
"value": "#response-approvals",
"mode": "name"
},
"text": "={{ $json.confidence_emoji }} *New Response Awaiting Approval*\n\n*Request ID:* `{{ $json.request_id }}`\n*From:* {{ $json.sender_name }} <{{ $json.sender_email }}>\n*Context:* {{ $json.context }}\n*AI Confidence:* {{ $json.confidence.toUpperCase() }}\n*Needs Review:* {{ $json.needs_human_review ? 'Yes' : 'No' }}\n{{ $json.reason_for_review ? '*Review Reason:* ' + $json.reason_for_review : '' }}\n\n---\n:speech_balloon: *Original Message:*\n> {{ $json.original_message.replace(/\\n/g, '\\n> ') }}\n\n---\n:pencil: *AI Draft Response:*\n```{{ $json.draft_response }}```\n\n*Tone:* {{ $json.tone }} | *Suggested Subject:* {{ $json.suggested_subject }}\n\n---\n:point_right: *To respond, POST to the approval webhook:*\n`{{ $execution.resumeUrl }}`\n\nPayload options:\n\u2022 `{\"decision\": \"approved\"}` \u2014 send as-is\n\u2022 `{\"decision\": \"rejected\", \"rejection_reason\": \"your reason\"}` \u2014 discard\n\u2022 `{\"decision\": \"edited\", \"edited_response\": \"your edited text\"}` \u2014 send your version\n\n_This request expires in 24 hours._",
"otherOptions": {
"unfurl_links": false
}
},
"id": "slack-approval-request",
"name": "Slack: Send for Approval",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.3,
"position": [
800,
60
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resume": "webhook",
"options": {
"webhookSuffix": "=approval-{{ $('Parse AI Draft').item.json.request_id }}",
"responseData": "firstEntryJson",
"limitWaitTime": true,
"limitType": "afterTimeInterval",
"resumeAmount": 24,
"resumeUnit": "hours"
}
},
"id": "wait-approval",
"name": "Wait: Human Decision",
"type": "n8n-nodes-base.wait",
"typeVersion": 1.1,
"position": [
1040,
60
]
},
{
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.body.decision }}",
"rightValue": "approved",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputIndex": 0
},
{
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.body.decision }}",
"rightValue": "rejected",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputIndex": 1
},
{
"conditions": {
"options": {
"caseSensitive": false,
"leftValue": "",
"typeValidation": "strict"
},
"conditions": [
{
"leftValue": "={{ $json.body.decision }}",
"rightValue": "edited",
"operator": {
"type": "string",
"operation": "equals"
}
}
],
"combinator": "and"
},
"outputIndex": 2
}
]
},
"options": {
"fallbackOutput": 3
}
},
"id": "switch-decision",
"name": "Route by Decision",
"type": "n8n-nodes-base.switch",
"typeVersion": 3.2,
"position": [
1280,
60
]
},
{
"parameters": {
"resource": "message",
"operation": "sendHtml",
"toList": [
"={{ $('Parse AI Draft').item.json.sender_email }}"
],
"subject": "={{ $('Parse AI Draft').item.json.suggested_subject }}",
"message": "=<html><body style=\"font-family: Arial, sans-serif; line-height: 1.6;\">\n{{ $('Parse AI Draft').item.json.draft_response.replace(/\\n/g, '<br>') }}\n</body></html>",
"options": {}
},
"id": "gmail-send-approved",
"name": "Gmail: Send Approved Response",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1520,
-160
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"resource": "message",
"operation": "sendHtml",
"toList": [
"={{ $('Parse AI Draft').item.json.sender_email }}"
],
"subject": "={{ $('Parse AI Draft').item.json.suggested_subject }}",
"message": "=<html><body style=\"font-family: Arial, sans-serif; line-height: 1.6;\">\n{{ ($json.body.edited_response || $('Parse AI Draft').item.json.draft_response).replace(/\\n/g, '<br>') }}\n</body></html>",
"options": {}
},
"id": "gmail-send-edited",
"name": "Gmail: Send Edited Response",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1520,
60
],
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_APPROVALS_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Approval Log",
"mode": "list",
"cachedResultName": "Approval Log"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Request ID": "={{ $('Parse AI Draft').item.json.request_id }}",
"Sender Name": "={{ $('Parse AI Draft').item.json.sender_name }}",
"Sender Email": "={{ $('Parse AI Draft').item.json.sender_email }}",
"Context": "={{ $('Parse AI Draft').item.json.context }}",
"Original Message": "={{ $('Parse AI Draft').item.json.original_message }}",
"AI Draft": "={{ $('Parse AI Draft').item.json.draft_response }}",
"AI Confidence": "={{ $('Parse AI Draft').item.json.confidence }}",
"Needs Review": "={{ $('Parse AI Draft').item.json.needs_human_review }}",
"Review Reason": "={{ $('Parse AI Draft').item.json.reason_for_review }}",
"Decision": "=approved",
"Final Response Sent": "={{ $('Parse AI Draft').item.json.draft_response }}",
"Decided At": "={{ new Date().toISOString() }}",
"Received At": "={{ $('Parse AI Draft').item.json.received_at }}"
},
"schema": []
},
"options": {}
},
"id": "sheets-log-approved",
"name": "Sheets: Log Approved",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1760,
-160
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_APPROVALS_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Approval Log",
"mode": "list",
"cachedResultName": "Approval Log"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Request ID": "={{ $('Parse AI Draft').item.json.request_id }}",
"Sender Name": "={{ $('Parse AI Draft').item.json.sender_name }}",
"Sender Email": "={{ $('Parse AI Draft').item.json.sender_email }}",
"Context": "={{ $('Parse AI Draft').item.json.context }}",
"Original Message": "={{ $('Parse AI Draft').item.json.original_message }}",
"AI Draft": "={{ $('Parse AI Draft').item.json.draft_response }}",
"AI Confidence": "={{ $('Parse AI Draft').item.json.confidence }}",
"Needs Review": "={{ $('Parse AI Draft').item.json.needs_human_review }}",
"Review Reason": "={{ $('Parse AI Draft').item.json.reason_for_review }}",
"Decision": "=rejected",
"Rejection Reason": "={{ $json.body.rejection_reason || 'Not specified' }}",
"Final Response Sent": "=N/A - Rejected",
"Decided At": "={{ new Date().toISOString() }}",
"Received At": "={{ $('Parse AI Draft').item.json.received_at }}"
},
"schema": []
},
"options": {}
},
"id": "sheets-log-rejected",
"name": "Sheets: Log Rejected",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1520,
280
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_APPROVALS_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Approval Log",
"mode": "list",
"cachedResultName": "Approval Log"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Request ID": "={{ $('Parse AI Draft').item.json.request_id }}",
"Sender Name": "={{ $('Parse AI Draft').item.json.sender_name }}",
"Sender Email": "={{ $('Parse AI Draft').item.json.sender_email }}",
"Context": "={{ $('Parse AI Draft').item.json.context }}",
"Original Message": "={{ $('Parse AI Draft').item.json.original_message }}",
"AI Draft": "={{ $('Parse AI Draft').item.json.draft_response }}",
"AI Confidence": "={{ $('Parse AI Draft').item.json.confidence }}",
"Needs Review": "={{ $('Parse AI Draft').item.json.needs_human_review }}",
"Review Reason": "={{ $('Parse AI Draft').item.json.reason_for_review }}",
"Decision": "=edited",
"Final Response Sent": "={{ $json.body.edited_response }}",
"Decided At": "={{ new Date().toISOString() }}",
"Received At": "={{ $('Parse AI Draft').item.json.received_at }}"
},
"schema": []
},
"options": {}
},
"id": "sheets-log-edited",
"name": "Sheets: Log Edited",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1760,
60
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"operation": "append",
"documentId": {
"__rl": true,
"value": "YOUR_APPROVALS_SHEET_ID",
"mode": "id"
},
"sheetName": {
"__rl": true,
"value": "Approval Log",
"mode": "list",
"cachedResultName": "Approval Log"
},
"columns": {
"mappingMode": "defineBelow",
"value": {
"Request ID": "={{ $('Parse AI Draft').item.json.request_id }}",
"Sender Name": "={{ $('Parse AI Draft').item.json.sender_name }}",
"Sender Email": "={{ $('Parse AI Draft').item.json.sender_email }}",
"Context": "={{ $('Parse AI Draft').item.json.context }}",
"Original Message": "={{ $('Parse AI Draft').item.json.original_message }}",
"AI Draft": "={{ $('Parse AI Draft').item.json.draft_response }}",
"AI Confidence": "={{ $('Parse AI Draft').item.json.confidence }}",
"Decision": "=timed_out",
"Final Response Sent": "=N/A - Timed Out (24h)",
"Decided At": "={{ new Date().toISOString() }}",
"Received At": "={{ $('Parse AI Draft').item.json.received_at }}"
},
"schema": []
},
"options": {}
},
"id": "sheets-log-timeout",
"name": "Sheets: Log Timed Out",
"type": "n8n-nodes-base.googleSheets",
"typeVersion": 4.5,
"position": [
1520,
460
],
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"respondWith": "json",
"responseBody": "={{ JSON.stringify({ success: true, message: 'Request received. AI is drafting a response.', request_id: $('Normalize Input').item.json.request_id }) }}",
"options": {
"responseCode": 200
}
},
"id": "webhook-response",
"name": "Respond to Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"typeVersion": 1.1,
"position": [
320,
280
]
},
{
"parameters": {},
"id": "error-trigger",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"typeVersion": 1,
"position": [
1760,
540
]
},
{
"parameters": {
"resource": "message",
"operation": "post",
"channel": {
"__rl": true,
"value": "#workflow-errors",
"mode": "name"
},
"text": "=:red_circle: *Workflow Error: Human Approval AI Response*\n\n*Node:* {{ $json.execution.lastNodeExecuted }}\n*Error:* {{ $json.execution.error.message }}\n*Execution ID:* {{ $json.execution.id }}\n*Time:* {{ new Date().toISOString() }}\n\nThe request may need to be manually processed. Check execution logs for details.",
"otherOptions": {}
},
"id": "slack-error",
"name": "Slack: Error Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.3,
"position": [
2000,
540
],
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Receive Request": {
"main": [
[
{
"node": "Normalize Input",
"type": "main",
"index": 0
}
]
]
},
"Normalize Input": {
"main": [
[
{
"node": "OpenAI: Draft Response",
"type": "main",
"index": 0
},
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"OpenAI: Draft Response": {
"main": [
[
{
"node": "Parse AI Draft",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Draft": {
"main": [
[
{
"node": "Slack: Send for Approval",
"type": "main",
"index": 0
}
]
]
},
"Slack: Send for Approval": {
"main": [
[
{
"node": "Wait: Human Decision",
"type": "main",
"index": 0
}
]
]
},
"Wait: Human Decision": {
"main": [
[
{
"node": "Route by Decision",
"type": "main",
"index": 0
}
]
]
},
"Route by Decision": {
"main": [
[
{
"node": "Gmail: Send Approved Response",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets: Log Rejected",
"type": "main",
"index": 0
}
],
[
{
"node": "Gmail: Send Edited Response",
"type": "main",
"index": 0
}
],
[
{
"node": "Sheets: Log Timed Out",
"type": "main",
"index": 0
}
]
]
},
"Gmail: Send Approved Response": {
"main": [
[
{
"node": "Sheets: Log Approved",
"type": "main",
"index": 0
}
]
]
},
"Gmail: Send Edited Response": {
"main": [
[
{
"node": "Sheets: Log Edited",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Slack: Error Alert",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveManualExecutions": true,
"callerPolicy": "workflowsFromSameOwner",
"errorWorkflow": "",
"saveExecutionProgress": true,
"saveDataSuccessExecution": "all",
"saveDataErrorExecution": "all",
"timezone": "America/New_York"
},
"staticData": null,
"tags": [
"human-in-the-loop",
"approval",
"openai",
"gmail",
"slack",
"google-sheets",
"reusable-pattern"
],
"triggerCount": 1,
"updatedAt": "2026-05-14T00:00:00.000Z",
"versionId": "08-human-approval-v1",
"active": false,
"id": "workflow-08"
}
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.
gmailOAuth2googleSheetsOAuth2ApihttpHeaderAuthslackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Human Approval AI Response. Uses httpRequest, slack, gmail, googleSheets. Webhook trigger; 20 nodes.
Source: https://github.com/humayun-sarfraz/n8n-ai-workflow-kit/blob/main/workflows/08-human-approval-ai-response.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Receive inventory movements via webhook, validate data, update stock levels, and trigger automatic alerts when products need reordering.
Receive support tickets via webhook, categorize by priority, track SLA deadlines, notify your team on Slack, and send confirmation emails to customers.
This workflow is a fully automated AI matte painting generation system for VFX pipelines, designed to convert a single environment prompt into multiple cinematic background variations. It handles gene
Deliver coordinated messages through multiple channels with priority-based formatting, delivery tracking, and compliance logging.
Who is this for? This template is ideal for event organizers, conference managers, and community teams who need an automated participant management system. Perfect for workshops, conferences, meetups,