Skip to main content
MindStudio
Pricing
Blog About
My Workspace
WorkflowsAutomationIntegrations

How to Use Blotato with Claude Code to Schedule and Publish Social Media Posts

Connect Blotato's API to Claude Code to build a social media automation skill that drafts, reviews, and publishes posts across 9 platforms.

MindStudio Team
How to Use Blotato with Claude Code to Schedule and Publish Social Media Posts

The Real Cost of Managing Social Media Manually

If you’re publishing to multiple social platforms, the actual writing is only half the work. The other half is reformatting content for each platform, logging into different dashboards, and manually scheduling posts one at a time.

Social media automation using Blotato’s API and Claude Code eliminates that overhead. Blotato gives you a single API that covers nine platforms — Twitter/X, LinkedIn, Instagram, Facebook, TikTok, Pinterest, YouTube, Threads, and Bluesky. Claude Code gives you an AI agent that can draft platform-specific content, apply your brand guidelines, and call that API — all from your terminal.

This guide covers the complete setup: how to configure Claude Code for this workflow, how to write a publishing script, how to handle media and scheduling, and how to automate the full loop once it’s running reliably.


What Blotato and Claude Code Each Bring

Blotato’s API

Blotato is a social media management platform built around a clean REST API. Instead of integrating with nine different platform APIs — each with its own OAuth flow, rate limits, and quirks — you authenticate once with Blotato and use a consistent interface across all supported platforms.

Key capabilities through the API:

  • Create and publish posts immediately or schedule them for a future time using a scheduled_at timestamp
  • Upload media files and attach them to posts
  • Fetch connected account IDs for routing posts to the right accounts
  • Retrieve post status and performance data

Claude Code

Claude Code is Anthropic’s terminal-based agentic coding tool. It reads your project files, writes and executes code, and interacts with external systems — including APIs — based on natural language instructions.

For this workflow, Claude Code handles:

  • Reading a topic brief and drafting platform-appropriate post variations
  • Applying formatting rules (character limits, hashtag placement, tone)
  • Running Python scripts to call the Blotato API
  • Displaying drafts for review before taking any action

The important distinction: Claude Code isn’t just generating text. It executes code, reads files, and calls APIs. That makes it a practical automation layer, not just a copywriting tool.


Prerequisites and Setup

Before building this workflow, you need:

  • Claude Code — Available through Anthropic’s developer platform. Requires an Anthropic API key or Claude Pro/Max subscription.
  • A Blotato account — Sign up at blotato.com and generate an API key from your account settings.
  • Connected social accounts — Link each platform inside Blotato’s dashboard. The API uses account IDs that correspond to these linked accounts.
  • Python 3.8+ — Claude Code will execute Python scripts to call the API.
  • A dedicated project directory — Create a folder for this workflow. Everything lives here: your configuration file, scripts, drafts, and logs.

Store your API key as an environment variable. Never put it in a code file:

export BLOTATO_API_KEY="your_api_key_here"

Add this to your .zshrc or .bashrc so it persists across sessions. Alternatively, use a .env file with python-dotenv for project-scoped credential management.


Building the Workflow

Step 1: Configure CLAUDE.md

The CLAUDE.md file gives Claude Code persistent, project-specific instructions. Every time you start a Claude Code session in this directory, it reads this file automatically. This is where your brand voice, platform rules, and workflow logic live.

Create CLAUDE.md in your project folder:

# Social Media Publishing Workflow

## Your Role
You are a social media content assistant. When given a topic or brief:
1. Draft platform-specific posts for the requested platforms
2. Apply the platform guidelines below
3. Display all drafts for review before taking any action
4. Call the Blotato API only after I explicitly approve

## Platform Guidelines

**Twitter/X**: Max 280 characters. Direct and punchy. One or two hashtags max.
**LinkedIn**: 150–300 words. Professional tone. Add 3–5 hashtags at the end.
**Instagram**: Strong hook in first two lines. 5–10 hashtags at end.
**Facebook**: Conversational, 50–100 words. Link previews supplement text.
**TikTok**: Under 150 characters. Hook-first. Trending hashtags.
**Pinterest**: Keyword-rich. 100–200 characters. Outcome-focused.
**YouTube**: Shorts description, 200–300 characters. Include keywords.
**Threads**: Under 500 characters. Casual and conversational.
**Bluesky**: Under 300 characters. Community-aware tone, similar to Twitter.

