OmniSocialsOmniSocials
DocumentationAPI reference
Help centerSupport
  • Documentation
  • API reference
Developers
  • Quickstart
  • API reference
  • SDKs
  • MCP server
  • CLI
For AI agents
  • Docs for AI agents
  • llms.txt
  • OpenAPI spec
  • Postman collection
Product
  • OmniSocials
  • Pricing
  • Changelog
  • Help center
Company
  • Support
  • Privacy policy
  • Terms of service

ยฉ 2026 OmniSocials

OmniSocials on GitHubOmniSocials on XOmniSocials on LinkedIn
Overview
Get started
SDKs
CLI
MCPDocs for AI agentsWebhooks
Guides
    PostsStoriesReelsCross-postingMediaAnalyticsSocial inboxAutomations
Platforms
Integrations
Migrate
Plans and billing
GlossaryChangelogAPI reference
Guides

Cross-post to 14 channels in one API call

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.

TerminalTerminal
curl -X POST https://api.omnisocials.com/v1/posts/create \ -H "Authorization: Bearer $OMNISOCIALS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content": { "default": "New feature launched today ๐Ÿš€" }, "accounts": [ "your-facebook-account-id", "your-instagram-account-id", "your-linkedin-account-id", "your-linkedin-page-account-id", "your-x-account-id" ], "media_urls": ["https://example.com/launch.jpg"] }'

That single call produces one post record in OmniSocials, as a draft. Add "publish_now": true (or a schedule_at) and it publishes to Facebook, Instagram, both LinkedIn slots, and X; GET /posts/:id then carries the resulting URL for each platform in published_urls 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.

JSON
{ "content": "New blog post is live: https://example.com/blog", "accounts": ["fb-id", "x-id", "linkedin-id"] }

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.

JSON
{ "content": { "default": "We just shipped something cool. Check the blog for details.", "x": "New drop ๐Ÿ”ฅ https://example.com/blog", "linkedin": "Today we shipped a new capability. Here's what it unlocks for teams managing multi-platform content at scale...", "linkedin_page": "[Official] Our engineering team just shipped a major capability. Read the full write-up on our blog." }, "accounts": [ "your-facebook-account-id", "your-instagram-account-id", "your-x-account-id", "your-linkedin-account-id", "your-linkedin-page-account-id" ] }

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.

JSON
{ "content": { "default": "Behind the scenes from the photoshoot", "linkedin": "A look at the creative process behind our latest campaign. The full story is on our blog." }, "accounts": [ "instagram-id", "linkedin-id", "linkedin-page-id" ], "media_urls": [ "https://example.com/photo1.jpg", "https://example.com/photo2.jpg", "https://example.com/photo3.jpg" ] }

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.

JSON
{ "content": { "default": "Spring collection is live" }, "accounts": [ "instagram-id", "pinterest-id", "facebook-id", "x-id" ], "media_urls": { "default": ["https://example.com/spring-16x9.jpg"], "instagram": ["https://example.com/spring-square.jpg"], "pinterest": ["https://example.com/spring-2x3-tall.jpg"], "x": [] } }
  • 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.

PlatformLimit
X (standard)280 (weighted: every link = 23, emoji and CJK characters = 2)
X (Premium)25,000 (applied automatically when the connected X account has Premium; you cannot choose the tier per post)
Bluesky300 (graphemes)
Threads500 (per post, and per part of a thread)
MastodonPer-instance (read from your instance at connect time; 500 on mastodon.social)
Pinterest500
LinkedIn3,000
TikTok2,200 for videos, 4,000 for photo posts
Instagram2,200
Facebook63,206
Google Business1,500
Telegram4,096 (1,024 under media; a longer text goes as a reply under the media)
Discord2,000 (300 for a poll question)

Two strategies to avoid rejection:

  1. Write to the strictest limit. If you're posting to X along with LinkedIn and Facebook, cap your copy at 280 characters.
  2. 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.

JSON
{ "content": { "default": "New video drop" }, "accounts": [ "tiktok-id", "youtube-id", "instagram-id" ], "media_urls": ["https://example.com/vertical-video.mp4"], "type": "reel", "tiktok": { "privacy_level": "PUBLIC_TO_EVERYONE" }, "youtube": { "title": "Behind the scenes", "privacy_status": "public" } }

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.

Two more per-platform tools compose with cross-posting:

  • Hashtag sets per channel. Apply a saved set with hashtag_set, and restrict which channels receive the tags with hashtag_platforms (for example hashtags on Instagram and X, a clean caption on LinkedIn). See Hashtag sets.
  • Thread posts on X, Bluesky, Mastodon, and Threads. Pass x.thread_parts, bluesky.thread_parts, mastodon.thread_parts, or threads.thread_parts to publish a chained thread on those channels while every other channel in accounts gets the normal single post. See the X, Bluesky, Mastodon, and Threads pages.

