AutomationFlowsAI & RAG › Business Post Pipeline (agent)

Business Post Pipeline (agent)

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

Cron / scheduled trigger★★★★☆ complexityAI-powered27 nodesAgentGoogle Gemini ChatSlackPostgresHTTP RequestGmail
AI & RAG Trigger: Cron / scheduled Nodes: 27 Complexity: ★★★★☆ AI nodes: yes Added:
Business Post Pipeline (agent) — 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": "d4be055b-4eef-45fd-bfd3-860a4732dca7",
      "name": "Gemini: Draft Post",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 3.1,
      "position": [
        3504,
        1392
      ],
      "retryOnFail": true,
      "waitBetweenTries": 2000
    },
    {
      "parameters": {
        "options": {}
      },
      "id": "ced83c48-f11d-4560-bd96-da65c7f16fee",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1.1,
      "position": [
        3504,
        1584
      ],
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "select": "channel",
        "channelId": {
          "__rl": true,
          "value": "#content-approvals",
          "mode": "name"
        },
        "text": "Please check your Gmail for post approval.",
        "otherOptions": {}
      },
      "id": "fac7f3c3-6f07-4e5f-9e24-fb220c145157",
      "name": "Slack: Approval Card",
      "type": "n8n-nodes-base.slack",
      "typeVersion": 2.5,
      "position": [
        4224,
        1248
      ],
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO pipeline_audit (hash, action, actioned_at)\nVALUES ('{{ $json.hash }}', 'central_log', NOW())\nON CONFLICT DO NOTHING;",
        "options": {}
      },
      "id": "8262fb52-32e0-49c6-afd8-45a6e174740c",
      "name": "Central Audit Log",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        5904,
        1392
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours",
              "hoursInterval": 6
            }
          ]
        }
      },
      "id": "83343212-9ab5-494f-bdd8-4212ecbba8e9",
      "name": "Schedule Trigger1",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.1,
      "position": [
        1568,
        1392
      ]
    },
    {
      "parameters": {
        "jsCode": "const runId = `run_${Date.now()}`;\nconst runAt = new Date().toISOString();\nconsole.log(`[Pipeline] Starting run: ${runId}`);\nreturn [{ json: { runId, runAt } }];"
      },
      "id": "89269cff-36e1-48f6-838c-22ab36e504fc",
      "name": "Init Run1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1808,
        1392
      ]
    },
    {
      "parameters": {
        "url": "https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=15839135",
        "options": {
          "timeout": 30000
        }
      },
      "id": "fe16651e-efeb-488d-a5c8-81be0fcab483",
      "name": "Fetch Earnings RSS1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2064,
        1248
      ]
    },
    {
      "parameters": {
        "url": "https://www.nist.gov/news-events/news/rss.xml",
        "options": {
          "timeout": 10000
        }
      },
      "id": "09f5ff76-6df2-4dd6-b60f-4a32c6d2c155",
      "name": "Fetch Regulatory RSS1",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        2064,
        1520
      ]
    },
    {
      "parameters": {
        "jsCode": "// Feed failed \u2014 log and swallow so other stream continues\nconst err = $input.item.json.error || 'Unknown error';\nconsole.error(`[Pipeline] Earnings feed failed: ${err}`);\nreturn [];"
      },
      "id": "daab39bb-5a29-44aa-97f5-4b354535b7fe",
      "name": "Handle Earnings Error1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2064,
        1056
      ]
    },
    {
      "parameters": {
        "jsCode": "const err = $input.item.json.error || 'Unknown error';\nconsole.error(`[Pipeline] Regulatory feed failed: ${err}`);\nreturn [];"
      },
      "id": "d07a5b16-db5c-408e-b7cf-4a3b1f6d7b09",
      "name": "Handle Regulatory Error1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2064,
        1760
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse RSS XML and extract article metadata\nconst body = $input.item.json.data || '';\nconst MAX = 3; // max items per run\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: 'Yahoo Finance'\n    }});\n  }\n}\n\nconsole.log(`[Pipeline] Parsed ${items.length} earnings items`);\nreturn items;"
      },
      "id": "5647c3b7-2843-4a0e-b0d6-fec3adfe38ae",
      "name": "Parse Earnings Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2304,
        1248
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse RSS and keyword-filter for AI relevance\nconst body = $input.item.json.data || '';\nconst MAX = 3;\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": "ed7b470f-98fb-46ab-8e60-03c564fd7995",
      "name": "Parse Regulatory Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2304,
        1520
      ]
    },
    {
      "parameters": {
        "jsCode": "// Simple hash function \u2014 crypto module not available in n8n sandbox\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; // Convert to 32bit integer\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\n  const hash = simpleHash(title + url);\n\n  result.push({\n    json: {\n      ...item.json,\n      hash\n    }\n  });\n}\n\nconsole.log(`[Pipeline] ${result.length} items ready for memory check`);\nreturn result;"
      },
      "id": "1e4ee654-7cea-4e11-aac3-2ba1b2ec728d",
      "name": "Merge and Hash Items1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        2544,
        1392
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "SELECT hash FROM pipeline_memory WHERE hash = '{{ $json.hash }}' LIMIT 1;",
        "options": {}
      },
      "id": "39e1e164-12c2-4b37-aa8a-18d24c8748a3",
      "name": "Check Memory (Postgres)1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        2784,
        1392
      ],
      "alwaysOutputData": true,
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "onError": "continueRegularOutput"
    },
    {
      "parameters": {
        "jsCode": "// If Postgres returned a row \u2192 duplicate, skip\n// If empty \u2192 new item, pass through\nconst result = $input.item.json;\nif (Array.isArray(result) && result.length > 0) {\n  console.log(`[Pipeline] Duplicate skipped: ${result[0]?.hash}`);\n  return [];\n}\nreturn [$input.item];"
      },
      "id": "dc1936b3-6e0b-4480-afbb-25aa443eee22",
      "name": "Filter Duplicates1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3024,
        1392
      ]
    },
    {
      "parameters": {
        "jsCode": "// Build Brand DNA style 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": "fc44d9c7-cad3-4511-9525-35460e6dcb97",
      "name": "Inject Brand DNA1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3264,
        1392
      ]
    },
    {
      "parameters": {
        "jsCode": "// Extract post text from Gemini agent output\nconst output = $input.item.json.output || '';\nif (!output.trim()) {\n  console.error('[Pipeline] Gemini returned empty output');\n  return [];\n}\nconsole.log(`[Pipeline] Post drafted \u2014 ${output.trim().split(' ').length} words`);\nreturn [{ json: { ...$node['Inject Brand DNA1'].json, postText: output.trim() } }];"
      },
      "id": "8d3a0796-fcc5-4b4a-bb32-330e344f7d83",
      "name": "Extract Post Text1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3792,
        1392
      ]
    },
    {
      "parameters": {
        "jsCode": "const item = $input.item.json;\n\n// Simple hash for token without crypto\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\n// Slack Block Kit\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}` },\n    { type: 'mrkdwn', text: `*Type:* ${item.sourceType}` }\n  ]},\n  { type: 'section', text: { type: 'mrkdwn', text: `*Article:*\\n${item.title}` } },\n  { type: 'divider' },\n  { type: 'section', text: { type: 'mrkdwn', text: `*Draft Post:*\\n\\`\\`\\`${item.postText ? item.postText.slice(0, 800) : 'Generating...'}\\`\\`\\`` } },\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 \u00b7 Hash: ${item.hash ? item.hash.slice(0,8) : 'N/A'}...` }] }\n];\n\n// Gmail HTML\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}</td></tr>\n    <tr><td style=\"padding:8px;background:#f5f5f5;font-weight:bold\">Type</td><td style=\"padding:8px\">${item.sourceType}</td></tr>\n    <tr><td style=\"padding:8px;background:#f5f5f5;font-weight:bold\">Article</td><td style=\"padding:8px\">${item.title}</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": "065edc66-661f-43b4-ae71-ddc86d0c1b01",
      "name": "Build Approval Notification1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3984,
        1392
      ]
    },
    {
      "parameters": {
        "sendTo": "=agentutk@gmail.com",
        "subject": "=\ud83d\udccb Approve Post: {{ $json.title }}",
        "message": "={{ $json.gmailHtml }}",
        "options": {}
      },
      "id": "a04f895a-ecec-4542-9794-ac4e9dab831e",
      "name": "Gmail: Send Preview1",
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        4224,
        1520
      ],
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "INSERT INTO pipeline_memory (hash, title, url, source_name, source_type, date_fetched, status)\nVALUES ('{{ $json.hash }}', '{{ $json.title.replace(/'/g, \"''\") }}', '{{ $json.url }}', '{{ $json.sourceName }}', '{{ $json.sourceType }}', NOW(), 'pending_approval')\nON CONFLICT (hash) DO NOTHING;",
        "options": {}
      },
      "id": "cc469ced-938a-4f89-9abd-2472730ccc62",
      "name": "Memory: Mark Pending1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        4464,
        1392
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "path": "pipeline-approval",
        "options": {}
      },
      "id": "7bdb2ac6-43ce-4f1c-8439-5adc23ca9bac",
      "name": "Webhook: Approval Gate1",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        4704,
        1392
      ]
    },
    {
      "parameters": {
        "jsCode": "// Validate HMAC token \u2014 prevents spoofed approvals\nconst { hash, token, action } = $input.item.json.query || {};\nif (!hash || !token || !['approve','reject'].includes(action)) {\n  return [{ json: { valid: false, reason: 'Bad parameters' } }];\n}\nconst expected = require('crypto')\n  .createHmac('sha256', process.env.APPROVAL_WEBHOOK_SECRET || 'dev-secret')\n  .update(hash).digest('hex').slice(0, 16);\nif (token !== expected) {\n  console.error(`[Pipeline] Invalid token for hash ${hash}`);\n  return [{ json: { valid: false, reason: 'Invalid token' } }];\n}\nconsole.log(`[Pipeline] Decision: ${action} \u2014 hash: ${hash}`);\nreturn [{ json: { valid: true, hash, action } }];"
      },
      "id": "fcdf6a4e-e88b-4780-ab80-806ca7b01858",
      "name": "Validate Approval Token1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        4944,
        1392
      ]
    },
    {
      "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": "cac7c43e-953a-4701-992f-b4ddbeba799d",
      "name": "Approve or Reject?1",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2.2,
      "position": [
        5184,
        1392
      ]
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE pipeline_memory SET status = 'approved', outcome_at = NOW() WHERE hash = '{{ $json.hash }}';\nINSERT INTO pipeline_audit (hash, action, actioned_at) VALUES ('{{ $json.hash }}', 'approved', NOW()) ON CONFLICT DO NOTHING;",
        "options": {}
      },
      "id": "d4be8bed-9a86-41da-81d1-b91b029d6588",
      "name": "Memory: Mark Approved1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        5424,
        1248
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "executeQuery",
        "query": "UPDATE pipeline_memory SET status = 'rejected', outcome_at = NOW() WHERE hash = '{{ $json.hash }}';\nINSERT INTO pipeline_audit (hash, action, actioned_at) VALUES ('{{ $json.hash }}', 'rejected', NOW()) ON CONFLICT DO NOTHING;",
        "options": {}
      },
      "id": "1e792ec9-4906-41e8-9ae1-e1144c4ea46e",
      "name": "Memory: Mark Rejected1",
      "type": "n8n-nodes-base.postgres",
      "typeVersion": 2.5,
      "position": [
        5424,
        1520
      ],
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "<html><body style='font-family:Arial;text-align:center;padding:60px'><h2 style='color:#28a745'>\u2705 Post Approved!</h2><p>The LinkedIn post has been queued for publishing.</p></body></html>",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html"
              }
            ]
          }
        }
      },
      "id": "46ce071c-93f5-44f6-bcfa-6203580b7507",
      "name": "Response: Approved1",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        5664,
        1248
      ]
    },
    {
      "parameters": {
        "respondWith": "text",
        "responseBody": "<html><body style='font-family:Arial;text-align:center;padding:60px'><h2 style='color:#dc3545'>\u274c Post Rejected</h2><p>Draft archived. Will not be published.</p></body></html>",
        "options": {
          "responseHeaders": {
            "entries": [
              {
                "name": "Content-Type",
                "value": "text/html"
              }
            ]
          }
        }
      },
      "id": "628bed67-2e0f-450a-9ba1-f65d40af75fd",
      "name": "Response: Rejected1",
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.1,
      "position": [
        5664,
        1520
      ]
    }
  ],
  "connections": {
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Gemini: Draft Post",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Gemini: Draft Post": {
      "main": [
        [
          {
            "node": "Extract Post Text1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Slack: Approval Card": {
      "main": [
        []
      ]
    },
    "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
          }
        ]
      ]
    },
    "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
          }
        ]
      ]
    },
    "Extract Post Text1": {
      "main": [
        [
          {
            "node": "Build Approval Notification1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Approval Notification1": {
      "main": [
        [
          {
            "node": "Slack: Approval Card",
            "type": "main",
            "index": 0
          },
          {
            "node": "Gmail: Send Preview1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail: Send Preview1": {
      "main": [
        [
          {
            "node": "Memory: Mark Pending1",
            "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": "Memory: Mark Approved1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Memory: Mark Rejected1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Memory: Mark Approved1": {
      "main": [
        [
          {
            "node": "Response: Approved1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Memory: Mark Rejected1": {
      "main": [
        [
          {
            "node": "Response: Rejected1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Response: Approved1": {
      "main": [
        [
          {
            "node": "Central Audit Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Response: Rejected1": {
      "main": [
        [
          {
            "node": "Central Audit Log",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Regulatory Items1": {
      "main": [
        [
          {
            "node": "Merge and Hash Items1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate",
    "availableInMCP": false,
    "timeSavedMode": "fixed",
    "errorWorkflow": "aQ4pRJ43HvubpN2W",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "40b5d3aa-49e3-436d-b7aa-f4092c3f20ae",
  "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, postgres. Scheduled trigger; 27 nodes.

Source: https://github.com/utkarsh-ankit/business_post_pipeline/blob/main/workflows/workflow_3.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, httpRequest. Scheduled trigger; 24 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