## API Details
- Base URL: https://api.blotato.com/v1
- Auth: Bearer token via BLOTATO_API_KEY environment variable
- Post endpoint: POST /posts
- Schedule via: scheduled_at field (ISO 8601 format)
- Publishing script: publish.py

## Workflow
1. Draft posts for requested platforms
2. Display a numbered list of all drafts with character counts
3. Wait for my approval ("approve all" or specific edits)
4. After approval, run publish.py for each platform
5. Log all API responses to logs/

## Auto-Publish Rules
- "daily-tip" content type: auto-publish without review
- "announcement" content type: always require review
- "campaign" content type: require review, then schedule as a batch

This configuration does most of the work. Every session starts with consistent platform rules, workflow logic, and API details — without repeating any of it.

Step 2: Create the Publishing Script

Claude Code will use a Python script to make API calls. Create publish.py in your project directory:

import os
import json
import requests
from datetime import datetime

API_KEY = os.environ.get("BLOTATO_API_KEY")
BASE_URL = "https://api.blotato.com/v1"

HEADERS = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

PLATFORM_LIMITS = {
    "twitter": 280,
    "bluesky": 300,
    "threads": 500,
    "tiktok": 150,
    "pinterest": 500,
    "youtube": 5000,
    "linkedin": 3000,
    "instagram": 2200,
    "facebook": 63206,
}

def validate_content(platform: str, content: str) -> bool:
    """Check content against platform character limits."""
    limit = PLATFORM_LIMITS.get(platform, 5000)
    if len(content) > limit:
        print(f"ERROR: {platform} content is {len(content)} chars (limit: {limit})")
        return False
    return True

def upload_media(file_path: str) -> str:
    """Upload a media file and return its media ID."""
    with open(file_path, "rb") as f:
        response = requests.post(
            f"{BASE_URL}/media",
            headers={"Authorization": f"Bearer {API_KEY}"},
            files={"file": f}
        )
    response.raise_for_status()
    return response.json().get("id")

def publish_post(platform: str, content: str, account_id: str,
                 media_ids: list = None, scheduled_at: str = None) -> dict:
    """Publish or schedule a post via Blotato API."""
    if not validate_content(platform, content):
        raise ValueError(f"Content validation failed for {platform}")

    payload = {
        "platform": platform,
        "content": content,
        "account_id": account_id,
    }

    if media_ids:
        payload["media_ids"] = media_ids
    if scheduled_at:
        payload["scheduled_at"] = scheduled_at

    response = requests.post(f"{BASE_URL}/posts", headers=HEADERS, json=payload)
    response.raise_for_status()
    return response.json()

def log_response(response_data: dict, platform: str):
    """Save API response to logs directory."""
    os.makedirs("logs", exist_ok=True)
    date_str = datetime.now().strftime("%Y-%m-%d")
    log_file = f"logs/{date_str}-responses.json"

    existing = []
    if os.path.exists(log_file):
        with open(log_file) as f:
            existing = json.load(f)

    existing.append({
        "platform": platform,
        "timestamp": datetime.now().isoformat(),
        "response": response_data
    })

    with open(log_file, "w") as f:
        json.dump(existing, f, indent=2)

if __name__ == "__main__":
    import sys
    platform = sys.argv[1]
    content = sys.argv[2]
    account_id = sys.argv[3]
    scheduled_at = sys.argv[4] if len(sys.argv) > 4 else None

    result = publish_post(platform, content, account_id, scheduled_at=scheduled_at)
    log_response(result, platform)
    print(json.dumps(result, indent=2))

The validation step is worth noting. Claude Code sometimes generates content slightly over a platform’s character limit. Having validate_content() run before every API call prevents bad requests from reaching Blotato.

Check Blotato’s official API documentation for exact field names and endpoint paths — the structure above follows standard REST conventions, but specific parameter names may vary by API version.

Step 3: Fetch Your Account IDs

Each connected social account in Blotato has a unique ID. You’ll need these to route posts to the right accounts. Run this in your terminal:

import os, requests
key = os.environ.get("BLOTATO_API_KEY")
r = requests.get(
    "https://api.blotato.com/v1/accounts",
    headers={"Authorization": f"Bearer {key}"}
)
for a in r.json():
    print(f"{a['platform']}: {a['id']} ({a.get('username', '')})")

Copy the output and add it to your CLAUDE.md:

## Account IDs
twitter_main: acc_abc123
linkedin_company: acc_def456
instagram_brand: acc_ghi789

