What you’ll build in this tutorial

By the end of this guide, you’ll have a working n8n workflow that:

  1. Pulls draft content from a Google Sheet (or RSS feed, Airtable, Notion — your choice)
  2. Uses Claude or GPT-4 to rewrite each post for 10 different social platforms, tailored to each platform’s tone and character limits
  3. Schedules the posts across LinkedIn, X (Twitter), Instagram, TikTok, YouTube, Facebook, Pinterest, Threads, Bluesky, and Reddit using a single API call
  4. Handles failures gracefully with retry logic and idempotency keys
  5. Sends you a Slack notification when a post publishes successfully — or a different notification when one fails

This isn’t a toy tutorial. The workflow is production-ready, handles real-world edge cases (OAuth token refresh, rate limits, partial platform failures), and ships with a downloadable .json you can import into any n8n instance.

The full working workflow is available at the end of this guide as a free download.

Why n8n + SchedPilot beats the alternatives

Before diving in, let me be direct about why this specific stack. I’ve tested the main approaches for automating multi-platform publishing from n8n. Here’s what actually works and what doesn’t.

Approach 1: Native platform integrations in n8n

n8n ships with integrations for X, LinkedIn, and a few others. For single-platform publishing to one account, these work. For anything more complex — multi-platform, multi-account, or Instagram/TikTok (where n8n’s native nodes are limited or missing) — you hit walls fast.

The bigger problem: you need separate developer app registrations for Meta (Instagram + Facebook), LinkedIn, X, Pinterest, TikTok, and so on. Each has its own review process. Some take weeks. Some require actual verifiable business documents. This stops being a weekend project and becomes a months-long bureaucracy exercise.

Approach 2: Direct HTTP calls to each platform’s API

Technically possible, practically awful. Every platform has its own OAuth flow, rate limit rules, media upload requirements, and error shapes. Your n8n workflow balloons to 40+ nodes and becomes fragile the moment any platform pushes an API change.

Approach 3: A unified API (the working approach)

A unified social media API abstracts all 10 platforms behind one REST endpoint. You get OAuth handled once, rate limits managed server-side, and consistent JSON shapes. Your n8n workflow stays clean — usually 4-8 nodes total, regardless of how many platforms you publish to.

This tutorial uses SchedPilot’s API as the unified layer. SchedPilot supports 10 platforms, includes AI content features, and costs a flat $5/month (compared to Ayrshare at $49/month or per-user enterprise pricing elsewhere). The same pattern works with Ayrshare or Blotato if you prefer those — swap the API endpoint and auth header.


Prerequisites

To follow this tutorial, you’ll need:

  • An n8n instance (cloud or self-hosted). The free n8n cloud trial includes 1,000 workflow executions, which is plenty to complete this tutorial.
  • A SchedPilot account with at least 2-3 social accounts connected. The free 7-day trial is enough — you don’t need to commit to a paid plan to follow the tutorial.
  • A Google Sheet with a few draft posts. I’ll provide a template.
  • An Anthropic or OpenAI API key for the AI content generation step. Anthropic’s Claude models work slightly better for tone-matching across platforms, but either works. Budget $2-5 of API credits to follow this tutorial end-to-end.
  • Optional: a Slack workspace with a webhook URL for notifications. Not required.

Total setup time: 30-45 minutes the first time, including connecting accounts. Once set up, the workflow runs autonomously.


Part 1: Setting up SchedPilot for API access

This is the one-time setup. After this, you won’t touch it again.

Step 1: Connect your social accounts

Sign in to your SchedPilot dashboard. Go to Settings → Social Accounts and connect the platforms you want to automate. For each platform, you’ll authorize SchedPilot via the platform’s OAuth flow — the same way you’d connect to Buffer or Hootsuite.

This is the step you only do once. Every subsequent API call from n8n will use SchedPilot’s stored tokens, so your n8n workflow never has to handle OAuth directly.

Step 2: Generate your API key

Navigate to Settings → API & Developers and click Generate API Key. Copy the key immediately — it won’t be shown again. Store it somewhere secure; we’ll add it to n8n as a credential in the next step.

A note on security: treat this key like a password. It has full publishing permissions across all your connected accounts. If you’re building this for a team, use the team’s main SchedPilot account — don’t share individual API keys.

Step 3: Test the API with a quick curl

Before building the n8n workflow, verify the API key works. From your terminal:

curl -X GET https://api.schedpilot.com/v1/accounts \
  -H "Authorization: Bearer YOUR_API_KEY"

