ContentStudio's CLI

The ContentStudio CLI is a command-line tool that lets you control your entire ContentStudio workspace from the terminal. Instead of opening the dashboard, you can schedule posts, upload media, manage approvals, respond to comments, and audit your connected accounts โ€” all through simple commands. It connects directly to the same API your dashboard uses, so every action is reflected in real time. Whether you're running bash scripts, building CI/CD pipelines, or wiring up an AI agent, the CLI gives you full programmatic access to your ContentStudio workflow.


1. Installation

Install the CLI globally using npm or pnpm โ€” whichever you already use.

1
Install the package globally from npm:
npm install -g contentstudio-cli
# or if you prefer pnpm
pnpm install -g contentstudio-cli
2
Verify the installation worked:
contentstudio --version
contentstudio --help
๐Ÿค– Using an AI assistant?
If you use Claude Code, Cursor, Codex, or similar โ€” install the skill file so your agent knows how to use this CLI automatically:
npx skills add d4interactive/contentstudio-agent
Pick which agents to install into when prompted. After that, your agent will use the CLI without any extra prompting.

2. Authentication

Before running any commands, you need to authenticate with your ContentStudio API key.

Persist your key (recommended for local use)

1
Go to your ContentStudio dashboard โ†’ Settings โ†’ API Keys โ†’ Generate new key. Copy the key โ€” it starts with cs_.
2
Log in via the CLI:
contentstudio auth:login --api-key cs_xxxxxxxxxxxxxxxx
This saves your key locally and verifies it immediately. You only need to do this once.
3
Check your auth status anytime:
contentstudio auth:status         # shows stored config (key is redacted)
contentstudio --json auth:whoami  # validates key against the API

3. Selecting a Workspace

Most commands are scoped to a workspace. Set your active workspace once and the CLI remembers it for all future commands.

1
List all workspaces on your account:
contentstudio --json workspaces:list
Returns workspace IDs, names, slugs, and timezones.
2
Set the one you want as active:
contentstudio workspaces:use <workspace_id>
3
Check which workspace is currently active:
contentstudio workspaces:current

Need to switch workspace for just one command? Use the --workspace flag inline โ€” it won't change your saved default:

contentstudio --workspace <other_workspace_id> accounts:list

4. Exploring Your Workspace

Before creating posts, you'll want to know which accounts, campaigns, labels, and team members are available in your workspace.

Connected social accounts

contentstudio --json accounts:list                       # all accounts
contentstudio --json accounts:list --platform facebook   # filter by platform
contentstudio --json accounts:list --search "barcelona"  # search by name

Valid --platform values: facebook, linkedin, twitter, instagram, youtube, tiktok, pinterest, gmb.

Campaigns, labels, categories, team members

contentstudio --json campaigns:list    # folders / campaigns
contentstudio --json categories:list   # content categories
contentstudio --json labels:list       # labels
contentstudio --json team:list         # team members

All of these support --page, --per-page, and --search filters.


5. Connecting Social Accounts

There are three ways to connect new accounts, depending on the platform.

OAuth platforms (Facebook, LinkedIn, Twitter, Instagram, YouTube, TikTok, Pinterest, GMB, Threads, Tumblr)

1
Run the connect command for your platform:
contentstudio --json accounts:connect facebook
This returns a one-time authorization_url.
2
Open that URL in your browser and complete the authorization flow.

To reconnect an account that has expired or gone invalid:

contentstudio --json accounts:connect facebook --reconnect --account-id <existing_account_id>

Available platform values: facebook, facebook-profile, instagram, instagram-via-facebook, twitter, linkedin, pinterest, tiktok, youtube, threads, gmb, tumblr.

Bluesky (no browser needed)

1
Generate an app password in Bluesky at bsky.app โ†’ Settings โ†’ App Passwords.
2
Connect using your handle and app password:
contentstudio --json accounts:add-bluesky \
  --handle yourname.bsky.social \
  --app-password xxxx-xxxx-xxxx-xxxx
