Migrate from Upload-Post to the OmniSocials API
This guide is for developers who post through the Upload-Post API and want to move to the OmniSocials API. Upload-Post has a separate multipart endpoint for each content type and picks the profile with a user field. OmniSocials has one JSON endpoint for every post type, and the API key itself picks the workspace. Media goes in as a URL or as an ID from an earlier upload. Social accounts are connected in the OmniSocials dashboard, not through a connect URL. Upload-Post facts on this page come from docs.upload-post.com and were checked on October 21, 2026.
Concepts
| Upload-Post | OmniSocials | Notes |
|---|---|---|
API key (Authorization: Apikey ...) | API key (Authorization: Bearer omsk_live_...) | An OmniSocials key belongs to one workspace. |
Profile (the user field, a username) | Workspace | Each workspace has its own API key. There is no user field. |
| Social accounts on a profile | Accounts in a workspace | One account per channel ID per workspace. |
Connect URL (generate-jwt, oauth/{platform}/start) | Dashboard connection | Accounts are connected only in the dashboard, never through the API. |
request_id and job_id | Post id | One ID for drafts, scheduled posts, and published posts. |
| Separate upload endpoints for video, photos, text, and documents | POST /posts/create | One endpoint. type picks a feed post, story, or reel. |
| Facebook page, LinkedIn page, and Google Business location IDs per request | Chosen when the account is connected | A workspace posts to one Facebook Page, one LinkedIn page, and one Google Business location. |
| Queue | None | GET /analytics/best-times recommends slots. You pick the time. |
Authentication
Text
With Upload-Post, one key serves every profile, and each request names the profile in user. An OmniSocials key is bound to one workspace, chosen when you create the key under Settings → API. To serve several brands, create one workspace and one key per brand, and store the key where you stored the Upload-Post username. 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. Upload-Post paths are relative to https://api.upload-post.com.
| Upload-Post | OmniSocials | Notes |
|---|---|---|
POST /api/upload (video) | POST /posts/create | Pass the video in media_urls or media_ids. Use type: "reel" for TikTok videos, Instagram reels, and YouTube Shorts. |
POST /api/upload_photos | POST /posts/create | Images in media_urls or media_ids. Two or more images publish as a carousel where the platform supports it. |
POST /api/upload_text | POST /posts/create | No media. Instagram, TikTok, Pinterest, and YouTube need media. |
POST /api/upload_document | POST /posts/create | Pass a PDF. On LinkedIn it publishes as a document. PPT and DOC files are not accepted. |
GET /api/uploadposts/status | GET /posts/{id} | Read status, published_urls, and errors. |
GET /api/uploadposts/schedule | GET /posts?status=scheduled | Page with limit (max 100) and offset. |
GET /api/uploadposts/schedule/<job_id> | GET /posts/{id} | |
PATCH /api/uploadposts/schedule/<job_id> | PATCH /posts/{id} | Drafts and scheduled posts only. Media and channels can change too. |
DELETE /api/uploadposts/schedule/<job_id> | DELETE /posts/{id} | Cancels a scheduled publish. On a published post it removes the post from OmniSocials only. |
GET /api/uploadposts/history | GET /posts?status=published | GET /posts/recent-platform reads recent posts made outside OmniSocials. |
GET /api/analytics/{profile_username} | GET /analytics/accounts, GET /analytics/overview | |
GET /api/uploadposts/post-analytics/{request_id} | GET /analytics/posts/{id} | GET /analytics/posts?ids= takes up to 100 post IDs. |
GET /api/uploadposts/me | GET /accounts | Returns the workspace and its connected accounts. |
GET /api/uploadposts/pinterest/boards | GET /accounts/{id} | A Pinterest account carries a boards array. Boards cannot be created through the API. |
GET /api/uploadposts/facebook/pages, GET /api/uploadposts/linkedin/pages | None | The page is chosen when the account is connected. |
POST /api/uploadposts/users and profile CRUD | None | Manage workspaces in the dashboard. |
POST /api/uploadposts/users/generate-jwt, POST /api/uploadposts/oauth/{platform}/start | None | Connect accounts in the dashboard. |
DELETE /api/uploadposts/users/social | None | Disconnect accounts in the dashboard. |
/api/uploadposts/queue/* | None | |
| Notification settings | POST /webhooks, GET, PATCH, DELETE /webhooks/{id} | See Webhooks. |
Create a post
The same post in both APIs: one video to TikTok and YouTube, scheduled for 08:00 UTC on November 2, 2026.
Upload-Post sends the file and the fields in one multipart request:
Terminal
OmniSocials takes JSON. Upload the file first, then create the post with the returned ID:
Terminal
Replace 123 with data.id from the upload response. If the video is already at a public URL, skip the upload and pass "media_urls": ["https://example.com/launch.mp4"] instead. On YouTube, content becomes the video description and youtube.title the title.
The create call answers with a 201 and the post under data. Publishing always runs in the background. Read the outcome with GET /posts/{id} or a post.published webhook.
Field mapping
| Upload-Post field | OmniSocials field | Notes |
|---|---|---|
user | None | The API key selects the workspace. |
platform[] | accounts | A JSON array. x and google_business keep their names. Alias: channels. |
video | media_urls or media_ids | A URL, or the ID of an earlier upload. The file itself is not sent in the post request. |
photos[] | media_urls or media_ids | Up to 10 URLs per post. |
document | media_urls or media_ids with a PDF | One image per page. A LinkedIn document on LinkedIn. |
title | content | The post text. A string, or an object with default and channel keys. |
[platform]_title, such as x_title | content.x, content.linkedin, and so on | Per-channel text. On YouTube, set the title in youtube.title. |
description | content | On YouTube, content becomes the description. |
scheduled_date | schedule_at | ISO 8601 in UTC. Alias: scheduled_at. |
timezone | None | Convert to UTC before you send. |
first_comment, [platform]_first_comment | first_comment under the channel key, such as instagram.first_comment | Instagram, Facebook, LinkedIn, YouTube, TikTok, and Telegram. |
privacy_level | tiktok.privacy_level, youtube.privacy_status | |
pinterest_board_id | pinterest.board_id | Required on every Pinterest post. |
facebook_page_id | None | The Page is chosen when Facebook is connected. |
target_linkedin_page_id | linkedin_page in accounts | linkedin is the personal profile. |
gbp_location_id | None | The location is chosen when Google Business is connected. |
add_to_queue, max_posts_per_slot | None | |
async_upload | None | Publishing is always asynchronous. |
external_id, request_id, Idempotency-Key | None | Store the returned post id next to your own ID. |
Media and scheduling
Media. Upload-Post takes the file inside the post request. OmniSocials keeps media and posts apart:
media_urlson the post. Pass public URLs and OmniSocials downloads them. Up to 10 files, each up to 100 MB.POST /media/upload. A multipart upload with afilefield, up to 100 MB. Usedata.idinmedia_ids.POST /media/upload-from-url. OmniSocials fetches a public URL of up to 1 GB. Files above about 100 MB come back withstatus: "processing". PollGET /media/{id}until it isready.POST /media/upload-from-base64. For a client that holds the file as base64.
A file in the library can be used on many posts, so upload once when the same video goes out more than once. The largest file OmniSocials takes is 1 GB. Platform limits, such as video length, are checked when a post is scheduled or published. See Media.
Scheduling. Send schedule_at as an ISO 8601 time in UTC. OmniSocials publishes within one minute of that time. There is no timezone field and no queue. A time in the past returns 400 validation_error. To publish now, send publish_now: true, or call POST /posts/create-and-publish. A post with neither schedule_at nor publish_now is saved as a draft.
Webhooks
Register a webhook with POST /webhooks. Webhooks belong to the workspace of the key that creates them. The response returns a secret once. Store it.
Terminal
| Upload-Post event | OmniSocials event | Notes |
|---|---|---|
upload_completed | post.published, post.failed | post.published fires when at least one channel succeeds. A partial publish has data.status set to warning. Check each entry in data.targets. |
social_account_connected, social_account_disconnected, social_account_reauth_required | None | Poll GET /accounts and check needs_reconnect. |
| None | post.scheduled | Sent when a post is scheduled through the API. |
| None | post.approved, post.rejected | Approval workflow outcomes. |
Signatures. Both APIs sign the same string: the timestamp, a dot, and the raw body, with HMAC-SHA256 and your webhook secret. Only the headers change. Upload-Post sends X-Upload-Post-Signature: sha256=<hex> and X-Upload-Post-Timestamp. OmniSocials sends one header, X-OmniSocials-Signature: t=<timestamp>,v1=<hex>. Deduplicate on X-OmniSocials-Delivery. See Webhooks for verification code.
Delivery. Answer with a 2xx within 10 seconds. Failed deliveries are retried twice, after 2 seconds and then 5 more. After that the event is dropped. Webhook URLs must use HTTPS.
Platform coverage
As of October 21, 2026, from docs.upload-post.com and the OmniSocials platforms page.
| Platform | Upload-Post | OmniSocials |
|---|---|---|
Yes (facebook) | Yes (facebook), Pages | |
Yes (instagram), no text-only posts | Yes (instagram), Business and Creator accounts | |
| Threads | Yes (threads) | Yes (threads) |
Yes (linkedin), profiles and pages | Yes, profile (linkedin) and company page (linkedin_page) | |
| YouTube | Yes (youtube) | Shorts only (youtube) |
| TikTok | Yes (tiktok) | Yes (tiktok) |
Yes (pinterest) | Yes (pinterest) | |
| Bluesky | Yes (bluesky) | Yes (bluesky) |
| X | Yes (x) | Yes (x) |
| Google Business Profile | Yes (google_business) | Yes (google_business) |
| Telegram | Yes (telegram) | Yes (telegram), a channel or group |
| Mastodon | Yes (mastodon) | Yes (mastodon) |
| Listed, currently unavailable | Coming soon | |
| Snapchat | Not listed | Coming soon |
| Discord | Yes (discord) | No |
| WordPress | Yes (wordpress) | No |
| Slack, Nostr, Lemmy, Dev.to, Hashnode, Whop, Listmonk | Text posts | No |
What is different
- Account connection. OmniSocials has no
generate-jwtor OAuth start endpoint. Accounts are connected in the dashboard. If your product lets end users connect their own accounts through your app, OmniSocials does not support that today. - No profiles API. Workspaces are created in the dashboard, and each API key reaches one workspace.
- One account per channel. A workspace posts to one account per channel ID, including one Facebook Page, one LinkedIn page, and one Google Business location. Pages cannot be picked per request.
- JSON, not multipart. Posts are JSON. Media is a URL or an ID from an earlier upload.
- File size. The largest file OmniSocials takes is 1 GB, through
upload-from-url. Direct uploads andmedia_urlsstop at 100 MB per file. - YouTube is Shorts only, up to 3 minutes. Documents must be PDF.
- Rate limit. OmniSocials allows 100 requests per minute per key. Upload-Post documents 60 to 1,000 requests per minute, by plan and number of profiles. Limits are per key on OmniSocials, so you can split heavy work across keys. See Rate limits and errors.
- No queue, timezone field, or idempotency key.
- X links. X posts whose text contains a link use prepaid credits. Posts without a link do not. See X.
- Fewer webhook events. There are no account events.
- Error shape. Upload-Post errors use
success,message, anderror_code. OmniSocials errors nest undererror, withcode,message, and optionaldetails. Branch onerror.code. - Fewer channels. Discord, WordPress, Slack, and the other text-only channels are not part of OmniSocials. Reddit is not live yet.
- No test mode. Neither API documents one. On OmniSocials, use drafts or a workspace with test accounts.
- What OmniSocials adds. A Social inbox API for DMs and comments, approval workflows with
post.approvedandpost.rejectedevents, alt text per image, PDF to carousel on Instagram, TikTok, Threads, and Pinterest, hashtag sets, and Instagram comment-to-DM automations.
Migration steps
- Create an OmniSocials account. Add one workspace for each Upload-Post profile.
- Connect each social account in the dashboard, under Settings → Organisation → Workspaces. Pick the Facebook Page, LinkedIn page, and Google Business location there.
- Create one API key per workspace under Settings → API. Start with
posts:write,posts:read,media:write,accounts:read, andwebhooks:manage. - Replace each Upload-Post username in your config with that workspace's key.
- Call
GET /accountswith each key to see the connected channels. For Pinterest, copy the board IDs fromGET /accounts/{id}. - Replace the four upload calls with one
POST /posts/create. Send JSON. Move files tomedia_urls, or upload them first and passmedia_ids. Rename the fields with the field mapping table. - Convert
scheduled_dateandtimezoneto a UTCschedule_at. - Register your webhooks with
POST /webhooks. Swap the signature check and map the events. - Recreate the posts that are still scheduled in Upload-Post with
schedule_at. Then cancel them withDELETE /api/uploadposts/schedule/<job_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.