You should see a JSON response listing your connected social accounts. If you get a 401, double-check the API key. If you get a 200 with an empty list, go back to Step 1 and connect at least one social account.

Part 2: Setting up the Google Sheet as the content source

This tutorial uses a Google Sheet as the simplest possible content source. In production, many teams use Airtable, Notion, or an RSS feed instead. The workflow pattern is identical — swap the first n8n node and everything downstream still works.

Step 4: Create the content sheet

Create a Google Sheet with these columns:

Column Purpose Example
id Unique identifier for idempotency post-2026-05-01-launch
topic The core idea to post about Launched new AI workflow feature
platforms Comma-separated platforms linkedin,x,bluesky
schedule_at ISO 8601 timestamp 2026-05-01T14:00:00Z
status Tracking column pending
post_id Filled in by the workflow (blank)

The id column is critical for idempotency. If your workflow runs twice accidentally, the same id prevents duplicate posts. I’ll explain this more when we build the SchedPilot node.

Add 2-3 test rows with status pending. Keep the topics short (one sentence each) — the AI will expand them into platform-specific posts.

Step 5: Prepare the Google Sheets credential in n8n

In n8n, go to Credentials → Add Credential → Google Sheets OAuth2 API. Follow n8n’s standard Google OAuth setup flow. If you’re self-hosting n8n, this involves creating a Google Cloud project and OAuth credentials — n8n’s docs walk through this.

Give the credential a clear name like Google Sheets (schedpilot-automation) so you can find it later.


Part 3: Building the n8n workflow

Now the fun part. We’ll build the workflow node by node. At the end, I’ll share the complete JSON export so you can import the whole thing if you’d rather skip manual building.

Workflow architecture

Here’s the architecture we’re building:

Schedule Trigger (daily at 9am)
  ↓
Google Sheets (read pending rows)
  ↓
Loop Over Items (process each row)
  ↓
Claude / GPT-4 (generate platform-specific content)
  ↓
Code Node (format payload for SchedPilot)
  ↓
HTTP Request (POST to SchedPilot /v1/posts)
  ↓
IF Node (branch on success/failure)
  ↓ ↓
  Google Sheets (update status)
  Slack (notify)

Nine nodes total. The complexity scales with your needs — you can add AI review steps, image generation, A/B testing branches, and more once the base workflow runs.

Node 1: Schedule Trigger

Add a Schedule Trigger node. Set the schedule to match when you want the workflow to run. For a daily content pipeline, cron expression 0 9 * * * runs it every day at 9am.

For testing, use the Manual Trigger node instead — you can swap it for the schedule trigger once everything works.

Node 2: Google Sheets — Get Rows

Add a Google Sheets node. Configure it with:

  • Operation: Lookup
  • Credential: the Google Sheets credential from Step 5
  • Document: select your content sheet
  • Sheet: the tab name (usually Sheet1)
  • Lookup column: status
  • Lookup value: pending
  • Return all matches: enable this

This returns every row where status = pending. If you have 5 pending posts, the next nodes will process each one separately.

Node 3: Split In Batches

Add a Split In Batches node with batch size 1. This ensures the workflow processes one post at a time — important because if one post fails, the others still run.

Node 4: AI Content Generation (Anthropic / OpenAI)

This is where the magic happens. Add an Anthropic node (for Claude) or an OpenAI node (for GPT-4). Both work — I’ll show the Claude version because I’ve found it handles platform-specific tone better, but substitute either.

Anthropic node configuration:

  • Operation: Message
  • Model: claude-opus-4-7 (or any Claude model available to your account)
  • Max tokens: 1500
  • System prompt: (see below — this is the important part)
  • User prompt: reference the topic from the Google Sheet via {{ $json.topic }}

The system prompt (this is the content engine):

You are a social media content specialist. Given a single topic or idea, write tailored versions of the content for each of these platforms. Output valid JSON only, no markdown, no explanations.

For each platform, match the tone and constraints:

- linkedin: professional, 1200-2200 chars, 2-3 paragraphs, end with a question to drive comments
- x: punchy, under 280 chars, 1-2 short lines, use line breaks for emphasis
- bluesky: conversational but not casual, under 300 chars
- instagram: engaging first line as the hook, 2-3 paragraphs, 5-8 relevant hashtags at the end
- threads: conversational, 400-500 chars, casual tone
- facebook: friendly, 2 paragraphs, no hashtags
- reddit: informational, no self-promotion, value-first
- pinterest: SEO-optimized, keyword-rich, 200-300 chars