What happens when one platform fails

Cross-posting introduces a partial-failure mode: the post publishes to some platforms and fails on others. When that happens, OmniSocials sets the post status to warning (not posted or failed). The live URLs of the platforms that succeeded go in published_urls, and the per-platform error messages of the ones that failed go in errors. Both are objects keyed by platform identifier: succeeded platforms are omitted from errors, failed platforms are omitted from published_urls.

JSON
{ "id": "123", "status": "warning", "published_urls": { "facebook": "https://www.facebook.com/123456789/posts/987654321", "instagram": "https://www.instagram.com/p/Cxyz123ABC/", "linkedin": "https://www.linkedin.com/feed/update/urn:li:share:7191234567890" }, "errors": { "x": "Duplicate content posted within the last 24 hours" } }

(A post where every platform fails gets status: "failed" with all channels in errors; a post where every platform succeeds gets status: "published" and errors: null.)

Two ways to handle a partial failure:

  1. Fix and retry. Address the cause first if needed (reconnect the account, or edit the offending copy with PATCH /posts/:id to dodge a duplicate filter), then call POST /posts/:id/retry. It re-publishes only the platforms that failed; channels that already succeeded are never posted again. It works on both warning and failed posts, and each platform can be retried at most 3 times. POST /posts/:id/publish deliberately refuses warning and failed posts; retry is the endpoint for them. See Retrying failed posts.
  2. Listen via webhooks. A partial failure fires the post.published event with data.status: "warning"; inspect data.targets for the per-platform outcome. See Webhooks.

Schedule once, publish everywhere

Cross-posting works the same way for scheduled posts. Add schedule_at (ISO 8601 UTC) and OmniSocials publishes to every channel in the accounts array at the scheduled time.

JSON
{ "content": { "default": "Friday reading list", "x": "This week's top reads ๐Ÿงต" }, "accounts": ["linkedin-id", "x-id", "threads-id"], "schedule_at": "2026-04-18T14:00:00Z" }

Every channel publishes within a one-minute window of the scheduled time. Scheduling a cross-post does not lock anything in. You can still PATCH /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.

JSON
{ "content": { "default": "It's here. [Feature Name] is live.", "x": "Just shipped: [Feature Name] ๐Ÿš€\n\nLink in replies ๐Ÿ‘‡", "linkedin": "We're thrilled to announce the launch of [Feature Name]. For the past six months, our team has been...", "linkedin_page": "[Feature Name] is now generally available. Key capabilities include...", "threads": "We shipped [Feature Name] today. Open to questions." }, "accounts": [ "fb-id", "ig-id", "linkedin-id", "linkedin-page-id", "x-id", "threads-id" ], "media_urls": ["https://example.com/launch-hero.jpg"] }

A visual campaign

Same photo, different crops, one request.

JSON
{ "content": { "default": "Spring 2026 lookbook" }, "accounts": ["ig-id", "pinterest-id", "fb-id"], "media_urls": { "default": ["https://example.com/spring-16x9.jpg"], "instagram": [ "https://example.com/spring-square-1.jpg", "https://example.com/spring-square-2.jpg", "https://example.com/spring-square-3.jpg" ], "pinterest": ["https://example.com/spring-tall.jpg"] }, "pinterest": { "board_id": "your-board-id", "title": "Spring 2026 lookbook" } }

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 schedule_at, or batch them in a loop on your side.

JavaScript
const posts = [ { day: "Monday", copy: "Monday thoughts..." }, { day: "Tuesday", copy: "Tuesday tip..." }, // ... ] for (const post of posts) { await fetch("https://api.omnisocials.com/v1/posts/create", { method: "POST", headers: { "Authorization": `Bearer ${process.env.OMNISOCIALS_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ content: { default: post.copy }, accounts: ["linkedin-id", "x-id", "threads-id"], schedule_at: scheduleFor(post.day), }), }) }

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 429 and partial-failure (warning) handling
  • Webhooks for real-time status notifications
Last modified on October 22, 2026
ReelsMedia
On this page
  • The one-request-many-platforms mental model
  • Same text everywhere (flat string)
  • Different text per platform
  • Same media, different per-platform content
  • Different media per platform
  • Handling character limits
  • Platform-specific options apply automatically
  • What happens when one platform fails
  • Schedule once, publish everywhere
  • Practical recipes
    • A product launch
    • A visual campaign
    • Schedule a week of daily posts
  • Related reading
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
JSON
Javascript