Cross-Posting
The biggest reason to use OmniSocials instead of calling every platform's API directly is that a single POST /posts/create call can target any number of connected channels at once. You write one request, OmniSocials fans it out, handles each platform's quirks, and tells you what happened.
This guide walks through the patterns that matter when you're posting the same idea to multiple platforms at the same time.
The one-request-many-platforms mental model
Every post has an accounts array. Put as many account IDs in it as you want, and OmniSocials publishes the same post to each of them.
Code
That single call produces one post record in OmniSocials and publishes it to Facebook, Instagram, both LinkedIn slots, and X. The response includes the resulting URLs for each platform once publishing completes.
Same text everywhere (flat string)
The simplest shape. A single string in content is used on every channel in the accounts array.
Code
Use this when the message is short, generic, and reads well on every platform. The downside is there is no tuning per platform.
Different text per platform
Pass an object keyed by channel ID. The default key is the fallback for channels that don't have an explicit entry.
Code
Facebook and Instagram fall back to the default copy. X gets a punchy version under its tighter character limit. The two LinkedIn channels each get their own voice: personal tone on the profile, official tone on the company page.
You only need to override the channels you actually want to customize. Everything else inherits default.
Same media, different per-platform content
Media attachment works the same way: flat array (same on every channel) or object keyed by channel ID.
Code
All three channels get the same three photos. LinkedIn channels get the custom copy, Instagram inherits default.
Different media per platform
When platforms need different image aspect ratios or video formats, key the media object by channel ID. The default key is the fallback.
Code
- Instagram gets the square crop
- Pinterest gets the tall 2:3 crop for feed visibility
- Facebook falls back to the 16:9
default - X is opted out of media entirely (empty array) so the post goes out as text-only
The empty-array trick is how you say "this platform specifically should not have media" without having to remove it from accounts.
Handling character limits
Every platform has its own character limit. OmniSocials validates against the strictest limit of every channel in the accounts array and rejects the whole post with 400 if any platform would exceed it.
| Platform | Limit |
|---|---|
| X (standard) | 280 |
| X (Premium) | 25,000 |
| Bluesky | 300 (graphemes) |
| Threads | 500 |
| Mastodon | 500 (default) |
| 500 | |
| 3,000 | |
| TikTok | 4,000 |
| 2,200 | |
| 63,206 | |
| Google Business | 1,500 |
Two strategies to avoid rejection:
- Write to the strictest limit. If you're posting to X along with LinkedIn and Facebook, cap your copy at 280 characters.
- Use per-platform content to give X a shorter variant and let the others use a longer one.
Strategy 2 is usually the better call because you write once in default and only override X.
Platform-specific options apply automatically
Options that live under a channel-ID key (pinterest.board_id, youtube.title, tiktok.privacy_level, etc.) only apply to that channel. They're ignored by every other channel in the same request.
Code
TikTok picks up the tiktok options. YouTube picks up the youtube options. Instagram ignores both and uses its own defaults. No per-channel request splitting required.
What happens when one platform fails
Cross-posting introduces a new failure mode: the post publishes successfully to some platforms and fails on others. Instead of returning a flat posted or failed, OmniSocials sets the post status to partially_posted and records per-channel failures in a failed_platforms array.
Code
Three ways to handle partial failures:
- Retry the failed channels only.
POST /posts/:id/retry-failed-platformsre-runs the publish on every channel infailed_platforms. The successful channels are left untouched. - Edit and retry. Update the post with
PUT /posts/:id(e.g. slightly change the X copy to dodge the duplicate filter) and then retry. - Listen via webhooks. Subscribe to the
post.partially_publishedevent to get notified the moment a partial failure happens. See Webhooks.
Schedule once, publish everywhere
Cross-posting works the same way for scheduled posts. Add scheduled_at (ISO 8601 UTC) and OmniSocials publishes to every channel in the accounts array at the scheduled time.
Code
Every channel publishes within a one-minute window of the scheduled time. Scheduling a cross-post does not lock anything in. You can still PUT /posts/:id to change content, DELETE /posts/:id to cancel, or add and remove channels before the scheduled time arrives.
Practical recipes
A product launch
You want to announce a launch across every channel with platform-appropriate voice.
Code
A visual campaign
Same photo, different crops, one request.
Code
Instagram gets a three-image carousel of square crops. Pinterest gets the tall 2:3 crop with board metadata. Facebook falls back to the 16:9 default. One request.
Schedule a week of daily posts
Cross-posting composes naturally with scheduling. For a week of daily posts, call POST /posts/create once per day with a different scheduled_at, or batch them in a loop on your side.
Code
Each call creates a separate scheduled post. Each one fans out across the three channels at its scheduled time. Rate limits apply per key (100 req/min) so batching more than 100 posts in a single burst will start hitting 429 responses. Back off and retry, or split across multiple keys.
Related reading
- Creating Posts for the full field reference
- Platforms for per-platform options and limits
- Rate Limits and Errors for
429andpartially_postedhandling - Webhooks for real-time status notifications