Return JSON in this exact shape:
{
  "linkedin": "...",
  "x": "...",
  "bluesky": "...",
  "instagram": "...",
  "threads": "...",
  "facebook": "...",
  "reddit": "...",
  "pinterest": "..."
}

Only include platforms explicitly requested. Never invent hashtags for LinkedIn or Facebook.

Your user prompt just passes the topic:

Topic: {{ $json.topic }}
Platforms requested: {{ $json.platforms }}

Generate platform-optimized posts.

The expression {{ $json.topic }} pulls the topic from the Google Sheet row. The expression {{ $json.platforms }} pulls the comma-separated platforms list.

Cost note: each call to Claude costs roughly $0.01-0.03 depending on response length. A workflow processing 10 posts/day costs you around $3-10/month in LLM costs. Negligible for most use cases.

Node 5: Code Node — Format for SchedPilot

The AI returns a JSON object with platform-specific content. SchedPilot expects a specific payload shape. A short Code node bridges these:

// n8n Code node — JavaScript
const aiResponse = $input.first().json.content[0].text;
const platformContent = JSON.parse(aiResponse);

const sheetRow = $('Split In Batches').item.json;
const requestedPlatforms = sheetRow.platforms.split(',').map(p => p.trim());

// Build platform-specific content array
const posts = requestedPlatforms
  .filter(p => platformContent[p])
  .map(platform => ({
    platform: platform,
    content: platformContent[platform]
  }));

return [{
  json: {
    id: sheetRow.id,
    schedule_at: sheetRow.schedule_at,
    posts: posts
  }
}];

This node converts the AI’s output into the exact shape SchedPilot’s API wants. If you’re using OpenAI instead of Anthropic, replace the first line with const aiResponse = $input.first().json.message.content; — OpenAI’s response structure is slightly different.

Node 6: HTTP Request — POST to SchedPilot

The core publishing step. Add an HTTP Request node:

  • Method: POST
  • URL: https://api.schedpilot.com/v1/posts
  • Authentication: Generic Credential Type → Header Auth
  • Header name: Authorization
  • Header value: Bearer YOUR_SCHEDPILOT_API_KEY (or better — add as an n8n credential)
  • Content type: JSON
  • Body: (expression mode) {{ JSON.stringify($json) }}

Critical: enable idempotency. Under Header Parameters, add:

  • Name: Idempotency-Key
  • Value: {{ $json.id }}

This ensures that if the workflow accidentally runs twice on the same row (n8n error, retry, etc.), SchedPilot recognizes the duplicate and doesn’t create a second post. The id from the Google Sheet row becomes the idempotency key.

Node 7: IF Node — Branch on success/failure

Add an IF node to check whether the API call succeeded:

  • Condition: {{ $json.status }} equals scheduled

The status field in SchedPilot’s response tells you whether the post was accepted. If it’s scheduled, the post is queued. If it’s failed, you need to retry or alert.

The IF node creates two output branches — success and failure. Wire each to a different follow-up node.

Node 8a: Google Sheets — Update status on success

On the success branch, add another Google Sheets node:

  • Operation: Update
  • Lookup column: id
  • Lookup value: {{ $json.id }}
  • Columns to update:
    • status → published
    • post_id → {{ $json.id }} (from SchedPilot’s response)

This closes the loop — the Google Sheet now tracks which posts have been processed.

Node 8b: Google Sheets — Mark as failed on error

On the failure branch, add another Google Sheets node:

  • Operation: Update
  • Lookup column: id
  • Lookup value: {{ $json.id }}
  • Columns to update:
    • status → failed
    • error → {{ JSON.stringify($json) }}

Now you have a clear audit trail of which posts failed and why.

Node 9: Slack Notifications (optional)

Add a Slack node on each branch (or use Discord, Telegram, email — whatever your team uses). On success: "Post {{ $json.id }} scheduled across {{ $json.posts.length }} platforms". On failure: "Post {{ $json.id }} failed: {{ $json.error }}".


Part 4: Testing the workflow

Before turning on the schedule trigger, run it manually:

  1. Click Execute Workflow in n8n
  2. Watch each node light up green as it runs
  3. Check your Google Sheet — the status column should update from pending to published
  4. Check your SchedPilot dashboard → Calendar — the scheduled posts should appear for the schedule_at times
  5. Check your Slack — you should get a success notification

