This workflow corresponds to n8n.io template #13849 — we link there as the canonical source.
This workflow follows the Agent → Form Trigger 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 →
{
"nodes": [
{
"id": "d6df5e4d-1ea2-41d4-b13b-08a0c062389a",
"name": "On form submission1",
"type": "n8n-nodes-base.formTrigger",
"position": [
-1472,
1296
],
"parameters": {
"options": {},
"formTitle": "Content Approval Request",
"formFields": {
"values": [
{
"fieldType": "textarea",
"fieldLabel": "Content Body"
},
{
"fieldType": "dropdown",
"fieldLabel": "Approval Channel",
"fieldOptions": {
"values": [
{
"option": "slack"
},
{
"option": "email"
}
]
}
}
]
},
"formDescription": "Submit AI-generated content for multi-channel approval routing via Slack or Email"
},
"typeVersion": 2.5
},
{
"id": "b2a3aa4d-ad53-4fa2-aeeb-758524f32675",
"name": "AI Agent1",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1248,
1296
],
"parameters": {
"text": "=Enhance the following content for publishing. Make it more engaging and professional while keeping the original message intact. Return only the enhanced content, nothing else. Keep it short please.\n\nContent: {{ $json['Content Body'] }}",
"options": {},
"promptType": "define"
},
"typeVersion": 3.1
},
{
"id": "316833b7-3a56-4c0c-8f18-b3fc9e5433f2",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1184,
1520
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o",
"cachedResultName": "gpt-4o"
},
"options": {},
"builtInTools": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1.3
},
{
"id": "9988eb6a-b3bc-4caf-9583-9d95d82982e9",
"name": "Route by Channel",
"type": "n8n-nodes-base.switch",
"position": [
-896,
1296
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Slack",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "fd55a0f7-397f-480b-97f2-b4311713d7bf",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('On form submission1').item.json['Approval Channel'] }}",
"rightValue": "slack"
}
]
},
"renameOutput": true
},
{
"outputKey": "Email",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e0cf2764-9264-4f84-b789-7e6491f2b7bf",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('On form submission1').item.json['Approval Channel'] }}",
"rightValue": "email"
}
]
},
"renameOutput": true
}
]
},
"options": {}
},
"typeVersion": 3.4
},
{
"id": "cad71c5b-918c-40a1-ada5-4baf93396386",
"name": "Slack Approval Request",
"type": "n8n-nodes-base.slack",
"position": [
-672,
1104
],
"parameters": {
"user": {
"__rl": true,
"mode": "list",
"value": "U0AB7QP5H1B",
"cachedResultName": "elvissaravia"
},
"message": "=*Content Approval Required*\n\n*Original:*\n{{ $('On form submission1').item.json['Content Body'].substring(0,300) }}\n\n*AI Enhanced:*\n{{ $json.output.substring(0,300) }}",
"options": {
"limitWaitTime": {
"values": {
"resumeUnit": "minutes",
"resumeAmount": 2
}
}
},
"operation": "sendAndWait",
"authentication": "oAuth2",
"approvalOptions": {
"values": {
"approvalType": "double",
"disapproveLabel": "Reject"
}
}
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.2
},
{
"id": "5efdfe87-6d20-4fef-ba90-0c224e15b815",
"name": "Slack Decision",
"type": "n8n-nodes-base.switch",
"position": [
-448,
1088
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Timed Out",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "77d67b45-6916-4cab-986b-cecc0ece5bfd",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json.data }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "Approved",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "557bf7ff-70e9-4732-8620-a7b0e22be3a5",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": "true"
}
]
},
"renameOutput": true
},
{
"outputKey": "Rejected",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "6621782e-1c23-4e2e-b125-e962e30fd0b8",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": "false"
}
]
},
"renameOutput": true
}
]
},
"options": {},
"looseTypeValidation": true
},
"typeVersion": 3.4
},
{
"id": "b9f8c952-c7cc-405d-85f1-84e8d7eba3a9",
"name": "Publish Content",
"type": "n8n-nodes-base.code",
"position": [
-224,
1104
],
"parameters": {
"jsCode": "// Content approved - publish\nconst items = $input.all();\nreturn items.map(item => ({\n json: {\n status: 'published',\n content: item.json.ai_enhanced_content || 'Approved content',\n published_at: new Date().toISOString()\n }\n}));"
},
"typeVersion": 2
},
{
"id": "8ac35e39-93c6-49bb-b569-a43b49d4064a",
"name": "Handle Rejection",
"type": "n8n-nodes-base.code",
"position": [
-224,
1296
],
"parameters": {
"jsCode": "// Content rejected - route back for revision\nconst items = $input.all();\nreturn items.map(item => ({\n json: {\n status: 'rejected',\n content: item.json.original_content || 'Rejected',\n rejected_at: new Date().toISOString(),\n action: 'Send back to content team for revision'\n }\n}));"
},
"typeVersion": 2
},
{
"id": "b4914384-c828-470c-bcc5-66890d5c581f",
"name": "Escalate to Manager",
"type": "n8n-nodes-base.gmail",
"position": [
-224,
1488
],
"parameters": {
"sendTo": "ellfae@gmail.com",
"message": "=A content approval request received no response within 24 hours.\n\nOriginal content submitted:\n{{ $('On form submission1').item.json['Content Body'].substring(0,500) }}\n\nThe request was sent via {{ $('On form submission1').item.json['Approval Channel'] }} and no decision was made within the allowed timeframe.\n\nPlease review and take action.",
"options": {},
"subject": "=ESCALATION: Content Approval Timed Out",
"emailType": "text"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "81b339e6-6344-42ea-bb30-40bfa69bbe09",
"name": "Email Decision",
"type": "n8n-nodes-base.switch",
"position": [
-448,
1472
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Timed Out",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "06bbf56d-4498-4412-917d-688511b8de9f",
"operator": {
"type": "string",
"operation": "empty",
"singleValue": true
},
"leftValue": "={{ $json.data }}",
"rightValue": ""
}
]
},
"renameOutput": true
},
{
"outputKey": "Approved",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "ae650af8-9e9e-41ca-a31d-65dfcc1ca3be",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": "true"
}
]
},
"renameOutput": true
},
{
"outputKey": "Rejected",
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "8a5edea2-7dfc-43f9-99ab-827da9d9f2b6",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.approved }}",
"rightValue": "false"
}
]
},
"renameOutput": true
}
]
},
"options": {},
"looseTypeValidation": true
},
"typeVersion": 3.4
},
{
"id": "23dbf2b0-b565-4b89-b628-ccb8d8bea5c7",
"name": "Email Approval Request",
"type": "n8n-nodes-base.gmail",
"position": [
-672,
1488
],
"parameters": {
"sendTo": "ellfae@gmail.com",
"message": "=Content Approval Required\n\nOriginal:\n{{ $('On form submission1').item.json['Content Body'] }}\n\nAI Enhanced:\n{{ $json.output }}\n\nPlease review the content above and approve or reject.",
"options": {
"limitWaitTime": {
"values": {
"resumeUnit": "minutes"
}
}
},
"subject": "=Content Approval Required",
"operation": "sendAndWait",
"approvalOptions": {
"values": {
"approvalType": "double",
"disapproveLabel": "Reject"
}
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "090c7433-0d2b-4703-88b0-814eb18347e1",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2368,
1040
],
"parameters": {
"width": 752,
"height": 656,
"content": "## Multi-Channel Content Approval with Slack and Email Escalation\n\n### How it works\n1. **Form Trigger** collects a content draft and preferred review channel (Slack or Email).\n2. **AI Agent** enhances the submitted content using the connected LLM.\n3. **Route by Channel** (Switch node) directs the approval request to Slack or Email based on the form selection.\n4. **Approval nodes** send the content with Approve/Reject buttons and pause until the reviewer responds or the timeout expires.\n5. **Decision nodes** handle three outcomes: approved routes to publish, rejected routes to handling, timed out escalates to a manager via email.\n\n### Setup\n- Connect your **LLM credentials** (e.g., OpenAI) to the Chat Model node\n- Connect your **Slack credentials** and set the target channel on the Slack Approval Request node\n- Connect your **Gmail credentials** on the Email Approval Request and Escalate to Manager nodes\n- Set timeout durations on each approval node (e.g., 2-4 hours for operational reviews)\n\n### Customization\n- Add more review channels (e.g., Microsoft Teams) by extending the Switch node\n- Replace the Publish Content and Handle Rejection code nodes with your actual publishing logic\n\n\nThis template is a learning companion to the Production AI Playbook, a series that explores strategies, shares best practices, and provides practical examples for building reliable AI systems in n8n. \n\n[Link to blog](https://go.n8n.io/PAP-HO-Blog)\n"
},
"typeVersion": 1
},
{
"id": "e629a92b-3259-49f6-8283-5527a834272a",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1536,
1024
],
"parameters": {
"color": 7,
"width": 544,
"height": 704,
"content": "## Submit & Enhance\n"
},
"typeVersion": 1
},
{
"id": "d4404a82-64ea-42d0-900b-64ccf968754b",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-960,
1024
],
"parameters": {
"color": 7,
"width": 448,
"height": 704,
"content": "## Route & Review"
},
"typeVersion": 1
},
{
"id": "bee79d99-d6b7-45ab-98eb-b41d739a837e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-480,
1024
],
"parameters": {
"color": 7,
"width": 448,
"height": 704,
"content": "## Decide & Act"
},
"typeVersion": 1
}
],
"connections": {
"AI Agent1": {
"main": [
[
{
"node": "Route by Channel",
"type": "main",
"index": 0
}
]
]
},
"Email Decision": {
"main": [
[
{
"node": "Escalate to Manager",
"type": "main",
"index": 0
}
],
[
{
"node": "Publish Content",
"type": "main",
"index": 0
}
],
[
{
"node": "Handle Rejection",
"type": "main",
"index": 0
}
]
]
},
"Slack Decision": {
"main": [
[
{
"node": "Escalate to Manager",
"type": "main",
"index": 0
}
],
[
{
"node": "Publish Content",
"type": "main",
"index": 0
}
],
[
{
"node": "Handle Rejection",
"type": "main",
"index": 0
}
]
]
},
"Route by Channel": {
"main": [
[
{
"node": "Slack Approval Request",
"type": "main",
"index": 0
}
],
[
{
"node": "Email Approval Request",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent1",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"On form submission1": {
"main": [
[
{
"node": "AI Agent1",
"type": "main",
"index": 0
}
]
]
},
"Email Approval Request": {
"main": [
[
{
"node": "Email Decision",
"type": "main",
"index": 0
}
]
]
},
"Slack Approval Request": {
"main": [
[
{
"node": "Slack Decision",
"type": "main",
"index": 0
}
]
]
}
}
}
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.
gmailOAuth2openAiApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Route AI-generated content to reviewers on Slack or email, with automatic escalation if nobody responds. This template demonstrates a full multi-channel review workflow with timeout handling.
Source: https://n8n.io/workflows/13849/ — 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.
This workflow automates legal policy governance for legal teams, policy managers, and compliance officers, eliminating manual document review, approval classification, and multi-channel stakeholder di
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
Whether you’re a product manager, developer, or simply curious about workflow automation, you’re in the right place. This n8n workflow is designed to help you streamline and automate your social media
This workflow turns your website form into a fully automated AI Lead Qualification system. Whenever a new lead submits your form, the workflow: Receives the submission through a Webhook Cleans and nor
Onboarding Workflow. Uses gmail, formTrigger, stickyNote, slack. Event-driven trigger; 19 nodes.