๐Ÿ”” Bluesky โ€” important
  • Use an app password, not your main password. Never pass your actual Bluesky account password here. App passwords can be revoked at any time from your settings.
  • The CLI redacts the app password in --dry-run output, but it is sent to ContentStudio's API over HTTPS during a live run.

Facebook Groups (manual)

contentstudio --json accounts:add-facebook-group \
  --name "My Community Group" \
  --image https://example.com/group-cover.jpg   # image URL is optional

All three connect methods support --dry-run to preview the payload without calling the API.


6. Creating Posts

There are two ways to create a post โ€” shortcut flags for simple cases, or a full JSON body for platform-specific options.

Shortcut flags (simple posts)

# Scheduled post to a Facebook page with one image
contentstudio posts:create \
  -c "Our latest blog post is live!" \
  -i <account_id> \
  -t scheduled \
  -s "2026-05-01 10:00:00" \
  -m https://example.com/hero.jpg
Flag What it does
-c, --content The post text / caption
-i, --account Social account ID. Repeat for multi-account posts.
-t, --publish-type scheduled | draft | queued | content_category
-s, --scheduled-at Schedule time in YYYY-MM-DD HH:MM:SS format
-m, --image-url External image URL. Repeatable for multiple images.
--video-url External video URL
--media-id ID of an asset already in your media library. Repeatable.
--post-type feed | reel | story | feed+reel | feed+story | carousel | video | shorts
--dry-run Print the payload and exit โ€” no API call made

Posting to multiple accounts at once

Repeat the -i flag for each account:

contentstudio posts:create \
  -c "Cross-platform announcement ๐Ÿš€" \
  -i <facebook_id> \
  -i <linkedin_id> \
  -i <twitter_id> \
  -t scheduled \
  -s "2026-05-01 09:00:00"

Using media from your library

# Find a media ID
contentstudio --json media:list --type images

# Reference it by ID in your post
contentstudio posts:create \
  -c "Post with library asset" \
  -i <account_id> \
  -t draft \
  --media-id <media_library_id>

Full body via JSON file (for advanced / platform-specific options)

For TikTok privacy settings, YouTube categories, GMB topic types, approval workflows, first comments, labels, and campaigns โ€” write a JSON body file and pass it with --body:

contentstudio --json posts:create --body /tmp/post.json

Full JSON schema:

{
  "content": {
    "text": "Hello world",
    "media": {
      "images": ["https://example.com/img.jpg"],
      "video": "https://example.com/clip.mp4",
      "media_ids": ["<media_library_id>"]
    }
  },
  "accounts": ["<account_id>"],
  "post_type": "reel+story",
  "post_video_title": "My Video Title",
  "scheduling": {
    "publish_type": "scheduled",
    "scheduled_at": "2026-05-01 10:00:00"
  },
  "first_comment": {
    "message": "๐Ÿ”— link in bio",
    "accounts": ["<account_id>"]
  },
  "labels": ["<label_id>"],
  "campaign_id": "<campaign_id>",
  "approval": {
    "approvers": ["<user_id>"],
    "approve_option": "anyone",
    "notes": "please review"
  },
  "youtube_options":   { "title": "...", "privacy_status": "public", "category": "EDUCATION", "tags": ["tag1"], "license": "youtube", "made_for_kids": false },
  "tiktok_options":    { "privacy_level": "PUBLIC_TO_EVERYONE", "disable_comment": false, "disable_duet": false, "disable_stitch": false, "auto_add_music": false },
  "pinterest_options": { "title": "...", "link": "https://..." },
  "gmb_options":       { "topic_type": "EVENT", "start_date": "2026-05-01", "end_date": "2026-05-02", "title": "...", "action_type": "BOOK", "cta_link": "https://..." }
}
โœ… Always preview before publishing
Every mutating command supports --dry-run โ€” it prints the full request body and exits without touching the API. Use it before creating, deleting, or approving anything for the first time:
contentstudio --json posts:create --dry-run \
  -c "Test" -i <account_id> -t scheduled -s "2026-05-01 10:00"

7. Platform-Specific Examples

Facebook

