AutomationFlowsAI & RAG › Business Post Pipeline (agent) #2

Business Post Pipeline (agent) #2

Business Post Pipeline. Uses agent, lmChatGoogleGemini, slack, httpRequest. Scheduled trigger; 24 nodes.

Cron / scheduled trigger★★★★☆ complexityAI-powered24 nodesAgentGoogle Gemini ChatSlackHTTP RequestPostgresGmail
AI & RAG Trigger: Cron / scheduled Nodes: 24 Complexity: ★★★★☆ AI nodes: yes Added:
Business Post Pipeline (agent) #2 — n8n workflow card showing Agent, Google Gemini Chat, Slack integration

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
{
  "name": "Business Post Pipeline",
  "nodes": [
    {
      "parameters": {
        "promptType": "define",
        "text": "={{ $json.prompt }}",
        "options": {
          "systemMessage": "You are a ghostwriter for a senior enterprise AI practitioner. Follow the Brand DNA rules in the prompt exactly. Return ONLY the LinkedIn post text \u2014 no preamble, no explanation, no markdown, no quotation marks."
        }
      },
      "id": "d2d0102c-38d0-4140-9159-311728102bab",
      "name": "Gemini: Draft Post",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        2544,
        1248
      ],
      "retryOnFail": true,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "deda6592-182a-439c-a20b-a2745c262d74",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1.1,
      "position": [
        2544,
        1440
      ],
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#content-approvals",
          "mode": "name"
        },
        "text": "\ud83d\udccb New post ready for approval. Check Gmail for details and approve/reject buttons.",
        "otherOptions": {}
      },
      "id": "b213eb3d-1e42-43a1-a757-fa357cbe205d",
      "name": "Slack: Approval Card",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        3472,
        1152
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "id": "0989b9b6-212c-4f0a-ac96-4505574c27cb",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        608,
        1248
      ]
    },
    {
      "parameters": {
        "jsCode": "const runId = `run_${Date.now()}`;\nconst runAt = new Date().toISOString();\nconsole.log(`[Pipeline] Starting run: ${runId}`);\nreturn [{ json: { runId, runAt } }];"
      },
      "id": "896ff700-05bb-466c-ac93-423423907518",
      "name": "Init Run1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        848,
        1248
      ]
    },
    {
      "parameters": {
        "url": "https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=15839135",
        "options": {
          "timeout": 30000
        }
      },
      "id": "15935881-f283-4cf1-88bd-6a09f95481eb",
      "name": "Fetch Earnings RSS1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1104,
        1104
      ]
    },
    {
      "parameters": {
        "url": "https://www.nist.gov/news-events/news/rss.xml",
        "options": {
          "timeout": 30000
        }
      },
      "id": "579ac864-6889-4fe8-8dd8-844fab7483cc",
      "name": "Fetch Regulatory RSS1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        1104,
        1376
      ]
    },
    {
      "parameters": {
        "jsCode": "const err = $input.item.json.error || 'Unknown error';\nconsole.error(`[Pipeline] Earnings feed failed: ${err}`);\nreturn [];"
      },
      "id": "3f239ceb-a2f6-4691-90aa-cfe5db37a42a",
      "name": "Handle Earnings Error1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1344,
        912
      ]
    },
    {
      "parameters": {
        "jsCode": "const err = $input.item.json.error || 'Unknown error';\nconsole.error(`[Pipeline] Regulatory feed failed: ${err}`);\nreturn [];"
      },
      "id": "72d798bf-719e-492b-9589-f6f3518c2a2d",
      "name": "Handle Regulatory Error1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1344,
        1568
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse RSS XML and extract article metadata\nconst body = $input.item.json.data || '';\nconst MAX = 1;\n\nconst blocks = (body.match(/<item>(.*?)<\\/item>/gs) || []).slice(0, MAX);\nconst items = [];\n\nfor (const block of blocks) {\n  const title   = (block.match(/<title>(?:<!\\[CDATA\\[)?(.*?)(?:\\]\\]>)?<\\/title>/) || [])[1] || '';\n  const url     = (block.match(/<link>(.*?)<\\/link>/) || [])[1] || '';\n  const desc    = (block.match(/<description>(?:<!\\[CDATA\\[)?(.*?)(?:\\]\\]>)?<\\/description>/) || [])[1] || '';\n  const pubDate = (block.match(/<pubDate>(.*?)<\\/pubDate>/) || [])[1] || '';\n\n  if (title && url) {\n    items.push({ json: {\n      title: title.trim(),\n      url: url.trim(),\n      description: desc.replace(/<[^>]+>/g, '').trim().slice(0, 600),\n      pubDate,\n      sourceType: 'earnings',\n      sourceName: 'CNBC Earnings'\n    }});\n  }\n}\n\nconsole.log(`[Pipeline] Parsed ${items.length} earnings items`);\nreturn items;"
      },
      "id": "7e2147d6-fa44-4dc0-8aab-f36d065a0beb",
      "name": "Parse Earnings Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        1104
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse RSS and keyword-filter for AI relevance\nconst body = $input.item.json.data || '';\nconst MAX = 1;\n\nconst KEYWORDS = [\n  'artificial intelligence', 'AI', 'machine learning',\n  'automation', 'LLM', 'AI governance', 'AI compliance',\n  'AI regulation', 'AI Act', 'cybersecurity'\n];\n\nconst blocks = body.match(/<item>(.*?)<\\/item>/gs) || [];\nconst items = [];\n\nfor (const block of blocks) {\n  if (items.length >= MAX) break;\n\n  const title   = (block.match(/<title>(?:<!\\[CDATA\\[)?(.*?)(?:\\]\\]>)?<\\/title>/) || [])[1] || '';\n  const url     = (block.match(/<link>(.*?)<\\/link>/) || [])[1] || '';\n  const desc    = (block.match(/<description>(?:<!\\[CDATA\\[)?(.*?)(?:\\]\\]>)?<\\/description>/) || [])[1] || '';\n  const pubDate = (block.match(/<pubDate>(.*?)<\\/pubDate>/) || [])[1] || '';\n\n  const combined = (title + ' ' + desc).toLowerCase();\n  const isRelevant = KEYWORDS.some(kw => combined.includes(kw.toLowerCase()));\n\n  if (isRelevant && title && url) {\n    items.push({ json: {\n      title: title.trim(),\n      url: url.trim(),\n      description: desc.replace(/<[^>]+>/g, '').trim().slice(0, 600),\n      pubDate,\n      sourceType: 'regulatory',\n      sourceName: 'NIST'\n    }});\n  }\n}\n\nconsole.log(`[Pipeline] Parsed ${items.length} regulatory items`);\nreturn items;"
      },
      "id": "148d0e86-795c-43b1-9b7d-c772870c4341",
      "name": "Parse Regulatory Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1360,
        1376
      ]
    },
    {
      "parameters": {
        "jsCode": "// Merge streams + generate hash\nfunction simpleHash(str) {\n  let hash = 0;\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i);\n    hash = ((hash << 5) - hash) + char;\n    hash = hash & hash;\n  }\n  return Math.abs(hash).toString(16).padStart(8, '0');\n}\n\nconst items = $input.all();\nconst result = [];\n\nfor (const item of items) {\n  const { title, url } = item.json;\n  if (!title || !url) continue;\n  const hash = simpleHash(title + url);\n  result.push({ json: { ...item.json, hash } });\n}\n\nconsole.log(`[Pipeline] ${result.length} items ready for memory check`);\nreturn result;"
      },
      "id": "590dd83b-1f42-40e0-a952-20f369a34e3a",
      "name": "Merge and Hash Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1584,
        1248
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT COUNT(*) as duplicate_count, '{{ $json.hash }}' as hash, '{{ $json.title }}' as title, '{{ $json.url }}' as url, '{{ $json.sourceType }}' as source_type, '{{ $json.sourceName }}' as source_name, '{{ $json.description }}' as description FROM pipeline_memory WHERE hash = '{{ $json.hash }}'",
        "options": {}
      },
      "id": "310ed423-3129-451d-a6ac-5edc4eff258c",
      "name": "Check Memory (Postgres)1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        1824,
        1248
      ],
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// Check duplicate count and pass through original data\nconst item = $input.item.json;\nconst count = parseInt(item.duplicate_count || '0');\n\nif (count > 0) {\n  console.log('[Pipeline] Duplicate, skipping: ' + item.title);\n  return [];\n}\n\nconsole.log('[Pipeline] New item: ' + item.title);\nreturn [{ json: {\n  hash: item.hash,\n  title: item.title,\n  url: item.url,\n  sourceType: item.source_type,\n  sourceName: item.source_name,\n  description: item.description\n} }];"
      },
      "id": "f0acbe14-d4bd-4ff8-9540-3ff0a7257457",
      "name": "Filter Duplicates1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2064,
        1248
      ]
    },
    {
      "parameters": {
        "jsCode": "// Build Brand DNA config and inject into AI prompt\nconst brandDNA = {\n  voice: 'Direct, sharp, slightly contrarian. Practitioner who has seen things fail.',\n  hook: 'Open with a surprising stat or uncomfortable truth. Never start with I or In todays.',\n  structure: 'Short punchy paragraphs. Max 2 sentences each.',\n  cta: 'End with a quiet open question \u2014 not a hard sell.',\n  length: '150-220 words',\n  emoji: 'Maximum 1, only for directional emphasis like arrow down',\n  hashtags: 'Exactly 3, always on the very last line',\n  forbidden: 'leverage, synergy, ecosystem, game-changer, delve, robust, seamless, cutting-edge',\n  rules: [\n    'Always anchor to real data or a named source',\n    'Never make predictions \u2014 focus on what the data shows now',\n    'Every paragraph should feel like it is about the reader, not the writer',\n    'If it sounds like a vendor pitch, rewrite it'\n  ]\n};\n\nconst item = $input.item.json;\n\nconst prompt = `You are a ghostwriter for a senior enterprise AI practitioner publishing on LinkedIn.\n\nBRAND DNA \u2014 NON-NEGOTIABLE RULES:\nVoice: ${brandDNA.voice}\nHook style: ${brandDNA.hook}\nStructure: ${brandDNA.structure}\nClosing: ${brandDNA.cta}\nLength: ${brandDNA.length}\nEmoji: ${brandDNA.emoji}\nHashtags: ${brandDNA.hashtags}\nForbidden words: ${brandDNA.forbidden}\nRules:\n${brandDNA.rules.map(r => '- ' + r).join('\\n')}\n\nWrite a LinkedIn post based on this ${item.sourceType} update:\nTitle: ${item.title}\nSource: ${item.sourceName}\nSummary: ${item.description}\n\nFind the ONE most surprising or counterintuitive truth in this source and build the post around it.\nReturn ONLY the post text. No preamble. No quotation marks. No markdown.`;\n\nreturn [{ json: { ...item, prompt } }];"
      },
      "id": "c29af564-88b5-46c8-a7b9-8518a85fe741",
      "name": "Inject Brand DNA1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2304,
        1248
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract post text from Gemini and carry forward all item data\nconst output = $input.item.json.output || $input.item.json.text || '';\n\nif (!output.trim()) {\n  console.log('[Pipeline] Gemini returned empty output');\n  return [];\n}\n\n// Get original item data from Inject Brand DNA node\nconst original = $('Inject Brand DNA1').first().json;\n\nconsole.log('[Pipeline] Post drafted \u2014 ' + output.trim().split(' ').length + ' words');\n\nreturn [{ json: {\n  hash: original.hash,\n  title: original.title,\n  url: original.url,\n  sourceType: original.sourceType,\n  sourceName: original.sourceName,\n  description: original.description,\n  postText: output.trim()\n} }];"
      },
      "id": "702b3d82-84a3-4680-9cb2-e8fed544456e",
      "name": "Extract Post Text1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2832,
        1248
      ]
    },
    {
      "parameters": {
        "jsCode": "const item = $input.item.json;\n\nfunction simpleHash(str) {\n  let hash = 0;\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i);\n    hash = ((hash << 5) - hash) + char;\n    hash = hash & hash;\n  }\n  return Math.abs(hash).toString(16).padStart(8, '0');\n}\n\nconst token = simpleHash((item.hash || '') + 'dev-secret');\n\nconst approveUrl = `http://localhost:5678/webhook/pipeline-approval?hash=${item.hash}&token=${token}&action=approve`;\nconst rejectUrl  = `http://localhost:5678/webhook/pipeline-approval?hash=${item.hash}&token=${token}&action=reject`;\n\nconst slackBlocks = [\n  { type: 'header', text: { type: 'plain_text', text: '\ud83d\udccb LinkedIn Post \u2014 Ready for Review' } },\n  { type: 'section', fields: [\n    { type: 'mrkdwn', text: `*Source:* ${item.sourceName || 'Unknown'}` },\n    { type: 'mrkdwn', text: `*Type:* ${item.sourceType || 'Unknown'}` }\n  ]},\n  { type: 'section', text: { type: 'mrkdwn', text: `*Article:*\\n${item.title || 'Untitled'}` } },\n  { type: 'divider' },\n  { type: 'section', text: { type: 'mrkdwn', text: `*Draft Post:*\\n\\`\\`\\`${(item.postText || 'Generating...').slice(0, 800)}\\`\\`\\`` } },\n  { type: 'divider' },\n  { type: 'actions', elements: [\n    { type: 'button', text: { type: 'plain_text', text: '\u2705 Approve' }, style: 'primary', url: approveUrl },\n    { type: 'button', text: { type: 'plain_text', text: '\u274c Reject' }, style: 'danger', url: rejectUrl }\n  ]},\n  { type: 'context', elements: [{ type: 'mrkdwn', text: `\u23f1 Expires 48h` }] }\n];\n\nconst gmailHtml = `<html><body style=\"font-family:Arial,sans-serif;max-width:600px;margin:0 auto;padding:20px\">\n  <h2 style=\"color:#1a1a2e\">\ud83d\udccb LinkedIn Post \u2014 Approval Required</h2>\n  <table style=\"width:100%;border-collapse:collapse;margin-bottom:20px\">\n    <tr><td style=\"padding:8px;background:#f5f5f5;font-weight:bold\">Source</td><td style=\"padding:8px\">${item.sourceName || 'Unknown'}</td></tr>\n    <tr><td style=\"padding:8px;background:#f5f5f5;font-weight:bold\">Type</td><td style=\"padding:8px\">${item.sourceType || 'Unknown'}</td></tr>\n    <tr><td style=\"padding:8px;background:#f5f5f5;font-weight:bold\">Article</td><td style=\"padding:8px\">${item.title || 'Untitled'}</td></tr>\n  </table>\n  <h3>Draft Post</h3>\n  <div style=\"background:#f9f9f9;border-left:4px solid #667eea;padding:16px;white-space:pre-wrap;font-size:14px;line-height:1.7\">${item.postText || 'Generating...'}</div>\n  <br/>\n  <div style=\"text-align:center;margin:28px 0\">\n    <a href=\"${approveUrl}\" style=\"background:#28a745;color:white;padding:14px 36px;text-decoration:none;border-radius:6px;margin-right:16px;font-weight:bold;font-size:16px\">\u2705 Approve</a>\n    <a href=\"${rejectUrl}\" style=\"background:#dc3545;color:white;padding:14px 36px;text-decoration:none;border-radius:6px;font-weight:bold;font-size:16px\">\u274c Reject</a>\n  </div>\n  <p style=\"color:#aaa;font-size:11px;text-align:center\">Expires in 48 hours \u00b7 business_post_pipeline</p>\n</body></html>`;\n\nreturn [{ json: { ...item, token, approveUrl, rejectUrl, slackBlocks, gmailHtml } }];"
      },
      "id": "2d8053aa-d4fe-4265-8a98-10958daa69fc",
      "name": "Build Approval Notification1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3024,
        1248
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO pipeline_memory (hash, title, url, source_name, source_type, date_fetched, status)\nVALUES ('{{ $json.hash }}', '{{ $json.title }}', '{{ $json.url }}', '{{ $json.sourceName }}', '{{ $json.sourceType }}', NOW(), 'pending_approval')\nON CONFLICT (hash) DO NOTHING;",
        "options": {}
      },
      "id": "b1c65524-868b-4f66-a7fd-783d12a260c2",
      "name": "Memory: Mark Pending1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        3264,
        1152
      ],
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "sendTo": "=agentutk@gmail.com",
        "subject": "=\ud83d\udccb Approve Post: {{ $json.title }}",
        "message": "={{ $json.gmailHtml }}",
        "options": {}
      },
      "id": "80c79d4b-85a9-4688-b42b-68800df0daa6",
      "name": "Gmail: Send Preview1",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        3280,
        1360
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "path": "pipeline-approval",
        "responseMode": "responseNode",
        "options": {}
      },
      "id": "58087f86-29ef-4556-847a-dfd0b2fe6f77",
      "name": "Webhook: Approval Gate1",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        1712,
        1808
      ]
    },
    {
      "parameters": {
        "jsCode": "// Validate HMAC token\nconst { hash, token, action } = $input.item.json.query || {};\n\nif (!hash || !token || !['approve','reject'].includes(action)) {\n  return [{ json: { valid: false, reason: 'Bad parameters' } }];\n}\n\nfunction simpleHash(str) {\n  let h = 0;\n  for (let i = 0; i < str.length; i++) {\n    const char = str.charCodeAt(i);\n    h = ((h << 5) - h) + char;\n    h = h & h;\n  }\n  return Math.abs(h).toString(16).padStart(8, '0');\n}\n\nconst expected = simpleHash(hash + 'dev-secret');\n\nif (token !== expected) {\n  return [{ json: { valid: false, reason: 'Invalid token' } }];\n}\n\nreturn [{ json: { valid: true, hash, action } }];"
      },
      "id": "791802ce-c69e-48fd-80e8-40dda1212124",
      "name": "Validate Approval Token1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1952,
        1808
      ]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict",
            "version": 1
          },
          "conditions": [
            {
              "id": "cond-approve",
              "leftValue": "={{ $json.action }}",
              "rightValue": "approve",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        },
        "options": {}
      },
      "id": "1978eb0a-10b5-4059-ab58-91b232597afc",
      "name": "Approve or Reject?1",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        2192,
        1808
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE pipeline_memory \nSET status = '{{ $json.action }}', outcome_at = NOW()\nWHERE hash = '{{ $json.hash }}';\n\nINSERT INTO pipeline_audit (hash, action, actioned_at)\nVALUES ('{{ $json.hash }}', '{{ $json.action }}', NOW())\nON CONFLICT DO NOTHING;",
        "options": {}
      },
      "id": "30098026-0e90-43e9-9b17-139665fd842e",
      "name": "Update Status + Audit Log",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.6,
      "position": [
        2464,
        1808
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "=\u2705 Decision recorded: {{ $json.action }}. Pipeline updated.",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html"
              }
            ]
          }
        }
      },
      "id": "0f006f05-d135-4af8-9d28-197692ae2c41",
      "name": "Respond: Decision Recorded",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        2704,
        1808
      ]
    }
  ],
  "connections": {
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Gemini: Draft Post",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Schedule Trigger1": {
      "main": [
        [
          {
            "node": "Init Run1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Init Run1": {
      "main": [
        [
          {
            "node": "Fetch Earnings RSS1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch Regulatory RSS1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Earnings RSS1": {
      "main": [
        [
          {
            "node": "Parse Earnings Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Regulatory RSS1": {
      "main": [
        [
          {
            "node": "Parse Regulatory Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Earnings Items1": {
      "main": [
        [
          {
            "node": "Merge and Hash Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Regulatory Items1": {
      "main": [
        [
          {
            "node": "Merge and Hash Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge and Hash Items1": {
      "main": [
        [
          {
            "node": "Check Memory (Postgres)1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Memory (Postgres)1": {
      "main": [
        [
          {
            "node": "Filter Duplicates1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter Duplicates1": {
      "main": [
        [
          {
            "node": "Inject Brand DNA1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Inject Brand DNA1": {
      "main": [
        [
          {
            "node": "Gemini: Draft Post",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gemini: Draft Post": {
      "main": [
        [
          {
            "node": "Extract Post Text1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Post Text1": {
      "main": [
        [
          {
            "node": "Build Approval Notification1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Approval Notification1": {
      "main": [
        [
          {
            "node": "Memory: Mark Pending1",
            "type": "main",
            "index": 0
          },
          {
            "node": "Gmail: Send Preview1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Memory: Mark Pending1": {
      "main": [
        [
          {
            "node": "Slack: Approval Card",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook: Approval Gate1": {
      "main": [
        [
          {
            "node": "Validate Approval Token1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Validate Approval Token1": {
      "main": [
        [
          {
            "node": "Approve or Reject?1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Approve or Reject?1": {
      "main": [
        [
          {
            "node": "Update Status + Audit Log",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Update Status + Audit Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Update Status + Audit Log": {
      "main": [
        [
          {
            "node": "Respond: Decision Recorded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Approval Card": {
      "main": [
        []
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false,
    "timeSavedMode": "fixed",
    "errorWorkflow": "aQ4pRJ43HvubpN2W",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "00b441de-a307-44e2-98cb-fc2dced26b7f",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodeGroups": [],
  "id": "SkUAnXnyWZSLT87x",
  "tags": []
}

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

Business Post Pipeline. Uses agent, lmChatGoogleGemini, slack, httpRequest. Scheduled trigger; 24 nodes.

Source: https://github.com/utkarsh-ankit/business_post_pipeline/blob/main/workflows/workflow_4.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

Business Post Pipeline. Uses postgres, httpRequest, agent, lmChatGoogleGemini. Scheduled trigger; 30 nodes.

Postgres, HTTP Request, Agent +4
AI & RAG

Business Post Pipeline. Uses httpRequest, postgres, agent, lmChatGoogleGemini. Scheduled trigger; 27 nodes.

HTTP Request, Postgres, Agent +3
AI & RAG

Business Post Pipeline. Uses agent, lmChatGoogleGemini, slack, postgres. Scheduled trigger; 27 nodes.

Agent, Google Gemini Chat, Slack +3
AI & RAG

Automates sales data analysis and strategic insight generation for sales managers and strategists needing actionable intelligence. Fetches multi-source data from sales, marketing, and financial system

HTTP Request, Agent, OpenAI Chat +6
AI & RAG

Scheduled runs collect data from oil markets, global shipping movements, news sources, and official reports. The system performs statistical checks to detect anomalies and volatility shifts. An AI-dri

HTTP Request, Agent, Gmail +3