One key, twelve channels
Publishing to eleven social platforms from a single REST call — and the two costs that sit outside the flat monthly price
One POST replaces eleven platform APIs, each with its own OAuth flow, media rules and idea of what counts as a video. The scheduling call is the easy part — four lines. The parts worth knowing before you build on it are the two costs that sit outside the flat monthly price, and the fact that the field names in the curl examples are not the field names the SDKs put on the wire.
Posting one thing to Instagram, LinkedIn, X and TikTok by hand means four APIs, four OAuth flows, four media specs and four sets of rules about file size and duration. This puts a single REST endpoint in front of all of them: send content, a list of target channels and optional media, and it fans out. Connecting the accounts stays manual and one-time — OAuth happens in the dashboard and cannot be done through the API — but after that every key in the workspace can publish to them.
The numbers, verified on 18 September 2026
Read off the published OpenAPI schema, the package registries and the pricing page rather than taken from the write-up.
Create the account
Fourteen-day trial, then $10 a month per workspace on annual billing. Seats and extra workspaces are $10 each on top — the API itself is not gated behind a sales call.
Connect the accounts
Settings → Connect on each platform. Two clicks each: sign in, approve. This is the one part with no API equivalent.
What you can connect
Twelve rows, eleven platforms — LinkedIn appears twice because a personal profile and a company page are separate connections with separate options.
Create the key
Settings → Organisation → API → Create key.
Keys read omsk_live_… against real accounts or omsk_test_… for a sandbox that touches nothing, and the value is displayed exactly once. The two inbox scopes are opt-in: a key created without them returns 403 the first time it reads a DM, which looks like a broken key rather than an unticked box. Scopes cannot be added to an existing key — a key that needs them has to be replaced.
The full scope list, which is longer than most walkthroughs mention
Keep it out of the code
Every call uses this header
Schedule a post
content and accounts are the only required fields. Everything else is optional.
The fields that matter
content takes a plain string when every platform gets the same caption, or an object keyed by platform with a default fallback. The object form is the documented one, and it is the actual argument for routing through one API instead of four — the same post, phrased for each audience, in one call.
accounts takes either a bare platform name or the composite <workspace_id>_<platform> id returned by GET /v1/accounts. The workspace prefix has to match the workspace the key belongs to; a mismatch comes back as a 400 naming the unknown account rather than quietly skipping that target.
Drop schedule_at and the post is saved as a draft. Add "publish_now": true to send it straight away, or POST to /v1/posts/:id/publish afterwards. media_urls takes public URLs the API downloads for you — up to 10 files, 100 MB each. To upload a local file instead, POST it to /v1/media/upload first (multipart, field name file) and pass the returned id in media.
The curl examples and the OpenAPI schema use accounts, schedule_at and media. Every SDK sends channels, scheduled_at and media_ids instead. This is not one library drifting — the Go and Python clients, written separately, both do it, and both decode the documented names on the way back. So it reads as a genuine alias set rather than a bug. I could not exercise both spellings against a live key, so treat the mapping as observed from two shipped clients rather than confirmed end to end; the practical point stands either way, which is that a payload copied between the docs and an SDK issue will not line up field for field.
The same fields, under two names
How a post performed
Up to 100 ids in one call
The batch endpoint exists precisely so a sync job does not spend its 100-a-minute budget one post at a time.
Account-level numbers, not tied to a post
The social inbox
Every DM, comment and mention across every connected platform in one thread. Needs inbox:read and inbox:write.
Read a thread, and reply to it
X bills developers roughly thirteen times more for a post whose text contains a URL ($0.20 against $0.015), and that is passed through at cost as prepaid credits: 20 credits for a link post, 1 credit to receive an X DM, 2 to reply. Credits are €0.01 each, topped up in €5–500 blocks, and every organisation starts with 200 free. A scheduled X link post reserves its cost until it publishes, and one that would push the reserved total past the balance is refused up front with 402 x_credits_insufficient. If the balance runs dry at publish time the X target alone fails and the rest of the post still goes out. Everything else — X posts without links, every other platform, scheduling, analytics, the inbox — stays free and unlimited. Worth knowing before pointing a release-notes automation at X.
Or skip the raw HTTP
Same shape in every language: client.posts.create(...), typed requests and responses, retries, and a webhook signature helper.
Eight documented, seven you can install today
Each one checked against its registry on 18 September 2026.
There is also an MCP server
The guide never mentions it, but the same API ships as an MCP server, which is the more interesting door for anyone already driving work from an assistant. It honours the same scopes as the REST API, so the key decides what the assistant may do — a read-only key is a genuinely safe way to let a model look at your analytics without giving it the ability to post anything.
Published as @omnisocials/mcp-server, MIT, at 1.35.0 as of 15 September 2026.