How to Build an AI-Powered Content Distribution System with n8n (Free Template)

How to Build an AI-Powered Content Distribution System with n8n (Free Template)

You publish a newsletter every week. Then you spend hours manually creating social posts, scheduling them, and tracking what went live. This workflow eliminates that bottleneck. You'll build a system that converts your newsletter into 10-20 platform-specific social posts, stores them in Google Sheets for review, and automatically publishes approved content across Instagram, LinkedIn, X, and Facebook. By the end of this guide, you'll have a working n8n workflow that handles the entire content distribution pipeline.

The Problem: Manual Content Repurposing Kills Productivity

You write valuable content in your newsletter. But extracting social posts from that content requires manual effort every single time.

Current challenges:

  • Manually reading newsletters and brainstorming 10-20 social post ideas takes 2-3 hours per newsletter
  • Adapting content for different platforms (Instagram vs LinkedIn vs X) requires understanding each platform's best practices
  • Scheduling posts across 4+ platforms means logging into multiple tools and copy-pasting content
  • Tracking which posts went live and which are still pending requires spreadsheet maintenance

Business impact:

  • Time spent: 3-4 hours per newsletter on content repurposing and scheduling
  • Inconsistent posting schedule when you're busy with client work
  • Lost engagement opportunities because social content doesn't go out consistently
  • Mental overhead of remembering to create and schedule posts after each newsletter

The Solution Overview

This n8n workflow automates the entire newsletter-to-social pipeline. It monitors your newsletter source (Mailchimp or Substack), extracts the content, uses OpenAI to generate platform-specific social posts, writes them to Google Sheets for review, and automatically publishes approved posts via Buffer. The system handles content generation, approval workflows, and multi-platform scheduling without manual intervention. You mark posts as "READY" in the Sheet, and n8n handles the rest.

What You'll Build

This workflow delivers a complete content distribution system with approval gates and multi-platform publishing.

Component Technology Purpose
Newsletter Source Mailchimp/Substack API Fetch published newsletter content automatically
AI Content Generator OpenAI GPT-4 Generate 10-20 platform-specific social posts from newsletter
Content Warehouse Google Sheets Store generated posts with approval status tracking
Approval Workflow n8n Schedule + Filter Nodes Check Sheet every hour for posts marked "READY"
Social Scheduler Buffer API Publish approved posts to Instagram, LinkedIn, X, Facebook
Error Handling n8n Error Workflow Catch API failures and log issues for review

Key capabilities:

  • Automatic newsletter monitoring (checks every 6 hours for new content)
  • AI-powered post generation with platform-specific formatting
  • Manual review and approval via Google Sheets interface
  • Automated multi-platform publishing on your schedule
  • Complete audit trail of what was generated, approved, and published

Prerequisites

Before starting, ensure you have:

  • n8n instance (cloud or self-hosted version 1.0+)
  • OpenAI API account with GPT-4 access ($20/month minimum usage)
  • Google account with Sheets API enabled
  • Buffer account (Essentials plan or higher for API access)
  • Mailchimp or Substack account with API credentials
  • Basic understanding of API authentication and JSON structure

Step 1: Set Up Newsletter Content Ingestion

This phase monitors your newsletter platform and extracts new content when published.

Configure the Newsletter Trigger

  1. Add a Schedule Trigger node set to run every 6 hours
  2. Connect an HTTP Request node to your newsletter API endpoint
  3. Add authentication credentials (API key for Mailchimp or Substack)

For Mailchimp:

{
  "method": "GET",
  "url": "https://{{dc}}.api.mailchimp.com/3.0/campaigns",
  "authentication": "predefinedCredentialType",
  "nodeCredentialType": "mailchimpApi",
  "qs": {
    "status": "sent",
    "since_send_time": "{{ $now.minus({hours: 6}).toISO() }}"
  }
}

For Substack:

{
  "method": "GET", 
  "url": "https://{{subdomain}}.substack.com/api/v1/posts",
  "authentication": "headerAuth",
  "qs": {
    "limit": 1,
    "offset": 0
  }
}

