Setup & Installation

Install Social Media Assistant (via postsyncer.com) using the ClawHub CLI or OpenClaw CLI:

clawhub install postsyncer

If the CLI is not installed:

npx clawhub@latest install postsyncer

Or install with OpenClaw CLI:

openclaw skills install postsyncer

View on ClawHub · View on GitHub

What This Skill Does

Social Media Assistant (via postsyncer.com) is a social-media skill for OpenClaw by PostSyncer <support@postsyncer.com>.

PostSyncer Social Media Assistant

Autonomously manage social media through PostSyncer using the REST API.

Setup

  1. Create a PostSyncer account at app.postsyncer.com
  2. Connect social profiles (Instagram, TikTok, YouTube, X, LinkedIn, etc.)
  3. Go to Settings → API Integrations and create a personal access token with abilities: workspaces, accounts, posts, and (if you use them) labels, campaigns
  4. Add to .env: POSTSYNCER_API_TOKEN=your_token

PostSyncer MCP (optional)

PostSyncer MCP uses the same Bearer token as REST. Typical tools: list-workspaces, list-accounts, post CRUD, list-media, get-media, upload-media-from-url, delete-media, list-folders, create-folder, get-folder, update-folder, delete-folder, comments, labels, campaigns, analytics.

Multipart file upload is only via REST: POST /api/v1/media/upload/file (not exposed as an MCP tool). Use upload-media-from-url or REST URL import when the client cannot send multipart.

How to Make API Calls

All requests go to https://postsyncer.com/api/v1 with the header:

Authorization: Bearer $POSTSYNCER_API_TOKEN
Content-Type: application/json

Use web_fetch, curl, or any HTTP tool available. Always read $POSTSYNCER_API_TOKEN from the environment.


API Reference

Discovery (Call First)

List WorkspacesGET /api/v1/workspaces

curl "https://postsyncer.com/api/v1/workspaces" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Returns workspaces with id, name, slug, timezone.

List AccountsGET /api/v1/accounts

curl "https://postsyncer.com/api/v1/accounts" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Returns accounts with id, platform, username, workspace_id.


Media library

Requires the posts ability. Responses include id, workspace_id, folder_id, and asset metadata.

List MediaGET /api/v1/media

curl -G "https://postsyncer.com/api/v1/media" \
  --data-urlencode "workspace_id=12" \
  --data-urlencode "page=1" \
  --data-urlencode "per_page=50" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Query params: workspace_id, folder_id, root_only (true/false), page, per_page (max 100).

Get MediaGET /api/v1/media/{media_id}

curl "https://postsyncer.com/api/v1/media/999" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Import from URLsPOST /api/v1/media/upload/url

curl -X POST "https://postsyncer.com/api/v1/media/upload/url" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": 12, "urls": ["https://example.com/photo.jpg"], "folder_id": null}'

Upload file (multipart)POST /api/v1/media/upload/file

Use multipart/form-data with fields such as workspace_id, file (and optional chunk/chunk metadata if your client uses chunked upload). Not JSON.

Delete MediaDELETE /api/v1/media/{media_id} (confirm first)

curl -X DELETE "https://postsyncer.com/api/v1/media/999" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Media folders

Requires the posts ability.

List FoldersGET /api/v1/folders

curl -G "https://postsyncer.com/api/v1/folders" \
  --data-urlencode "workspace_id=12" \
  --data-urlencode "root=1" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Query params: workspace_id, parent_id, root (top-level only).

Create FolderPOST /api/v1/folders

curl -X POST "https://postsyncer.com/api/v1/folders" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"workspace_id": 12, "name": "Campaign assets", "color": "#3b82f6", "parent_id": null}'

Get FolderGET /api/v1/folders/{id}

Update FolderPUT /api/v1/folders/{id}

curl -X PUT "https://postsyncer.com/api/v1/folders/5" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Renamed folder"}'

Delete FolderDELETE /api/v1/folders/{id} (confirm first)


Posts

List PostsGET /api/v1/posts

curl "https://postsyncer.com/api/v1/posts?page=1&per_page=20&include_comments=false" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Query params: page, per_page (max 100), include_comments (true/false).