contentstudio --json posts:create \
  -c "Big news for our community ๐ŸŽ‰" \
  -i <facebook_page_id> \
  -t scheduled \
  -s "2026-05-01 10:00:00" \
  -m https://example.com/announcement.jpg

# Facebook Reels or Stories โ€” add --post-type
contentstudio posts:create \
  -c "Behind-the-scenes" \
  -i <facebook_id> \
  -t scheduled \
  -s "2026-05-01 10:00:00" \
  --video-url https://example.com/clip.mp4 \
  --post-type reel+story

LinkedIn

contentstudio --json posts:create \
  -c "Excited to share our Q2 roadmap" \
  -i <linkedin_id> \
  -t scheduled \
  -s "2026-05-01 09:00:00" \
  -m https://example.com/roadmap.png

Twitter / X

contentstudio --json posts:create \
  -c "New release shipped ๐Ÿš€" \
  -i <twitter_id> \
  -t scheduled \
  -s "2026-05-01 10:00:00" \
  -m https://example.com/preview.png

Instagram (feed, reel, story)

# Feed post
contentstudio posts:create \
  -c "Caption with #hashtags" \
  -i <instagram_id> \
  -t scheduled -s "2026-05-01 10:00:00" \
  -m https://example.com/photo.jpg \
  --post-type feed

# Reel
contentstudio posts:create \
  -c "" \
  -i <instagram_id> \
  -t scheduled -s "2026-05-01 10:00:00" \
  --video-url https://example.com/reel.mp4 \
  --post-type reel

# Story
contentstudio posts:create \
  -c "" \
  -i <instagram_id> \
  -t scheduled -s "2026-05-01 10:00:00" \
  -m https://example.com/story.jpg \
  --post-type story

YouTube (Videos & Shorts)

YouTube requires youtube_options โ€” use a JSON body file:

cat > /tmp/yt-post.json <<'JSON'
{
  "content": {
    "text": "Description shown under the video",
    "media": {"video": "https://example.com/clip.mp4"}
  },
  "accounts": ["<youtube_id>"],
  "post_type": "shorts",
  "post_video_title": "How we built ContentStudio CLI",
  "scheduling": {"publish_type": "scheduled", "scheduled_at": "2026-05-01 10:00:00"},
  "youtube_options": {
    "title": "How we built ContentStudio CLI",
    "privacy_status": "public",
    "category": "EDUCATION",
    "tags": ["cli", "automation", "social-media"],
    "license": "youtube",
    "made_for_kids": false
  }
}
JSON
contentstudio --json posts:create --body /tmp/yt-post.json

TikTok

cat > /tmp/tt-post.json <<'JSON'
{
  "content": {
    "text": "Quick demo #fyp #tutorial",
    "media": {"video": "https://example.com/tiktok.mp4"}
  },
  "accounts": ["<tiktok_id>"],
  "scheduling": {"publish_type": "scheduled", "scheduled_at": "2026-05-01 10:00:00"},
  "tiktok_options": {
    "privacy_level": "PUBLIC_TO_EVERYONE",
    "disable_comment": false,
    "disable_duet": false,
    "disable_stitch": false,
    "auto_add_music": false,
    "brand_content_toggle": false,
    "disclose_commercial_content": false,
    "is_aigc": false
  }
}
JSON
contentstudio --json posts:create --body /tmp/tt-post.json

Pinterest

cat > /tmp/pin-post.json <<'JSON'
{
  "content": {
    "text": "Check out our spring guide",
    "media": {"images": ["https://example.com/pin.jpg"]}
  },
  "accounts": ["<pinterest_id>"],
  "scheduling": {"publish_type": "scheduled", "scheduled_at": "2026-05-01 10:00:00"},
  "pinterest_options": {
    "title": "Spring 2026 Style Guide",
    "link": "https://example.com/spring-guide"
  }
}
JSON
contentstudio --json posts:create --body /tmp/pin-post.json

Google Business Profile