Why this works:
The Schedule Trigger creates a polling mechanism that checks for new newsletters every 6 hours. The since_send_time parameter ensures you only fetch newsletters published in the last 6 hours, preventing duplicate processing. This approach is more reliable than webhooks, which can fail silently if your newsletter platform has issues.

Add a Function node to extract the newsletter body content and metadata:

const items = $input.all();
const newsletters = [];

for (const item of items) {
  const data = item.json;
  
  // Extract content based on platform
  const content = data.archive_html || data.body_html || data.html;
  const title = data.settings?.title || data.title;
  const url = data.archive_url || data.canonical_url;
  
  if (content && content.length > 500) {
    newsletters.push({
      json: {
        title: title,
        content: content,
        url: url,
        published_date: data.send_time || data.post_date,
        newsletter_id: data.id
      }
    });
  }
}

return newsletters;

Step 2: Generate Platform-Specific Social Posts with AI

This section uses OpenAI to create 10-20 social posts optimized for each platform.

Configure OpenAI Content Generation

  1. Add an OpenAI node after the newsletter extraction
  2. Select the "Message a Model" operation
  3. Choose GPT-4 as the model (GPT-3.5-turbo works but produces lower quality)

Prompt structure:

You are a social media content strategist for a boutique real estate firm in NYC.

Newsletter Title: {{$json.title}}
Newsletter Content: {{$json.content}}
Newsletter URL: {{$json.url}}

Generate exactly 15 social media posts from this newsletter content. Create posts optimized for these platforms:
- 5 posts for Instagram (engaging, visual-focused, 150-200 characters, 3-5 hashtags)
- 5 posts for LinkedIn (professional, thought leadership, 200-300 characters, 2-3 hashtags)  
- 5 posts for X/Twitter (concise, conversation-starting, 200-280 characters, 1-2 hashtags)

Requirements:
- Each post must reference specific insights from the newsletter
- Include the newsletter URL in every post
- Use platform-appropriate tone and formatting
- No generic promotional language
- Focus on valuable insights, not self-promotion

Return your response as a JSON array with this exact structure:
[
  {
    "platform": "instagram",
    "post_text": "...",
    "hashtags": ["tag1", "tag2"],
    "character_count": 175
  }
]

Why this approach:
Specific character count requirements prevent posts from being truncated. The JSON structure ensures consistent parsing in the next step. Requesting 15 posts (5 per platform) gives you options while keeping API costs reasonable ($0.03-0.05 per newsletter). The prompt emphasizes newsletter-specific content to avoid generic AI output.

Add a Function node to parse the OpenAI response:

const response = $input.first().json;
let posts = [];

try {
  // OpenAI sometimes wraps JSON in markdown code blocks
  const jsonMatch = response.choices[0].message.content.match(/\[[\s\S]*\]/);
  posts = JSON.parse(jsonMatch[0]);
} catch (error) {
  throw new Error(`Failed to parse OpenAI response: ${error.message}`);
}

// Add metadata to each post
return posts.map((post, index) => ({
  json: {
    ...post,
    newsletter_id: $('Extract Newsletter Content').item.json.newsletter_id,
    newsletter_title: $('Extract Newsletter Content').item.json.title,
    newsletter_url: $('Extract Newsletter Content').item.json.url,
    status: 'PENDING',
    generated_date: new Date().toISOString(),
    post_id: `${Date.now()}_${index}`
  }
}));

Step 3: Write Generated Posts to Google Sheets

This phase creates your "content warehouse" where you review and approve posts.

Set Up Google Sheets Structure

Create a new Google Sheet with these columns:

  • A: post_id
  • B: newsletter_title
  • C: platform
  • D: post_text
  • E: hashtags
  • F: status (PENDING/READY/PUBLISHED)
  • G: generated_date
  • H: published_date
  • I: buffer_post_id
  • J: newsletter_url

Configure Google Sheets Node

  1. Add a Google Sheets node set to "Append" operation
  2. Authenticate with your Google account
  3. Select your content warehouse spreadsheet
  4. Map fields to columns

Field mapping:

{
  "post_id": "={{$json.post_id}}",
  "newsletter_title": "={{$json.newsletter_title}}",
  "platform": "={{$json.platform}}",
  "post_text": "={{$json.post_text}}",
  "hashtags": "={{$json.hashtags.join(', ')}}",
  "status": "PENDING",
  "generated_date": "={{$json.generated_date}}",
  "published_date": "",
  "buffer_post_id": "",
  "newsletter_url": "={{$json.newsletter_url}}"
}

Why this structure:
The post_id provides a unique identifier for tracking. The status column creates your approval gate—you manually change "PENDING" to "READY" for posts you want published. The buffer_post_id field stores the Buffer API response for troubleshooting. This single-sheet approach is simpler than multiple sheets per platform.

Step 4: Build the Approval and Publishing Workflow

This section monitors your Sheet for approved posts and publishes them via Buffer.

Configure the Approval Checker

  1. Add a new Schedule Trigger (separate workflow) that runs every hour
  2. Add a Google Sheets node set to "Read" operation
  3. Add a Filter node to find posts where status = "READY"

Filter configuration:

{
  "conditions": {
    "string": [
      {
        "value1": "={{$json.status}}",
        "operation": "equals",
        "value2": "READY"
      }
    ]
  }
}

Configure Buffer Publishing

Add an HTTP Request node for each platform with Buffer's API:

{
  "method": "POST",
  "url": "https://api.bufferapp.com/1/updates/create.json",
  "authentication": "genericCredentialType",
  "genericAuthType": "oAuth2Api",
  "sendBody": true,
  "bodyParameters": {
    "parameters": [
      {
        "name": "text",
        "value": "={{$json.post_text}}

{{$json.hashtags}}

{{$json.newsletter_url}}"
      },
      {
        "name": "profile_ids[]",
        "value": "={{$json.platform === 'instagram' ? $vars.instagram_profile_id : $json.platform === 'linkedin' ? $vars.linkedin_profile_id : $json.platform === 'twitter' ? $vars.twitter_profile_id : $vars.facebook_profile_id}}"
      },
      {
        "name": "shorten",
        "value": "false"
      }
    ]
  }
}

Variables to customize:
Store Buffer profile IDs as workflow variables:

  • instagram_profile_id: Your Instagram Buffer profile ID
  • linkedin_profile_id: Your LinkedIn Buffer profile ID
  • twitter_profile_id: Your X/Twitter Buffer profile ID
  • facebook_profile_id: Your Facebook Buffer profile ID

Find these IDs by calling GET https://api.bufferapp.com/1/profiles.json

Update Sheet with Published Status

Add a Google Sheets node set to "Update" operation:

{
  "operation": "update",
  "sheetName": "Content Warehouse",
  "dataMode": "defineBelow",
  "columnToMatchOn": "post_id",
  "valueToMatchOn": "={{$json.post_id}}",
  "fieldsToUpdate": {
    "values": [
      {
        "column": "status",
        "value": "PUBLISHED"
      },
      {
        "column": "published_date", 
        "value": "={{$now.toISO()}}"
      },
      {
        "column": "buffer_post_id",
        "value": "={{$json.id}}"
      }
    ]
  }
}

Why this works:
The hourly check creates a predictable publishing cadence. Matching on post_id ensures you update the correct row even if multiple posts are ready. Storing the buffer_post_id lets you troubleshoot if a post doesn't appear on the platform—you can check Buffer's dashboard using that ID.

Workflow Architecture Overview

This workflow consists of 18 nodes organized into 2 main workflows:

  1. Content Generation Workflow (Nodes 1-9): Monitors newsletter, generates posts, writes to Sheet
  2. Publishing Workflow (Nodes 10-18): Checks Sheet hourly, publishes approved posts, updates status

Execution flow:

  • Trigger: Schedule (every 6 hours for generation, every 1 hour for publishing)
  • Average run time: 45 seconds for generation, 15 seconds per post for publishing
  • Key dependencies: OpenAI API, Google Sheets API, Buffer API all must be configured