Get PostGET /api/v1/posts/{id}

curl "https://postsyncer.com/api/v1/posts/123" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Create PostPOST /api/v1/posts

curl -X POST "https://postsyncer.com/api/v1/posts" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": 12,
    "schedule_type": "schedule",
    "content": [{"text": "Caption #hashtags", "media": [42, "https://example.com/image.jpg"]}],
    "accounts": [{"id": 136}, {"id": 95, "settings": {"board_id": 123}}],
    "schedule_for": {"date": "2026-03-26", "time": "14:30", "timezone": "America/New_York"},
    "labels": [5],
    "repeatable": false
  }'
  • schedule_type: publish_now | schedule | draft
  • schedule_for: Optional scheduling object used when schedule_type is schedule. Provide {"date": "YYYY-MM-DD", "time": "HH:MM", "timezone": "..."} to schedule for a specific date/time, or omit/leave empty to auto-schedule to the next available time slot
  • content: Array of thread items. Each needs text and/or media: an array of library media IDs (integers) and/or HTTPS URL strings (import or list media first when you want stable IDs)
  • accounts: Array of {id, settings?}. Platform-specific options go in settings

Update PostPUT /api/v1/posts/{id}

curl -X PUT "https://postsyncer.com/api/v1/posts/123" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": [{"text": "Updated caption"}], "schedule_for": {"date": "2026-03-27", "time": "10:00"}}'

Only posts that have not been published yet can be updated.

Delete PostDELETE /api/v1/posts/{id} (confirm with user first)

curl -X DELETE "https://postsyncer.com/api/v1/posts/123" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Comments

List CommentsGET /api/v1/comments

curl -G "https://postsyncer.com/api/v1/comments" \
  --data-urlencode "post_id=123" \
  --data-urlencode "per_page=20" \
  --data-urlencode "include_replies=true" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Query params: post_id (required), per_page, page, include_replies, platform.

Get CommentGET /api/v1/comments/{id}

curl "https://postsyncer.com/api/v1/comments/456" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Create Comment / ReplyPOST /api/v1/comments

curl -X POST "https://postsyncer.com/api/v1/comments" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"post_id": 123, "content": "Reply text", "parent_comment_id": null, "media": [42]}'

Optional media: array of integer library IDs and/or HTTPS URLs (same shape as post content[].media; do not use a deprecated media_urls field).

Update CommentPUT /api/v1/comments/{id}

curl -X PUT "https://postsyncer.com/api/v1/comments/456" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content": "Updated reply text"}'

Hide CommentPOST /api/v1/comments/{id}/hide

curl -X POST "https://postsyncer.com/api/v1/comments/456/hide" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Delete CommentDELETE /api/v1/comments/{id} (confirm first)

curl -X DELETE "https://postsyncer.com/api/v1/comments/456" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Sync Comments from PlatformsPOST /api/v1/comments/sync

curl -X POST "https://postsyncer.com/api/v1/comments/sync" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"post_id": 123}'

Labels

List LabelsGET /api/v1/labels

curl "https://postsyncer.com/api/v1/labels" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Get LabelGET /api/v1/labels/{id}

Create LabelPOST /api/v1/labels

curl -X POST "https://postsyncer.com/api/v1/labels" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name": "Campaign 2026", "color": "#3b82f6", "workspace_id": 12}'

Update LabelPUT /api/v1/labels/{id}

Delete LabelDELETE /api/v1/labels/{id} (confirm first)


Analytics

All analytics endpoints require the posts API ability.

All WorkspacesGET /api/v1/analytics

curl "https://postsyncer.com/api/v1/analytics" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

By WorkspaceGET /api/v1/analytics/workspaces/{workspace_id}

curl "https://postsyncer.com/api/v1/analytics/workspaces/12" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

By PostGET /api/v1/analytics/posts/{post_id}

curl "https://postsyncer.com/api/v1/analytics/posts/123" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

By AccountGET /api/v1/analytics/accounts/{account_id}

curl "https://postsyncer.com/api/v1/analytics/accounts/136" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Sync Post AnalyticsPOST /api/v1/analytics/posts/{post_id}/sync

