Migrate from the Postiz public API to the OmniSocials API
This guide is for developers who post through the Postiz public API, on Postiz Cloud or a self-hosted instance, and want to move to the OmniSocials API. In Postiz, one request carries a separate entry for each channel, with its own text, media, and settings. In OmniSocials, one post lists its channels in accounts, and per-channel text and options sit in objects keyed by channel ID. Scheduling moves from a type field to schedule_at and publish_now. Social accounts are connected in the OmniSocials dashboard. Postiz facts on this page come from docs.postiz.com and were checked on October 21, 2026.
Concepts
| Postiz | OmniSocials | Notes |
|---|---|---|
API key (Authorization: your-api-key, no Bearer) | API key (Authorization: Bearer omsk_live_...) | |
| Organization (the key reaches all its channels) | Workspace (the key reaches one workspace) | Create one key per workspace. |
Customer (GET /groups) | Workspace | Give each customer its own workspace and key. |
Integration (a channel) with an id | Account with an id, or the bare channel ID | A workspace has one account per channel ID. |
Connect URL (GET /social/{integration}) | Dashboard connection | Accounts are connected only in the dashboard, never through the API. |
One posts[] entry per integration | One post with an accounts array | One post id covers every channel. |
Extra value[] entries (thread or comments) | thread_parts on X, Bluesky, Mastodon, and Threads, or first_comment | See Threads and comments. |
settings.__type and its fields | A top-level object named after the channel | For example x, pinterest, youtube. |
type: draft, schedule, now | No schedule_at, schedule_at, publish_now: true | |
States QUEUE, PUBLISHED, ERROR, DRAFT | scheduled, published (or warning), failed, draft | warning means some channels published and some failed. |
| Tags | None | |
| Find slot | GET /analytics/best-times | Recommended slots from your own history. You pick the time. |
Authentication
Text
Postiz takes the raw key in the header. OmniSocials needs the Bearer prefix. A Postiz key reaches every channel of the organization. An OmniSocials key is bound to one workspace, chosen when you create the key under Settings → API. GET /accounts returns workspace_id and workspace_name, so you can check which workspace a key belongs to.
Keys have scopes, such as posts:write and media:write. A key's scopes cannot be edited later. See Authentication.
Endpoint mapping
OmniSocials paths are relative to https://api.omnisocials.com/v1. Postiz paths are relative to https://api.postiz.com/public/v1 on Postiz Cloud, or https://{your-domain}/api/public/v1 when self-hosted.
| Postiz | OmniSocials | Notes |
|---|---|---|
POST /posts | POST /posts/create | POST /posts is an alias. POST /posts/create-and-publish publishes at once. |
GET /posts | GET /posts | No date range. Filter with status and page with limit (max 100) and offset, newest first. |
DELETE /posts/{id} | DELETE /posts/{id} | Removes the post from OmniSocials and cancels a scheduled publish. It does not delete a live post on the platform. |
DELETE /posts/group/{group} | DELETE /posts/{id} | One post covers all its channels, so there is no group. |
PUT /posts/{id}/status | PATCH /posts/{id} | Send draft: true to unschedule, or draft: false to schedule a draft that has a schedule_at. |
PUT /posts/{id}/settings | PATCH /posts/{id} | Drafts and scheduled posts only. Any create field can change. |
GET /integrations | GET /accounts | Returns the key's workspace and its accounts, with status and needs_reconnect. |
GET /is-connected, GET /me | GET /accounts | A 200 means the key works. |
GET /groups | None | Each customer becomes a workspace with its own key. |
GET /social/{integration} | None | Connect accounts in the dashboard. |
DELETE /integrations/{id} | None | Disconnect accounts in the dashboard. |
GET /find-slot/{id} | GET /analytics/best-times | Recommendations, not the next free slot. |
POST /upload | POST /media/upload | Multipart with a file field, up to 100 MB. |
POST /upload-from-url | POST /media/upload-from-url | Same { "url": "..." } body. Up to 1 GB. |
GET /media/{id}/status | GET /media/{id} | Wait for status: "ready". |
GET /media | GET /media | Search with search and filter with folder_id. |
GET /analytics/{integration} | GET /analytics/accounts | GET /analytics/overview gives workspace totals. |
GET /analytics/post/{postId} | GET /analytics/posts/{id} | GET /analytics/posts?ids= takes up to 100 post IDs. |
GET /notifications | None | Use webhooks or poll GET /posts?status=failed. |
POST /generate-video, POST /video/function, clipping endpoints | None |
Create a post
The same post in both APIs: a tweet scheduled for 08:00 UTC on November 2, 2026, that everyone can reply to.
Postiz:
Terminal
OmniSocials:
Terminal
Everyone can reply by default. To limit replies, set x.reply_settings to following or mentionedUsers.
To post to more channels, add them to accounts. Where Postiz needs a second posts[] entry for different text, OmniSocials uses one content object:
JSON
The response is a 201 with one post under data, not an array per channel. After publishing, published_urls on GET /posts/{id} maps each channel to its live URL.
Field mapping
| Postiz field | OmniSocials field | Notes |
|---|---|---|
type: "now" | publish_now: true | Or call POST /posts/create-and-publish. |
type: "schedule" with date | schedule_at | ISO 8601 in UTC. Alias: scheduled_at. |
type: "draft" | Leave out schedule_at and publish_now | draft: true with schedule_at keeps the time on the calendar without publishing. |
posts[].integration.id | accounts | Account id from GET /accounts, or the channel ID. Alias: channels. |
posts[].value[0].content | content, or content.<channel> for one channel | |
posts[].value[0].image[] | media_ids or media_urls | Use the id from an OmniSocials upload, or pass public URLs. Per-channel media is an object keyed by channel. |
image[].thumbnailTimestamp | video_cover | type: "frame" with thumb_offset in milliseconds. |
posts[].value[1..] | x.thread_parts and the like, or first_comment | See below. |
posts[].settings | A top-level object named after the channel | |
settings.__type | The channel ID | Rename linkedin-page to linkedin_page and gmb to google_business. |
who_can_reply_post (X) | x.reply_settings | following or mentionedUsers. Leave it out for everyone. |
shortLink | None | Links are posted as written. |
tags | None | |
posts[].group | None |
Threads and comments
In Postiz, extra entries in value become a thread or comments, depending on the platform. OmniSocials splits these two cases:
- Threads on X, Bluesky, Mastodon, and Threads use
thread_partsunder the channel key. Each part hastextand optionalmedia_idsormedia_urls. A thread has 2 to 25 parts. - One first comment on Instagram, Facebook, LinkedIn, YouTube, TikTok, and Telegram uses
first_commentunder the channel key. It is text only.
JSON
Chains of more than one comment have no equivalent. See X threads for the details.
Media and scheduling
Media. The upload calls map one to one. POST /media/upload takes a multipart file, and POST /media/upload-from-url takes { "url": "..." }. Both return the media record under data. Reference it on a post with media_ids: ["<data.id>"]. There is no path to send along. You can also skip uploads and pass public URLs in media_urls, up to 10 files of 100 MB each.
OmniSocials accepts JPEG, PNG, GIF, WebP, HEIC, MP4, MOV, AVI, and PDF. AVIF, BMP, and TIFF are not on that list, so convert them first. A PDF is turned into one image per page. On LinkedIn it publishes as a document. See Media.
Scheduling. Send schedule_at as an ISO 8601 time in UTC. OmniSocials publishes within one minute of that time. A time in the past returns 400 validation_error. To publish now, send publish_now: true.
Webhooks
Postiz webhooks are set up in the app, under Settings, and fire when a post publishes. OmniSocials webhooks are registered through the API with POST /webhooks. The response returns a secret once. Store it.
Terminal
| Event | When it fires |
|---|---|
post.scheduled | A post is scheduled through the API |
post.published | At least one channel published. A partial publish has data.status set to warning |
post.failed | Every channel failed |
post.approved | The last step of an approval workflow approved the post |
post.rejected | An approver rejected the post |
Every delivery is signed. X-OmniSocials-Signature: t=<timestamp>,v1=<hex> is an HMAC-SHA256 of the timestamp, a dot, and the raw body, keyed with your webhook secret. Verify it before you trust the payload, and deduplicate on X-OmniSocials-Delivery. Answer with a 2xx within 10 seconds. Failed deliveries are retried twice. See Webhooks for verification code.
Platform coverage
As of October 21, 2026, from docs.postiz.com and the OmniSocials platforms page.
| Platform | Postiz | OmniSocials |
|---|---|---|
Yes (facebook) | Yes (facebook), Pages | |
Yes (instagram, instagram-standalone) | Yes (instagram), Business and Creator accounts | |
| Threads | Yes (threads) | Yes (threads) |
Yes, profile (linkedin) and page (linkedin-page) | Yes, profile (linkedin) and page (linkedin_page) | |
| YouTube | Yes (youtube) | Shorts only (youtube) |
| TikTok | Yes (tiktok) | Yes (tiktok) |
Yes (pinterest) | Yes (pinterest) | |
| Bluesky | Yes (bluesky) | Yes (bluesky) |
| Mastodon | Yes (mastodon) | Yes (mastodon) |
| X | Yes (x) | Yes (x) |
| Google Business Profile | Yes (gmb) | Yes (google_business) |
| Telegram | Yes (telegram) | Yes (telegram), a channel or group |
Yes (reddit) | Coming soon | |
| Snapchat | Not listed | Coming soon |
| Discord, Slack | Yes | No |
| Farcaster, Nostr, VK, Lemmy | Yes | No |
| Twitch, Kick | Yes | No |
| Dribbble, Medium, Dev.to, Hashnode, WordPress, Tumblr, MeWe | Yes | No |
| Listmonk, Moltbook, Skool, Whop | Yes | No |
What is different
- Hosted only. OmniSocials has no self-hosted version.
- Account connection. OmniSocials has no connect-URL endpoint. Accounts are connected in the dashboard.
- One key per workspace. A Postiz key reaches the whole organization. An OmniSocials key reaches one workspace, so a multi-customer setup needs one key per customer.
- One account per channel. A workspace holds one account per channel ID. Two X accounts need two workspaces.
- One post, many channels. Per-channel text and settings live in objects keyed by channel, not in separate entries.
- Threads and comments. Threads work on X, Bluesky, Mastodon, and Threads. Other channels get one text-only first comment.
- Rate limit. OmniSocials allows 100 requests per minute per key, on every endpoint. Postiz limits only
POST /posts, per organization and per hour. Its docs give 30 and 90 requests per hour on different pages, and self-hosted instances set the value withAPI_LIMIT. See Rate limits and errors. - No tags, link shortening, video generation, or clipping.
GET /postshas no date range. Page through withstatus,limit, andoffset.- X links. X posts whose text contains a link use prepaid credits. Posts without a link do not. See X.
- Fewer channels. The channels in the last rows of the table above are not part of OmniSocials. YouTube is Shorts only, and Reddit is not live yet.
- No test mode. On OmniSocials, use drafts or a workspace with test accounts.
- What OmniSocials adds. Signed webhooks registered through the API, a Social inbox API for DMs and comments, approval workflows, alt text per image, PDF to carousel, hashtag sets, Instagram comment-to-DM automations, and SDKs in 8 languages.
Migration steps
- Create an OmniSocials account. Add one workspace per Postiz customer, or one for the whole organization if you use no customers.
- Connect each social account in the dashboard, under Settings → Organisation → Workspaces.
- Create one API key per workspace under Settings → API. Start with
posts:write,posts:read,media:write,accounts:read, andwebhooks:manage. - Call
GET /accountswith each key. Map every Postiz integrationidto an OmniSocials channel ID or accountid. - Change the base URL and add
Bearerbefore the key. - Rewrite the post body. Merge the
posts[]entries into oneaccountsarray and onecontentobject, and movesettingsto channel keys. Use the field mapping table. - Re-upload media with
POST /media/uploadorPOST /media/upload-from-url, and reference it withmedia_ids. - Register your webhooks with
POST /webhooks, and add signature verification. - Recreate the posts that are still queued in Postiz with
schedule_at. Then delete them in Postiz withDELETE /posts/{id}, so nothing publishes twice. - Test with drafts first, since there is no test mode. Then publish one post with
publish_now: trueand checkpublished_urlsonGET /posts/{id}.
Posts without schedule_at or publish_now are drafts and never publish on their own. Use them to check your field mapping against real accounts.