---
name: post-bridge-social-manager
version: 1.0.8
title: Social Media Assistant (via post-bridge.com)
description: Turn your OpenClaw into an autonomous social media manager using Post Bridge API. Use when scheduling, posting, or managing content across TikTok, Instagram Reels, YouTube Shorts, Twitter/X, LinkedIn, Pinterest, Facebook, Threads, or Bluesky. Covers media upload, post creation, scheduling, platform-specific configs, draft mode, and post result tracking.
license: MIT
author: Jack Friks <jack@frikit.net>
homepage: https://clawhub.ai/jackfriks/post-bridge-social-manager
repository: https://github.com/jackfriks/post-bridge-social-manager
keywords: social-media, automation, post-bridge, tiktok, instagram, youtube, twitter, linkedin
metadata:
  openclaw:
    requires:
      env:
        - POST_BRIDGE_API_KEY
      bins:
        - ffmpeg
    primaryEnv: POST_BRIDGE_API_KEY
---

# Social Media Assistant (via post-bridge.com)

Autonomously manage social media posting via [Post Bridge](https://post-bridge.com) API.

## Setup

1. Create a Post Bridge account at [post-bridge.com](https://post-bridge.com)
2. Connect your social accounts (TikTok, Instagram, YouTube, Twitter, etc.)
3. Enable API access (Settings → API)
4. Store your API key in workspace `.env`:
   ```
   POST_BRIDGE_API_KEY=pb_live_xxxxx
   ```
5. Download API docs: `https://api.post-bridge.com/reference` → save to workspace as `post-bridge-api.json`

## Auth

All requests use Bearer token:
```
Authorization: Bearer <POST_BRIDGE_API_KEY>
```

Base URL: `https://api.post-bridge.com`

## Core Workflow

### 1. Get Social Accounts
```
GET /v1/social-accounts
```
Returns array of connected accounts with `id`, `platform`, `username`, `needs_reconnect`. Store these IDs — you need them for every post. When `needs_reconnect` is `true`, repeated dead-token failures have paused posting to that account: posts to it are skipped until the user reconnects it in the dashboard (reconnecting clears the pause automatically). Skip those accounts in your automation instead of retrying.

### 2. Upload Media
```
POST /v1/media/create-upload-url
Body: { "mime_type": "video/mp4", "size_bytes": <int>, "name": "video.mp4" }
```
Returns `media_id` + `upload_url`. Then:
```
PUT <upload_url>
Content-Type: video/mp4
Body: <binary file>
```

### 3. Create Post
```
POST /v1/posts
Body: {
  "caption": "your caption here #hashtags",
  "media": ["<media_id>"],
  "social_accounts": [<account_id_1>, <account_id_2>],
  "scheduled_at": "2026-01-01T14:00:00Z",  // omit for instant post
  "platform_configurations": { ... }  // optional, see below
}
```

> **X/Twitter — links are stripped:** X now charges ~13× more for posts that contain a link, so Post Bridge automatically removes links from the caption before publishing to X. This covers full URLs (`http://`, `https://`, `www.`) and bare domains like `foo.com` or `foo.io/path`. Other platforms keep their links untouched. To share a link on X, put it in the `twitter.first_comment` config (posted as a reply right after the tweet — links are allowed there) or your bio.

**Additional create options:**

- `media_urls`: Array of publicly accessible URLs (used instead of `media` if no media IDs). Example: `["https://example.com/video.mp4"]`
- `is_draft`: If `true`, creates the post but does not process it until updated with a scheduled date or posted instantly later.
- `processing_enabled`: If `false`, skips video processing. Defaults to `true`.
- `use_queue`: Automatically schedule to your next available queue slot (configured in the Post Bridge dashboard). Cannot be used with `scheduled_at`. Pass `true` to use your saved timezone, or `{ "timezone": "America/New_York" }` to override.

**`use_queue` example:**
```json
{
  "caption": "Queued post!",
  "media": ["<media_id>"],
  "social_accounts": [44029],
  "use_queue": true
}
```
This finds the next open slot in your queue schedule and sets `scheduled_at` automatically. You must have a queue schedule configured in the dashboard first.

### 4. Update or Delete Scheduled Posts
```
PATCH /v1/posts/<post_id>
```
Update a scheduled post (caption, schedule time, etc.). Only works on posts with `scheduled` status.

```
DELETE /v1/posts/<post_id>
```
Delete a scheduled post. Only works on posts with `scheduled` status.

### 5. Check Results
```
GET /v1/posts/<post_id>
```
Returns status: `processing`, `scheduled`, `posted`, `failed`.

```
GET /v1/post-results
```
List all post results across platforms (paginated with `offset` and `limit`).

### 6. Analytics
```
GET /v1/analytics
```
Retrieve performance data (views, likes, shares, comments, etc.) for posts.

Query parameters:
- `platform` — filter by platform (e.g. `tiktok`, `youtube`, `instagram`)
- `post_result_id[]` — filter by specific post result IDs (multiple values = OR logic)
- `timeframe` — `7d`, `30d`, `90d`, or `all` (default: `all`)
- `offset` / `limit` — pagination

Returns: `view_count`, `like_count`, `comment_count`, `share_count`, `cover_image_url`, `share_url`, `duration`, and more per record.

```
POST /v1/analytics/sync
```
Manually trigger a sync of analytics from platforms. Optionally pass `?platform=tiktok` to sync a specific platform only. Rate-limited to once every 5 minutes.

## Platform Configurations

Optional per-platform overrides, passed inside the `platform_configurations` object on post creation/update. This is the #1 place to get wrong, so read carefully:

**Rules**
1. **Key by platform name.** Every override lives under a platform key: `pinterest`, `instagram`, `tiktok`, `twitter`, `youtube`, `facebook`, `linkedin`, `bluesky`, `threads`, `google_business`. A field placed at the wrong level (or under the wrong platform) is silently ignored.
2. **Only include platforms you're actually posting to.** Don't add a `tiktok` block if no TikTok account is in `social_accounts`.
3. **Only include fields you want to override.** Everything you omit falls back to the top-level `caption` / `media`. `caption` and `media` are accepted under *every* platform key; the other fields are platform-specific and listed below.
4. **Match the accepted values exactly.** Enums (`placement`, `trial_graduation`, `cta_action_type`, `location`, …) only accept the values shown — anything else errors or is dropped.

Every platform accepts:
- `caption` (string) — caption override for that platform only
- `media` (array of media IDs) — media override for that platform only

Platform-specific fields:

| Platform (`key`) | Field | Type / accepted values | What it does |
|---|---|---|---|
| **Pinterest** (`pinterest`) | `board_ids` | array of string IDs | Boards to pin to (IDs, not names). Omit → account default board. |
| | `link` | string (full URL) | Destination URL the pin links to. |
| | `title` | string (≤100 chars) | Pin title shown above the caption. |
| | `video_cover_timestamp_ms` | number (ms) | Video cover frame, e.g. `3000` = 3s in. |
| **Instagram** (`instagram`) | `placement` | `"story"` | Publish as a Story (one image/video, no caption/carousel/cover/trial). Omit → Reel/feed. |
| | `video_cover_timestamp_ms` | number (ms) | Cover frame for a reel/video. Ignored if `cover_image` is set. |
| | `cover_image` | string (media ID) | Uploaded image used as the reel cover. Upload first, pass its ID. |
| | `is_trial_reel` | boolean | Trial reel (non-followers first). Needs Pro/Creator account, 1,000+ followers, public profile. Max 5/day. Not with `placement:"story"`. |
| | `trial_graduation` | `"MANUAL"` \| `"SS_PERFORMANCE"` | Trial reel graduation. `MANUAL` (default) = you decide; `SS_PERFORMANCE` = auto-graduate on performance in 72h. |
| | `user_tags` | array of usernames | People-tag accounts (they get notified). `@` optional. Feed/carousel/reels only; ignored for stories. Max 20. |
| | `collaborators` | array of usernames | Invite co-authors: the post also appears on their profile and shares its likes/comments. `@` optional. **Max 3, public accounts only** — a private or wrong handle fails the post. Feed/carousel/reels only; ignored for stories. Publishes immediately; shows on their profile once they accept. |
| | `first_comment` | string (≤2200) | Comment posted right after the post publishes — good spot for a link or hashtags. Ignored for stories. A failed comment won't fail the post. |
| **TikTok** (`tiktok`) | `title` | string | Overrides the post title. |
| | `video_cover_timestamp_ms` | number (ms) | Cover frame, e.g. `3000` = 3s in. |
| | `draft` | boolean | Send as a **native TikTok draft** (finish/publish manually in the app, e.g. to add a trending sound). Different from top-level `is_draft` (which only saves in Post Bridge). |
| | `is_aigc` | boolean | Label as AI-generated content. |
| **Twitter/X** (`twitter`) | `first_comment` | string (≤280, 2200 premium) | Reply posted right after the tweet. **Put links here** — the main tweet strips URLs to dodge X's surcharge. A failed reply won't fail the post. |
| **YouTube** (`youtube`) | `title` | string (≤100 chars) | Video title override. |
| | `contains_synthetic_media` | boolean | Disclose realistic altered/AI content ("Altered or synthetic content" label). |
| | `thumbnail` | string (media ID) | Custom thumbnail. **Long-form videos only** — ignored on Shorts. Channel must be verified; JPEG/PNG, 1280×720, <2MB. |
| **Facebook** (`facebook`) | `placement` | `"story"` | Publish as a Page Story (one image/video, no caption/carousel). Omit → feed post. |
| | `first_comment` | string (≤2200) | Comment posted right after the post publishes — good spot for a link/CTA. Ignored for stories. A failed comment won't fail the post. |
| **LinkedIn** (`linkedin`) | `document_title` | string | Title for a PDF (document/carousel) post. Only applies when media is a PDF. Defaults to file name. |
| **Bluesky** (`bluesky`) | — | — | Only `caption` / `media` overrides. |
| **Threads** (`threads`) | `location` | `"timeline"` \| `"reels"` | Where it appears. `timeline` (default) or `reels` (video only). |
| | `first_comment` | string (≤500) | Reply posted right after the thread publishes — good spot for a link. A failed reply won't fail the post. |
| **Google Business** (`google_business`) | `media` | array (single image) | **One image only** — extra images are dropped for GMB (other platforms keep all). No video. |
| | `cta_action_type` | `BOOK` \| `ORDER` \| `SHOP` \| `LEARN_MORE` \| `SIGN_UP` \| `CALL` | CTA button. Pair with `cta_url` (except `CALL`, which uses the location phone number). |
| | `cta_url` | string (full URL) | CTA destination. Required when `cta_action_type` is set (except `CALL`). |
| | `language_code` | string (BCP-47) | e.g. `"en-US"`, `"es"`, `"fr-CA"`. Defaults to `"en-US"`. |

**Example — correct multi-platform config**

Posting one piece of content to TikTok + Instagram + X + Google Business, with per-platform tweaks:
```json
{
  "caption": "New drop is live 🎉",
  "social_accounts": [44029, 44030, 44031, 44032],
  "platform_configurations": {
    "tiktok": {
      "draft": true,
      "is_aigc": false
    },
    "instagram": {
      "caption": "New drop is live 🎉 tap the link in bio",
      "video_cover_timestamp_ms": 2000
    },
    "twitter": {
      "first_comment": "Grab it here: https://example.com/drop"
    },
    "google_business": {
      "cta_action_type": "SHOP",
      "cta_url": "https://example.com/drop"
    }
  }
}
```
Note how the X link lives in `twitter.first_comment` (not the caption), TikTok uses a native draft, and only the four platforms being posted to appear as keys.

## Recommended Workflow for Video Content

1. Store videos in a local folder
2. Extract a frame with ffmpeg to read any text overlays:
   ```
   ffmpeg -i video.mp4 -ss 00:00:04 -frames:v 1 frame.jpg -y
   ```
3. Write caption based on video content + hashtags
4. Upload → create post → schedule or post instantly (or use `use_queue` to auto-schedule)
5. Move posted videos to a `posted/` subfolder to avoid duplicates
6. Set a cron to check post status 5 mins after scheduled time
7. Track performance with `GET /v1/analytics` or by browsing platform pages

## Tips

- Post to multiple platforms simultaneously by including multiple account IDs
- Stagger posts throughout the day (e.g. 9am + 3pm) for better reach
- Use `scheduled_at` to pre-schedule batches — Post Bridge handles the timing
- Use `use_queue` to auto-fill your queue schedule without calculating times yourself
- TikTok draft mode lets you add trending sounds manually before publishing
- Keep hashtags to 4-5 per post for best engagement
- Monitor what works and iterate on captions/formats