Common errors and how to fix them:

  • 401 Unauthorized from SchedPilot → API key is wrong or missing Bearer prefix in the header
  • Empty AI response → LLM returned markdown instead of JSON. Add "Return ONLY valid JSON" to your system prompt
  • “Platform not connected” error → You haven’t connected that platform in SchedPilot’s dashboard yet
  • Timeout on HTTP Request node → SchedPilot’s media upload takes a few seconds for large files. Increase the HTTP timeout to 60 seconds if you’re publishing video
  • Same post appears twice in SchedPilot → Idempotency-Key header isn’t being sent. Double-check the header is set on the HTTP Request node

Part 5: Production hardening (don’t skip this)

The workflow we just built works. But “works on my laptop” isn’t the same as “runs reliably every day for 6 months.” Here’s what turns a hobby workflow into a production one.

Error handling

Wrap the HTTP Request node with an Error Trigger node. Currently, if SchedPilot’s API returns a 500 for any reason, n8n marks the workflow as failed and stops. The Error Trigger catches this and lets you retry or alert instead.

HTTP Request (main path)
  ↓ (on error)
Error Trigger
  ↓
Wait 60 seconds
  ↓
HTTP Request (retry, same idempotency key)
  ↓ (on error again)
Slack alert: "Manual intervention needed"

The idempotency key is what makes the retry safe. SchedPilot recognizes the duplicate and returns the original post ID without creating a second one.

Rate limit handling

SchedPilot returns X-RateLimit-Remaining and X-RateLimit-Reset headers on every response. If you’re processing bulk content (say, 100 posts from an RSS feed), add logic to check these headers and pause before continuing.

Add a Code node after the HTTP Request:

const remaining = parseInt($json.headers['x-ratelimit-remaining']);
const resetTime = parseInt($json.headers['x-ratelimit-reset']);

if (remaining < 10) {
  const waitMs = (resetTime * 1000) - Date.now() + 5000;
  await new Promise(resolve => setTimeout(resolve, waitMs));
}

return $input.all();

This pauses the workflow if you’re within 10 requests of your rate limit, preventing the kind of 429 errors that silently break production workflows.

Content review gates

For higher-stakes content (brand posts, client accounts, regulated industries), add a human-in-the-loop step. SchedPilot’s API supports a draft status — the post is saved but not published until a human approves it.

Change the HTTP Request body to include "status": "draft". Then add a follow-up Slack message with a link: "Review and approve: https://app.schedpilot.com/posts/{{ $json.id }}". A human reviews, approves in the dashboard, and publishing happens automatically.

This is the pattern most agencies use — AI drafts, human approves. It catches 95% of the AI mistakes that would otherwise publish to a client’s account.

Logging

Connect the workflow to your observability stack. At minimum, log every publish attempt to a dedicated logs channel. I use a second Slack channel for this (read-only for most of the team), with a message format like:

[2026-04-23 09:00] post-2026-05-01-launch · linkedin+x+bluesky · SUCCESS
[2026-04-23 09:01] post-2026-05-01-launch-v2 · instagram · FAILED (rate limit)

When something goes wrong — and something will go wrong eventually — these logs are how you figure out what happened.


Part 6: Scaling the workflow

Once the basic version works, you’ll probably want to extend it. Here are the most common extensions, in order of usefulness:

1. RSS feed as the source — replace the Google Sheets trigger with an RSS Feed Read node. Your workflow auto-publishes social posts whenever your blog updates.

2. Image generation — add a DALL-E or Stable Diffusion node before the SchedPilot call to generate platform-specific images. Upload the image via SchedPilot’s /v1/media endpoint, then reference the media_id in your post.

3. A/B testing — generate two variants of each post with the LLM, schedule both at different times, and measure engagement via SchedPilot’s webhook callbacks (post.engaged event).

4. Multi-client agency workflow — use Google Sheets tabs per client, and route posts to the correct SchedPilot workspace via the workspace_id parameter. This is how agencies run SchedPilot across 20+ brand accounts from a single n8n instance.

5. Content approval via Slack — use Slack’s interactive buttons to approve/reject AI-drafted posts directly from the notification message. When someone clicks “Approve,” a webhook triggers the actual SchedPilot publish.

Each extension is a separate tutorial — let me know in the comments which ones you’d want me to cover next.


Frequently asked questions

Can I use Make.com or Zapier instead of n8n?

Yes. The same workflow pattern works in Make.com (substitute Make’s HTTP module for n8n’s HTTP Request node) and Zapier (use Zapier’s Webhooks integration). n8n is the focus of this tutorial because it’s the most flexible for this use case and supports self-hosting, which matters for teams with data privacy requirements.