Claude Code will reference these labels when building API call payloads.


Running Content Sessions

Your First Drafting Session

Start a Claude Code session in your project directory:

cd your-social-media-workflow
claude

Give Claude Code a brief in plain language:

Draft posts for Twitter, LinkedIn, and Threads about our new feature: 
AI-powered scheduling that learns optimal posting times for each account. 
Show me all drafts before publishing anything.

Claude Code reads your CLAUDE.md guidelines and generates platform-appropriate content. Output looks like:

Draft Review — AI Scheduling Feature

1. Twitter/X (241 chars):
New: our scheduler learns when your audience is most active and auto-times 
posts to match. Zero extra configuration. Available on all plans. 
#ProductUpdate #SocialMedia

2. LinkedIn (183 words):
We've been building this for months, and it's finally here...
[full LinkedIn draft with professional framing and appropriate length]

3. Threads (191 chars):
Your best posting time isn't 9am Monday. It's whenever your specific audience 
is online. Our scheduler now learns that pattern automatically.

Type "approve all" to publish, or tell me what to change.

Reply with “approve all” — Claude Code calls publish.py for each platform, reads the response, and logs everything to your logs directory.

Scheduling Posts in Advance

For campaigns, include scheduling instructions in your brief:

Draft the feature announcement for Instagram and Pinterest. 
Schedule for next Tuesday at 9 AM Eastern. Show drafts before scheduling.

Claude Code will generate content and format the scheduled_at timestamp correctly. Add scheduling defaults to your CLAUDE.md to avoid repeating them each session:

## Scheduling Defaults
- Default timezone: America/New_York
- Morning posts: 9:00 AM
- Campaign cadence: Monday / Wednesday / Friday
- Never schedule more than 30 days out

Handling Images and Video

Media attachment is a two-step process: upload first, then attach to the post. Tell Claude Code which file to use:

Draft and publish the feature announcement to Instagram. 
Use /assets/feature-screenshot.png as the image. LinkedIn gets text only.

Claude Code calls upload_media() to get a media ID, then includes that ID in the Instagram post payload. For LinkedIn (text only in this case), it skips the media step. For video on TikTok or YouTube Shorts, the same pattern applies — upload the video file, get a media ID, attach to the post.


Automating the Full Publishing Loop

Once the manual-review version runs reliably, you can remove the approval step for routine content.

The auto-publish rules in your CLAUDE.md handle this. When you include “daily-tip” as the content type in your brief, Claude Code skips the review step. For announcements, it still pauses for approval.

For fully scheduled automation, use Claude Code’s --print flag with a cron job:

# Publish a daily tip across all platforms at 8 AM
0 8 * * * cd /path/to/workflow && claude --print \
  "Generate and auto-publish today's daily marketing tip across all nine platforms" \
  >> logs/daily-$(date +\%Y-\%m-\%d).log 2>&1

This runs Claude Code non-interactively, passes the instruction directly, and appends output to a dated log file.

For batching an entire campaign at once, ask Claude Code explicitly:

Create a 5-day LinkedIn and Twitter campaign for our product launch, 
Monday through Friday. One post per platform per day at 10 AM Eastern. 
Show the full batch for review before scheduling anything.

Claude Code generates 10 posts, displays the full batch, waits for your approval, then schedules all 10 sequentially after confirmation.


Common Mistakes to Avoid

Posting the same copy on every platform. Identical text across all nine platforms reduces engagement and can trigger spam detection on some networks. Your CLAUDE.md guidelines differentiate by platform, but verify Claude Code is actually writing distinct variations — not just trimming the same paragraph.

Hardcoding credentials. Keep your Blotato API key in environment variables, not in CLAUDE.md or any script file. Files in a project directory can end up in version control. A leaked API key means anyone can post to your accounts.

Skipping log files. Every API response contains a post ID. When you need to delete a misfired post or debug a failure, that ID is how you find it inside Blotato’s system. The logging step in publish.py takes seconds and saves significant debugging time later.

Ignoring validation errors. When validate_content() flags a character limit violation, the fix is to edit the content — not disable the check. A failed request wastes API calls and can trigger rate limiting on platforms sensitive to malformed submissions.

Enabling auto-publish before testing manually. Run the review-first version for at least a week. Verify posts appear correctly on every platform. Then, and only then, turn on auto-publish for low-stakes content types.


How MindStudio Extends This Further