cat > /tmp/gmb-post.json <<'JSON'
{
  "content": {
    "text": "Join our grand opening event",
    "media": {"images": ["https://example.com/event.jpg"]}
  },
  "accounts": ["<gmb_account_id>"],
  "scheduling": {"publish_type": "scheduled", "scheduled_at": "2026-05-01 10:00:00"},
  "gmb_options": {
    "topic_type": "EVENT",
    "start_date": "2026-05-15",
    "end_date": "2026-05-16",
    "title": "Grand Opening",
    "action_type": "BOOK",
    "cta_link": "https://example.com/rsvp"
  }
}
JSON
contentstudio --json posts:create --body /tmp/gmb-post.json

8. Managing Posts

Listing posts

contentstudio --json posts:list                                           # all recent
contentstudio --json posts:list --status draft --per-page 5
contentstudio --json posts:list --status scheduled --status published
contentstudio --json posts:list --date-from 2026-04-01 --date-to 2026-04-30

Deleting a post

# Delete from ContentStudio only
contentstudio --json posts:delete <post_id>

# Also delete from the connected social platforms
contentstudio --json posts:delete <post_id> --delete-from-social

# Limit cross-platform delete to a specific account
contentstudio --json posts:delete <post_id> --account <account_id> --delete-from-social

# Preview without deleting
contentstudio --json posts:delete <post_id> --dry-run

Approving or rejecting posts

contentstudio --json posts:approve <post_id> --comment "LGTM, ship it"
contentstudio --json posts:reject  <post_id> --comment "fix the link first"

# Preview without acting
contentstudio --json posts:approve <post_id> --dry-run

9. Comments & Internal Notes

# List all comments and notes on a post
contentstudio --json comments:list <post_id>

# Add a public comment
contentstudio --json comments:add <post_id> "Great work team!"

# Add an internal note (not visible publicly)
contentstudio --json comments:add <post_id> "Double-check the link before publishing" --note

# Mention team members
contentstudio --json comments:add <post_id> "Heads up" --mention <user_id> --mention <user_id>

# Preview without posting
contentstudio --json comments:add <post_id> "test" --note --dry-run

10. Media Library

Listing assets

contentstudio --json media:list                                           # all assets
contentstudio --json media:list --type images --sort recent --per-page 20
contentstudio --json media:list --type videos
contentstudio --json media:list --search "campaign-2026"

Valid --sort values: recent, oldest, size, a2z, z2a.

Uploading assets

# Upload a local file
contentstudio --json media:upload --file ./hero.jpg

# Import from an external URL
contentstudio --json media:upload --url https://example.com/asset.mp4

# Optionally put it in a specific folder
contentstudio --json media:upload --file ./hero.jpg --folder-id <folder_id>

# Preview without uploading
contentstudio --json media:upload --url https://example.com/img.jpg --dry-run

The upload response includes an _id you can pass as --media-id when creating posts.


11. Automation Workflows

Copy-paste ready scripts for common scenarios.

Schedule a daily post for the next 7 days

#!/bin/bash
ACCOUNT="<facebook_page_id>"
CONTENT=(
  "Monday motivation ๐Ÿ’ช"
  "Tuesday tips: keep it simple"
  "Wednesday wisdom from the team"
  "Throwback Thursday"
  "Friday vibes ๐ŸŽ‰"
  "Weekend prep โ€” try this"
  "Sunday reflections"
)

for i in "${!CONTENT[@]}"; do
  DATE=$(date -d "+$((i+1)) day 09:00" '+%F %T')
  contentstudio --json posts:create \
    -c "${CONTENT[$i]}" \
    -i "$ACCOUNT" \
    -t scheduled \
    -s "$DATE"
done

Cross-platform campaign (same post, multiple platforms)

#!/bin/bash
TIME="2026-05-01 10:00:00"

FB=$(contentstudio --json accounts:list --platform facebook | jq -r '.data[0]._id')
LI=$(contentstudio --json accounts:list --platform linkedin | jq -r '.data[0]._id')
TW=$(contentstudio --json accounts:list --platform twitter  | jq -r '.data[0]._id')

contentstudio --json posts:create \
  -c "Big launch today ๐Ÿš€" \
  -i "$FB" -i "$LI" -i "$TW" \
  -t scheduled \
  -s "$TIME" \
  -m https://example.com/launch.jpg