That said, n8n’s free tier is more generous than Zapier’s for this kind of workflow, and Make.com’s pricing scales better than Zapier’s as you add steps.

What’s the difference between SchedPilot’s API and Ayrshare or Postiz?

Ayrshare has more platform coverage (13+ versus SchedPilot’s 10) but starts at $49/month for developer access versus SchedPilot’s $5/month flat. Postiz is open-source and free to self-host, which is great if you have engineering time to maintain the infrastructure; if you want a managed service, it’s paid.

For this n8n tutorial, the workflow structure is identical across all three — you’d swap the API endpoint and authentication method and everything else stays the same.

Do I need to know JavaScript to follow this tutorial?

Only for the Code node (Part 3, Step 5) and the rate limit handler (Part 5). Both snippets are copy-paste ready, and you can skip the rate limit handling for smaller workloads.

If JavaScript is a blocker, the rest of the workflow is pure visual n8n. You can build 80% of this tutorial without writing a single line of code.

How much does it cost to run this workflow continuously?

Roughly $8-15/month for moderate use (10-20 posts/day):

  • SchedPilot Starter: $5/month flat
  • n8n Cloud Starter: $0 (free tier covers up to 1,000 executions/month) or $24/month on paid tier
  • Claude API: $3-10/month for 10-20 posts/day (very rough estimate — varies with content length)
  • Google Sheets: Free

For comparison, running the equivalent workflow with Ayrshare + n8n Cloud + Claude runs closer to $75-90/month because Ayrshare alone starts at $49/month for API access.

Can this workflow handle video posts?

Yes. SchedPilot’s /v1/media endpoint accepts video uploads for X, LinkedIn, Instagram, Facebook, TikTok, YouTube, Pinterest, and Threads. The workflow pattern is: upload video → get media_id → include media_id in the post payload. The same idempotency and error handling patterns apply.

Video handling is outside the scope of this tutorial because it adds 3-4 extra nodes. I’ll cover it in a follow-up.

Will this work on self-hosted n8n?

Yes, entirely. The only external dependencies are SchedPilot’s API, Anthropic’s (or OpenAI’s) API, and Google Sheets — all accessible via standard HTTP from any n8n instance. Self-hosted n8n is actually the better choice for production agency workflows because you can scale execution capacity without per-execution pricing.

The workflow JSON I provide works on n8n Cloud and self-hosted equally.

What platforms does SchedPilot support via this API?

As of April 2026: X (Twitter), LinkedIn, Instagram, Facebook, TikTok, YouTube, Pinterest, Threads, Bluesky, and Reddit. The capability matrix (text, image, video, carousel support per platform) is documented on the SchedPilot API page. New platforms are added based on user request and SchedPilot’s API changelog.


Download the complete workflow

The full workflow JSON is available for free download:

Download the n8n workflow template → (link placeholder — add actual download URL after uploading the .json file)

To import:

  1. In n8n, go to Workflows → Import from File
  2. Select the downloaded .json
  3. Update the three credentials (Google Sheets, Anthropic/OpenAI, SchedPilot) to use your own keys
  4. Run the test

If you run into issues, the most common problem is the Google Sheet column names not matching exactly. The template assumes the columns I specified above (idtopicplatformsschedule_atstatuspost_id). If you use different column names, update the expressions in the Code node.


What to build next

Once this workflow is running, the obvious next projects are:

  1. Build an autonomous AI agent that generates posts from scratch — instead of reacting to content you put in Google Sheets, build an agent that monitors trends and decides what to post.
  2. Compare n8n vs. Zapier for social media automation — if you’re evaluating workflow tools, this comparison goes deep on the tradeoffs.
  3. How to handle media uploads in SchedPilot’s API — video and multi-image carousel posts.

Final thoughts

The pattern in this tutorial — n8n for workflow orchestration, an LLM for content generation, a unified API for platform publishing — is what most agencies and SaaS teams converge on after trying the direct-integration approach and burning two weeks on Meta’s developer app approval process.

The total cost ($10-15/month) and setup time (30-45 minutes) make this accessible to solo creators, small agencies, and indie developers. The workflow pattern scales from 10 posts/day to 10,000 — the same JSON you imported from the template handles both with minor config tweaks.

If you build something cool on top of this, tag @schedpilot on X — I genuinely love seeing what people ship with this stack.


Get started with SchedPilot’s API — free 7-day trial, no credit card required, 10 platforms included. See the full API documentation or the AI agent integration page for advanced use cases.