The Claude Code setup above gives one developer direct terminal control over the publishing workflow. But if you want to share it with a marketing team, trigger it from other tools, or avoid managing cron jobs — MindStudio’s Agent Skills Plugin adds that layer cleanly.

The Plugin is an npm SDK (@mindstudio-ai/agent) that lets Claude Code call MindStudio-hosted workflows as simple, typed method calls. You can wrap your entire Blotato publishing logic inside a MindStudio agent — with approval steps, multi-user access, and built-in scheduling — then call it from Claude Code with a single invocation:

const { MindStudio } = require("@mindstudio-ai/agent");

const client = new MindStudio();
await client.workflows.SocialPublisher.publishContent({
  topic: "product launch announcement",
  platforms: ["twitter", "linkedin", "instagram"],
  scheduleFor: "2025-01-15T09:00:00Z"
});

This means a non-technical marketer can trigger the same workflow through a MindStudio UI, while developers still interact with it through Claude Code. Same underlying workflow, two access paths.

MindStudio also handles rate limiting and retry logic — useful when publishing to nine platforms simultaneously and a few requests fail intermittently. If you’re building content automation workflows for a team rather than for personal use, that infrastructure removes a real maintenance burden.

You can try MindStudio free at mindstudio.ai.


Frequently Asked Questions

Does Blotato’s API support all nine platforms equally?

Most core features — creating posts, scheduling, and attaching media — work across all nine platforms. Platform-specific features like Instagram Stories, Pinterest board selection, or YouTube Shorts metadata may require additional parameters. Check Blotato’s official API documentation for platform-specific payload options before building platform-specific logic into your scripts.

Can Claude Code run this workflow automatically without a human in the loop?

Yes. Using Claude Code’s --print flag in a cron job, you can run fully automated publishing without any interactive approval. The trade-off is losing quality control on individual posts. A practical middle ground: auto-publish routine content (daily tips, quotes, scheduled series) and keep the review step for announcements and campaign content. The CLAUDE.md auto-publish rules section handles this distinction.

How do I manage multiple brand accounts on the same platform?

Each connected account in Blotato gets its own unique account ID. If you manage two LinkedIn pages or three Twitter accounts, you’ll have multiple IDs for those platforms. Store them in your CLAUDE.md with clear labels (linkedin_company, linkedin_founder, twitter_support) and reference them by label when giving Claude Code instructions.

What happens if a post fails to publish?

Blotato’s API returns an error response with a status code and message. The publish.py script calls raise_for_status(), so failed requests throw a Python exception. Claude Code surfaces that exception in your session. Common causes include an expired API key, content that violates a platform’s policies, or hitting rate limits after too many rapid requests. The error message usually tells you exactly what failed.

Is this setup secure enough for a team environment?

For individual use, environment variables work fine. For shared or production use, add a proper secrets manager (AWS Secrets Manager, HashiCorp Vault, or equivalent) instead of shell-level environment variables, content validation before any auto-publishing runs, and log monitoring so failed posts don’t go unnoticed. The cron-based approach works well for solo use; team deployments need more infrastructure around credentials and alerting.

Can this same pattern work with other scheduling tools instead of Blotato?

Yes. The CLAUDE.md plus Python script pattern works with any social media scheduling API — Buffer, Hootsuite, Later, or direct platform APIs. You’d replace the Blotato-specific endpoints and payload structure with the target API’s conventions. Blotato’s practical advantage here is abstracting nine platforms behind one API, which keeps both the script and your CLAUDE.md configuration simple.


Key Takeaways

  • Blotato’s API covers nine social platforms with a single authentication flow, making cross-platform automation practical without managing nine separate integrations.
  • The CLAUDE.md file is your control layer — it holds platform guidelines, workflow rules, and account IDs so every Claude Code session behaves consistently.
  • Build the review-first version before automating. Run it manually for at least a week to verify quality, then enable auto-publish for appropriate content types.
  • Validation and logging aren’t optional — check character limits before every API call and log every response with its post ID.
  • MindStudio’s Agent Skills Plugin lets you extend this terminal-based workflow into a team-accessible system without rebuilding the underlying logic.

For teams that want to go further — multi-channel campaigns, analytics-driven scheduling, multi-step approval chains — MindStudio’s no-code agent builder provides the infrastructure to layer those capabilities on top of what you’ve built here.

Presented by MindStudio

No spam. Unsubscribe anytime.