Critical nodes:

  • OpenAI Chat Model: Handles content generation with GPT-4, costs $0.03-0.05 per newsletter
  • Function (Parse AI Response): Extracts JSON from OpenAI response, handles edge cases
  • Google Sheets (Append): Writes all generated posts in single batch operation
  • Filter (Status Check): Only processes posts marked "READY", prevents duplicate publishing
  • HTTP Request (Buffer API): Publishes to social platforms with platform-specific profile IDs

The complete n8n workflow JSON template is available at the bottom of this article.

Critical Configuration Settings

OpenAI Integration

Required fields:

  • API Key: Your OpenAI API key from platform.openai.com
  • Model: gpt-4 (not gpt-3.5-turbo—quality difference is significant)
  • Temperature: 0.7 (balances creativity with consistency)
  • Max Tokens: 2000 (allows for 15 detailed posts)

Common issues:

  • Using GPT-3.5-turbo → Generic, low-quality posts that need heavy editing
  • Temperature above 0.9 → Inconsistent formatting, sometimes breaks JSON structure
  • Max tokens below 1500 → Truncated responses, incomplete post lists

Buffer API Configuration

Authentication setup:

  1. Go to Buffer Dashboard → Account → Developer
  2. Create new app to get Client ID and Secret
  3. In n8n, add OAuth2 credential with these endpoints:
    • Authorization URL: https://bufferapp.com/oauth2/authorize
    • Access Token URL: https://api.bufferapp.com/1/oauth2/token.json
    • Scope: Leave empty (Buffer doesn't use scopes)

Profile ID mapping:
Create a workflow variable for each platform. Get IDs by calling:

GET https://api.bufferapp.com/1/profiles.json

Response includes:

{
  "id": "5f8a9b2c3d4e5f6g7h8i9j0k",
  "service": "instagram",
  "formatted_service": "Instagram"
}

Store the id value in your workflow variables.

Google Sheets Permissions

Required scopes:

  • https://www.googleapis.com/auth/spreadsheets (read and write)
  • https://www.googleapis.com/auth/drive.file (access specific files)

Sheet structure requirements:

  • First row must be headers (workflow expects row 1 to be column names)
  • Status column must use exact values: "PENDING", "READY", "PUBLISHED"
  • Date columns should use ISO 8601 format (YYYY-MM-DDTHH:mm:ss.sssZ)

Testing & Validation

Test the newsletter ingestion:

  1. Manually trigger the Content Generation workflow
  2. Check the "Extract Newsletter Content" node output
  3. Verify you see newsletter title, content (>500 characters), and URL
  4. If empty, check your API credentials and date range filter

Test AI post generation:

  1. Run workflow with a real newsletter
  2. Inspect "Parse AI Response" node output
  3. Confirm you see 15 posts with platform, post_text, and hashtags fields
  4. If parsing fails, check OpenAI response format in previous node

Test Google Sheets writing:

  1. After generation completes, open your Sheet
  2. Verify 15 new rows appeared with status "PENDING"
  3. Check that post_text isn't truncated (Google Sheets limit is 50,000 characters per cell)
  4. If rows are missing, check Sheet name matches node configuration exactly

Test publishing workflow:

  1. Manually change one post status to "READY" in Sheet
  2. Manually trigger the Publishing workflow
  3. Check Buffer dashboard to confirm post appears in queue
  4. Verify Sheet status updated to "PUBLISHED" with timestamp
  5. If post doesn't appear in Buffer, check the buffer_post_id in Sheet and search Buffer by ID

Common troubleshooting:

Issue Cause Solution
No newsletters fetched Date filter too restrictive Change since_send_time to last 24 hours for testing
AI response not parsing OpenAI wrapped JSON in markdown Function node already handles this—check for API errors instead
Posts not publishing Buffer profile ID incorrect Re-fetch profile IDs and update workflow variables
Duplicate posts published Status not updating to PUBLISHED Add error handling to Sheet update node

Production Deployment Checklist

Area Requirement Why It Matters
Error Handling Add Error Trigger workflow that logs failures to separate Sheet Prevents silent failures—you'll know within 1 hour if something breaks
API Rate Limits OpenAI: 3 requests/min, Buffer: 10 requests/min Batch operations and add 2-second delays between Buffer posts
Monitoring Set up n8n workflow execution notifications via email Get alerted if workflow fails 2+ times in a row
Backup Export workflow JSON weekly and store in Google Drive Recover quickly if you accidentally break the workflow
Documentation Add sticky notes to each node explaining its purpose Reduces troubleshooting time from 30 minutes to 5 minutes
Cost Management Set OpenAI spending limit to $50/month Prevents runaway costs if workflow triggers unexpectedly

Recommended monitoring setup:

  1. Create a new workflow with Error Trigger
  2. Add Google Sheets node to write errors to "Error Log" sheet
  3. Add Send Email node to notify you of failures
  4. Link this error workflow to both main workflows

Real-World Use Cases

Use Case 1: Weekly Newsletter to Daily Social Posts

  • Industry: Real estate, financial services, consulting
  • Scale: 1 newsletter/week → 15 posts → 3 posts/day for 5 days
  • Modifications needed: Change Buffer API call to schedule posts across 5 days instead of immediate publishing
  • Add this to Buffer API body: "scheduled_at": "={{$now.plus({days: $itemIndex / 3}).toUnixInteger()}}"

Use Case 2: Multi-Author Content Hub

  • Industry: Marketing agencies, media companies
  • Scale: 5 newsletters/week from different authors → 75 posts/week
  • Modifications needed: Add author name to Sheet, create separate Buffer profiles per author
  • Change OpenAI prompt to include: "Author: {{$json.author_name}}" and adjust tone accordingly

Use Case 3: Product Launch Campaign

  • Industry: SaaS, e-commerce
  • Scale: 1 product announcement → 20 posts over 2 weeks
  • Modifications needed: Change OpenAI prompt to focus on product features, benefits, and use cases
  • Add "campaign_id" column to Sheet for grouping related posts

Use Case 4: Thought Leadership Series

  • Industry: Executive coaching, professional services
  • Scale: Monthly long-form article → 30 posts (10 per platform)
  • Modifications needed: Increase OpenAI max_tokens to 3000, request 30 posts instead of 15
  • Add post sequencing logic to publish posts in specific order (intro posts first, then deep dives)

Customizing This Workflow

Alternative Integrations

Instead of Mailchimp/Substack:

  • ConvertKit: Use GET https://api.convertkit.com/v3/broadcasts endpoint—requires 3 node changes (URL, auth, response parsing)
  • Ghost: Better if you self-host your newsletter—use GET https://yourdomain.com/ghost/api/v3/admin/posts/ with Admin API key
  • WordPress: Use when newsletter is blog-based—requires RSS feed parser node instead of API call

Instead of Buffer:

  • Hootsuite: Enterprise features but more expensive—swap HTTP Request node for Hootsuite API, same structure
  • Later: Best for Instagram-heavy strategies—requires image URL field in Sheet, +2 nodes for image handling
  • Direct API posting: Use platform APIs directly (Meta Graph API, LinkedIn API, X API)—requires 4 separate HTTP Request nodes with different auth methods

Workflow Extensions

Add automated image generation:

  • Connect to DALL-E 3 API or Midjourney to create post images
  • Add image URL column to Sheet
  • Modify Buffer API call to include media attachment
  • Nodes needed: +3 (HTTP Request for image generation, Set node for URL, conditional logic)
  • Cost impact: +$0.04 per image with DALL-E 3

Add performance tracking:

  • Pull engagement metrics from Buffer Analytics API weekly
  • Write metrics back to Sheet (likes, comments, shares, clicks)
  • Generate monthly performance report
  • Nodes needed: +8 (Schedule trigger, HTTP Request, Function for calculations, Google Sheets update)
  • Benefit: Identify which newsletter topics generate most engagement

Add approval notifications:

  • Send Slack/email notification when new posts are ready for review
  • Include direct link to Google Sheet
  • Nodes needed: +2 (Slack/Email node after Sheet write)
  • Benefit: Reduces approval delay from 24 hours to 2 hours

Scale to handle multiple newsletters:

  • Add newsletter_source column to Sheet (Mailchimp, Substack, etc.)
  • Create separate ingestion branches for each source
  • Merge results before AI generation
  • Nodes needed: +5 per additional source (HTTP Request, Function, Merge node)
  • Performance: Handles 5+ newsletter sources with <60 second total execution time

Integration possibilities:

Add This To Get This Complexity
Canva API Auto-generate branded post graphics Medium (6 nodes, requires Canva Pro)
Airtable sync Better content calendar visualization Easy (3 nodes, replace Google Sheets)
Slack approval workflow Review posts in Slack instead of Sheet Medium (8 nodes, interactive buttons)
Analytics dashboard Power BI or Google Data Studio integration Hard (12 nodes, requires data warehouse)
A/B testing logic Generate 2 versions per post, track performance Medium (10 nodes, requires statistical analysis)

Get Started Today

Ready to automate your content distribution pipeline?

  1. Download the template: Scroll to the bottom of this article to copy the complete n8n workflow JSON
  2. Import to n8n: Go to Workflows → Import from URL or File, paste the JSON
  3. Configure your services: Add API credentials for OpenAI, Google Sheets, Buffer, and your newsletter platform
  4. Set up your Sheet: Create the content warehouse spreadsheet with the exact column structure from Step 3
  5. Test with one newsletter: Manually trigger the workflow and verify posts appear in your Sheet
  6. Approve and publish: Change one post status to "READY" and confirm it publishes to Buffer
  7. Activate the workflow: Enable both workflows to run on their schedules

Customization support:
This workflow is a starting point. You'll likely need to adjust the OpenAI prompt for your brand voice, modify the posting schedule, or add platform-specific features.

Need help customizing this workflow for your specific content strategy? Schedule an intro call with Atherial at https://atherial.ai/contact—we'll review your newsletter format and social media goals to optimize the automation for your business.

Complete N8N Workflow Template

Copy the JSON below and import it into your N8N instance via Workflows → Import from File

{
  "name": "Real Estate Content Distribution Hub",
  "nodes": [
    {
      "id": "webhook_trigger",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        100,
        100
      ],
      "parameters": {
        "path": "real-estate-newsletter",
        "httpMethod": "POST",
        "responseCode": 200,
        "responseData": "firstEntryJson",
        "responseMode": "onReceived"
      },
      "typeVersion": 2.1
    },
    {
      "id": "extract_newsletter",
      "name": "Extract Newsletter Data",
      "type": "n8n-nodes-base.set",
      "position": [
        300,
        100
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "0",
              "name": "newsletter_title",
              "value": "={{ $json.title }}"
            },
            {
              "id": "1",
              "name": "newsletter_content",
              "value": "={{ $json.content }}"
            },
            {
              "id": "2",
              "name": "newsletter_source",
              "value": "={{ $json.source || 'mailchimp' }}"
            },
            {
              "id": "3",
              "name": "timestamp",
              "value": "={{ new Date().toISOString() }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "generate_ai_posts",
      "name": "Generate AI Social Posts",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "maxTries": 2,
      "position": [
        500,
        100
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini"
        },
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "You are a social media content expert specializing in real estate marketing. Convert newsletter content into platform-specific social media posts. Return ONLY valid JSON with these exact keys: instagram_caption, linkedin_post, x_post, facebook_post. Each post must be optimized for the platform's character limits, tone, and best practices. Include relevant hashtags. Ensure the JSON is valid and parseable."
            },
            {
              "role": "user",
              "content": "=Create platform-specific social media posts from this real estate newsletter:\n\nTitle: {{ $json.newsletter_title }}\n\nContent: {{ $json.newsletter_content }}\n\nReturn ONLY valid JSON with no markdown or additional text."
            }
          ]
        },
        "resource": "text",
        "simplify": false
      },
      "retryOnFail": true,
      "typeVersion": 2,
      "continueOnFail": false,
      "waitBetweenTries": 1
    },
    {
      "id": "parse_ai_response",
      "name": "Parse AI Response",
      "type": "n8n-nodes-base.set",
      "position": [
        700,
        100
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "0",
              "name": "post_data",
              "value": "={{ JSON.parse($json.response.text) }}"
            },
            {
              "id": "1",
              "name": "instagram_caption",
              "value": "={{ $json.post_data.instagram_caption }}"
            },
            {
              "id": "2",
              "name": "linkedin_post",
              "value": "={{ $json.post_data.linkedin_post }}"
            },
            {
              "id": "3",
              "name": "x_post",
              "value": "={{ $json.post_data.x_post }}"
            },
            {
              "id": "4",
              "name": "facebook_post",
              "value": "={{ $json.post_data.facebook_post }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "add_to_approval_sheet",
      "name": "Add to Approval Queue",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        900,
        100
      ],
      "parameters": {
        "columns": {
          "value": {
            "x_post": "={{ $json.x_post }}",
            "timestamp": "={{ $json.timestamp }}",
            "facebook_post": "={{ $json.facebook_post }}",
            "linkedin_post": "={{ $json.linkedin_post }}",
            "scheduled_date": "",
            "approval_status": "pending",
            "newsletter_title": "={{ $json.newsletter_title }}",
            "posted_platforms": "",
            "instagram_caption": "={{ $json.instagram_caption }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp"
            },
            {
              "id": "newsletter_title",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Newsletter Title"
            },
            {
              "id": "instagram_caption",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Instagram Caption"
            },
            {
              "id": "linkedin_post",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "LinkedIn Post"
            },
            {
              "id": "x_post",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "X Post"
            },
            {
              "id": "facebook_post",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Facebook Post"
            },
            {
              "id": "approval_status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Approval Status"
            },
            {
              "id": "scheduled_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Scheduled Date"
            },
            {
              "id": "posted_platforms",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Posted Platforms"
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "approval_queue"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=env.GOOGLE_SHEETS_ID"
        }
      },
      "typeVersion": 4.7,
      "continueOnFail": true
    },
    {
      "id": "check_approvals",
      "name": "Check Approval Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1100,
        100
      ],
      "parameters": {
        "range": "approval_queue!A:I",
        "options": {
          "returnAllMatches": true
        },
        "operation": "read",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "approval_queue"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=env.GOOGLE_SHEETS_ID"
        }
      },
      "typeVersion": 4.7,
      "continueOnFail": true
    },
    {
      "id": "approval_check",
      "name": "Is Approved?",
      "type": "n8n-nodes-base.if",
      "position": [
        1300,
        100
      ],
      "parameters": {
        "conditions": {
          "options": [
            {
              "condition": "equal",
              "leftValue": "={{ $json.approval_status }}",
              "rightValue": "approved"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "schedule_to_buffer",
      "name": "Schedule to Buffer",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        1500,
        50
      ],
      "parameters": {
        "url": "https://api.buffer.com/1/updates/create.json",
        "method": "POST",
        "jsonBody": "={\n  \"profile_ids\": \"{{ $json.selected_profiles || 'multi-platform' }}\",\n  \"text\": \"{{ $json.instagram_caption }}\",\n  \"shorten\": true,\n  \"scheduled_at\": \"{{ $json.scheduled_date || new Date().toISOString() }}\"\n}",
        "sendBody": true,
        "contentType": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth"
      },
      "retryOnFail": true,
      "typeVersion": 4.3,
      "continueOnFail": true,
      "waitBetweenTries": 2
    },
    {
      "id": "post_to_x",
      "name": "Post to X (Twitter)",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        1500,
        150
      ],
      "parameters": {
        "url": "https://api.twitter.com/2/tweets",
        "method": "POST",
        "jsonBody": "={\n  \"text\": \"{{ $json.x_post }}\"\n}",
        "sendBody": true,
        "contentType": "json",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{ $credentials.accessToken }}"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.3,
      "continueOnFail": true,
      "waitBetweenTries": 2
    },
    {
      "id": "post_to_facebook",
      "name": "Post to Facebook",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        1500,
        250
      ],
      "parameters": {
        "url": "=https://graph.facebook.com/v18.0/{{ $json.facebook_page_id || 'me' }}/feed",
        "method": "POST",
        "jsonBody": "={\n  \"message\": \"{{ $json.facebook_post }}\",\n  \"access_token\": \"{{ $credentials.accessToken }}\"\n}",
        "sendBody": true,
        "contentType": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2"
      },
      "retryOnFail": true,
      "typeVersion": 4.3,
      "continueOnFail": true,
      "waitBetweenTries": 2
    },
    {
      "id": "post_to_linkedin",
      "name": "Post to LinkedIn",
      "type": "n8n-nodes-base.httpRequest",
      "maxTries": 2,
      "position": [
        1500,
        350
      ],
      "parameters": {
        "url": "https://api.linkedin.com/v2/ugcPosts",
        "method": "POST",
        "jsonBody": "={\n  \"content\": {\n    \"contentEntities\": [\n      {\n        \"entityLocation\": \"https://www.linkedin.com\"\n      }\n    ],\n    \"title\": \"Real Estate Market Update\"\n  },\n  \"distribution\": {\n    \"feedDistribution\": \"PUBLIC\",\n    \"targetEntities\": [],\n    \"thirdPartyDistributionChannels\": []\n  },\n  \"lifecycleState\": \"PUBLISHED\",\n  \"specific_content\": {\n    \"com.linkedin.ugc.share\": {\n      \"shareCommentary\": {\n        \"text\": \"{{ $json.linkedin_post }}\"\n      }\n    }\n  },\n  \"visibility\": {\n    \"com.linkedin.ugc.share\": {\n      \"visibility\": \"PUBLIC\"\n    }\n  }\n}",
        "sendBody": true,
        "contentType": "json",
        "sendHeaders": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "oAuth2",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer {{ $credentials.accessToken }}"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "retryOnFail": true,
      "typeVersion": 4.3,
      "continueOnFail": true,
      "waitBetweenTries": 2
    },
    {
      "id": "update_posted_status",
      "name": "Update Posted Status",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1700,
        200
      ],
      "parameters": {
        "range": "approval_queue!A:I",
        "columns": {
          "value": {
            "timestamp": "={{ $json.timestamp }}",
            "posted_platforms": "Instagram,LinkedIn,X,Facebook"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Timestamp"
            },
            {
              "id": "posted_platforms",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Posted Platforms"
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "timestamp"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "id",
          "value": "approval_queue"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "=env.GOOGLE_SHEETS_ID"
        }
      },
      "typeVersion": 4.7,
      "continueOnFail": true
    },
    {
      "id": "approval_pending_message",
      "name": "Approval Pending",
      "type": "n8n-nodes-base.set",
      "position": [
        1300,
        250
      ],
      "parameters": {
        "mode": "manual",
        "assignments": {
          "assignments": [
            {
              "id": "0",
              "name": "status",
              "value": "approval_pending"
            },
            {
              "id": "1",
              "name": "message",
              "value": "Content awaiting approval in Google Sheets"
            }
          ]
        },
        "includeOtherFields": false
      },
      "typeVersion": 3.4
    }
  ],
  "connections": {
    "Is Approved?": {
      "main": [
        [
          {
            "node": "Schedule to Buffer",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Approval Pending",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract Newsletter Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to Facebook": {
      "main": [
        [
          {
            "node": "Post to LinkedIn",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to LinkedIn": {
      "main": [
        [
          {
            "node": "Update Posted Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Response": {
      "main": [
        [
          {
            "node": "Add to Approval Queue",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Schedule to Buffer": {
      "main": [
        [
          {
            "node": "Post to X (Twitter)",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post to X (Twitter)": {
      "main": [
        [
          {
            "node": "Post to Facebook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add to Approval Queue": {
      "main": [
        [
          {
            "node": "Check Approval Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Approval Status": {
      "main": [
        [
          {
            "node": "Is Approved?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Newsletter Data": {
      "main": [
        [
          {
            "node": "Generate AI Social Posts",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate AI Social Posts": {
      "main": [
        [
          {
            "node": "Parse AI Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}