curl -X POST "https://postsyncer.com/api/v1/analytics/posts/123/sync" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Queues background jobs to refresh metrics. Does not return metrics directly — call GET after sync.


Account Management

Delete AccountDELETE /api/v1/accounts/{id} (destructive, confirm first)

curl -X DELETE "https://postsyncer.com/api/v1/accounts/136" \
  -H "Authorization: Bearer $POSTSYNCER_API_TOKEN"

Platform-Specific Settings

Pass per-platform options in accounts[].settings when creating/updating posts:

Pinterest: {"board_id": 123456}

X/Twitter:

{"reply_settings": "everyone", "for_super_followers_only": false, "quote_tweet_id": null, "reply": {"in_reply_to_tweet_id": null}, "community_id": null, "share_with_followers": true}

TikTok:

{"privacy_level": "PUBLIC_TO_EVERYONE", "disable_comment": false, "disable_duet": false, "disable_stitch": false, "post_mode": "DIRECT_POST"}

Instagram: {"post_type": "POST"} — options: REELS, STORIES, POST

YouTube:

{"video_type": "video", "title": "My Video", "privacyStatus": "public", "notifySubscribers": true}

LinkedIn: {"visibility": "PUBLIC"} — options: PUBLIC, CONNECTIONS, LOGGED_IN

Bluesky: {"website_card": {"uri": "https://...", "title": "...", "description": "..."}}

Telegram: {"disable_notification": false, "protect_content": false}


Common Workflows

Schedule a Post to Multiple Platforms

  1. GET /api/v1/workspaces → get workspace_id
  2. GET /api/v1/accounts → get ids for target platforms
  3. Optionally POST /api/v1/media/upload/url (or MCP upload-media-from-url) → use returned ids in content[].media
  4. POST /api/v1/posts with schedule_type: "schedule" and schedule_for

Reply to Comments

  1. GET /api/v1/posts → find post id
  2. POST /api/v1/comments/sync with post_id
  3. GET /api/v1/comments?post_id=123&include_replies=true
  4. POST /api/v1/comments with post_id and optional parent_comment_id

Check Performance

  1. GET /api/v1/analytics/posts/{id} for a specific post
  2. If stale: POST /api/v1/analytics/posts/{id}/sync, then re-fetch

Best Practices

  • Always start with GET /workspaces and GET /accounts to discover IDs; use GET /folders and GET /media when organizing or attaching library assets
  • New automations: Use schedule_type: "draft" or confirm before publish_now
  • Destructive actions: State what will happen, confirm before delete operations
  • Multi-network: One post can target multiple accounts; check per-platform status in the response
  • Rate limits: 60 requests/minute — don't call sync endpoints repeatedly
  • Hashtags: Keep relevant and limited (3–5 per post)

Error Handling

Status Meaning
401 Token missing or invalid
403 Token lacks required ability (e.g. posts)
404 Resource not found or no access
422 Validation error — check required fields and formats
429 Rate limited — wait before retrying

Links

Version History

Latest version: 2.1.1

First published: Mar 25, 2026. Last updated: Mar 31, 2026.

3 versions released.

Frequently Asked Questions

Is Social Media Assistant (via postsyncer.com) free to use?
Yes. Social Media Assistant (via postsyncer.com) is a free, open-source skill available on the OpenClaw Skills Registry. You can install and use it at no cost, and the source code is publicly available for review and contribution.
What platforms does Social Media Assistant (via postsyncer.com) support?
It runs on any platform that supports OpenClaw, including macOS, Linux, and Windows. As long as you have the OpenClaw runtime installed, Social Media Assistant (via postsyncer.com) will work seamlessly across operating systems.
How do I update Social Media Assistant (via postsyncer.com)?
Run openclaw skills update postsyncer to get the latest version. OpenClaw will download and apply the update automatically, preserving your existing configuration.
Can I use Social Media Assistant (via postsyncer.com) with other skills?
Yes. OpenClaw skills are composable — you can combine Social Media Assistant (via postsyncer.com) with any other installed skill in your workflows. This allows you to build powerful multi-step automations by chaining skills together.