Bulk-delete drafts older than 30 days

#!/bin/bash
CUTOFF=$(date -d '-30 days' '+%Y-%m-%d')

contentstudio --json posts:list --status draft --date-to "$CUTOFF" --per-page 100 \
  | jq -r '.data[]._id' \
  | while read id; do
      contentstudio --json posts:delete "$id"
    done

Upload a folder of images, one post per image

#!/bin/bash
ACCOUNT="<instagram_id>"

for img in ./photos/*.jpg; do
  RESP=$(contentstudio --json media:upload --file "$img")
  MEDIA_ID=$(echo "$RESP" | jq -r '.data._id')

  TIME=$(date -d "+1 hour" '+%F %T')
  contentstudio --json posts:create \
    -c "$(basename "$img" .jpg)" \
    -i "$ACCOUNT" \
    -t scheduled \
    -s "$TIME" \
    --media-id "$MEDIA_ID" \
    --post-type feed
done

Auto-approve posts from a trusted creator

#!/bin/bash
TRUSTED_USER_ID="<user_id>"

contentstudio --json posts:list --status pending_approval --per-page 50 \
  | jq -r --arg u "$TRUSTED_USER_ID" '.data[] | select(.created_by == $u) | ._id' \
  | while read id; do
      contentstudio --json posts:approve "$id" --comment "auto-approved (trusted creator)"
    done

12. JSON Output (for scripts & agents)

Every command supports --json. The response always has the same shape, making it easy to pipe into jq or handle in scripts.

// Success
{ "ok": true, "data": <payload> }

// Error
{
  "ok": false,
  "error": {
    "type": "AuthError",
    "message": "Invalid or revoked API key",
    "http_status": 401,
    "hint": "Run `contentstudio auth:login --api-key cs_...` to set a valid API key."
  }
}

Always check both ok and the process exit code (non-zero on error).


13. Error Reference

The CLI uses typed errors with specific exit codes so your scripts can handle failures cleanly.

Exit code Error type HTTP What it means
1 ContentStudioError varies Generic error โ€” check the message
2 AuthError 401, 403 Invalid or revoked key โ€” run auth:login again
3 NotFoundError 404 Resource doesn't exist or wrong workspace
4 ValidationError 422 Malformed request โ€” check the message for field details
5 RateLimitError 429 Too many calls โ€” back off and retry
6 BackendError 5xx / network Upstream issue โ€” retry with backoff
1 ConfigError โ€” Local config issue (no key or workspace set) โ€” see hint in output
โ„น๏ธ Automatic retries
The CLI automatically retries on rate limit (429) and server errors (5xx) โ€” up to 2 attempts with exponential backoff. Connection timeouts are retried too. You don't need to build retry logic yourself for these cases.

14. Quick Reference

# โ”€โ”€ Authentication โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio auth:login --api-key cs_...        # Persist key + verify
contentstudio auth:status                        # Show local config
contentstudio --json auth:whoami                 # Validate against API
contentstudio auth:logout                        # Forget credentials

# โ”€โ”€ Workspaces โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --json workspaces:list             # List all workspaces
contentstudio workspaces:use <workspace_id>      # Set active workspace
contentstudio workspaces:current                 # Show active workspace

# โ”€โ”€ Discovery โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --json accounts:list [--platform] [--search]
contentstudio --json campaigns:list
contentstudio --json categories:list
contentstudio --json labels:list
contentstudio --json team:list

# โ”€โ”€ Posts โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --json posts:list [--status] [--date-from] [--date-to]
contentstudio --json posts:create -c "text" -i <id> -t draft
contentstudio --json posts:create --body /path/to/post.json
contentstudio --json posts:create [...] --dry-run          # preview only
contentstudio --json posts:delete <post_id> [--delete-from-social]
contentstudio --json posts:approve <post_id> [--comment "..."]
contentstudio --json posts:reject  <post_id> [--comment "..."]

# โ”€โ”€ Comments / Notes โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --json comments:list <post_id>
contentstudio --json comments:add  <post_id> "message" [--note] [--mention <id>]

# โ”€โ”€ Media โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --json media:list [--type images|videos] [--sort recent]
contentstudio --json media:upload --file <path>
contentstudio --json media:upload --url <url>

# โ”€โ”€ Global flags โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
contentstudio --version
contentstudio --help
contentstudio <command> --help
contentstudio --json ...                         # JSON envelope output
contentstudio --workspace <id> ...              # Per-call workspace override
contentstudio --base-url <url> ...              # Per-call API URL override

15. API Endpoints

The CLI wraps these 20 endpoints from the ContentStudio v1 public API. Base URL: https://api.contentstudio.io/api/v1

Method Endpoint CLI command
GET /me auth:whoami
GET /platforms platforms:list
GET /workspaces workspaces:list
GET /workspaces/{w}/accounts accounts:list
POST /workspaces/{w}/connect/{platform} accounts:connect <platform>
POST /workspaces/{w}/add/bluesky accounts:add-bluesky
POST /workspaces/{w}/add/facebook-group accounts:add-facebook-group
GET /workspaces/{w}/campaigns campaigns:list
GET /workspaces/{w}/content-categories categories:list
GET /workspaces/{w}/labels labels:list
GET /workspaces/{w}/team-members team:list
GET /workspaces/{w}/media media:list
POST /workspaces/{w}/media media:upload
GET /workspaces/{w}/posts posts:list
POST /workspaces/{w}/posts posts:create
DELETE /workspaces/{w}/posts/{p} posts:delete
POST /workspaces/{w}/posts/{p}/approval posts:approve, posts:reject
GET /workspaces/{w}/posts/{p}/comments comments:list
POST /workspaces/{w}/posts/{p}/comments comments:add

Full OpenAPI spec: api.contentstudio.io/api-docs.json  ยท  Human-readable docs: api.contentstudio.io/guide  ยท  npm: contentstudio-cli  ยท  GitHub: d4interactive/contentstudio-agent


FAQs

  • Do I need to log in every time I use the CLI? No. Running contentstudio auth:login --api-key cs_...  saves your key locally, so you only need to do it once. You can check your stored credentials anytime with contentstudio auth:status .
  • Can I post to multiple social accounts at the same time? Yes. Just repeat the -i  flag for each account ID in your posts:create  command. One API call, one post, multiple platforms.
  • What's the difference between --image-url  and --media-id ?--image-url  pulls in an image from an external URL on the fly. --media-id  references an asset you've already uploaded to your ContentStudio media library. Use media:list  to find existing asset IDs.
  • How do I preview a command without actually sending anything? Add --dry-run  to any mutating command. It prints the full request payload and exits without touching the API. This works for posts:create , posts:delete , posts:approve , and more.
  • When do I need a JSON body file instead of shortcut flags? Whenever you need platform-specific options โ€” like TikTok privacy settings, YouTube categories, Pinterest link URLs, or Google Business event details. Pass the file with --body /path/to/post.json .
  • What happens if I hit a rate limit? The CLI handles it automatically. It retries up to twice with exponential backoff on 429 and 5xx errors, so you don't need to build retry logic yourself.
  • Can I scope a command to a different workspace without changing my default? Yes. Use the --workspace <id>  flag inline on any command. It overrides the active workspace for that call only and leaves your saved default untouched.
  • How do I connect a Bluesky account? Bluesky doesn't use OAuth. Generate an app password at bsky.app under Settings โ†’ App Passwords, then run accounts:add-bluesky  with your handle and that app password. Never use your main Bluesky password here.
  • Can I use the CLI in automated scripts? Yes, it's designed for this. Use --json  on any command to get a consistent { "ok": true, "data": ... }  envelope you can pipe into jq  or handle in bash. Non-zero exit codes signal errors, so standard script error handling works out of the box.
  • Why is my command returning a NotFoundError? Usually this means the resource ID doesn't exist in your currently active workspace. Double-check which workspace is active with workspaces:current , and make sure the post, account, or asset ID belongs to it.
Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.

Still need help? Contact Us Contact Us