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
Information
Posts
    List postsgetList live platform postsgetGet a postgetDelete a postdeleteUpdate a postpatchCreate a postpostCreate and publish postpostPublish a post nowpostRetry failed postpostApprove a postpostReject a postpostGet approval reviewget
Media
    List mediagetGet a media itemgetDelete a media itemdeleteRename or move mediapatchUpload a filepostUpload from base64postUpload from a URLpostCreate an upload URLpostSplit a PDF into pagespostCheck media limitspostUpload with a tokenpost
Folders
    List foldersgetCreate a folderpostDelete a folderdeleteRename or move a folderpatch
Hashtag Sets
    List hashtag setsgetCreate a hashtag setpostGet a hashtag setgetDelete a hashtag setdeleteUpdate a hashtag setpatch
Accounts
    List accountsgetGet an accountget
Analytics
    Get bulk post analyticsgetGet post analyticsgetGet analytics overviewgetGet account analyticsgetGet best posting timesget
Approvals
    List approval workflowsget
Webhooks
    List webhooksgetCreate a webhookpostGet a webhookgetDelete a webhookdeleteUpdate a webhookpatchRotate webhook secretpost
Locations
    Search locationsgetValidate a locationget
Audio
    Search Instagram audioget
Pinterest
    List product PinsgetCheck a product Pinget
Inbox
    List conversationsgetList messagesgetMark conversation readpostReply to a conversationpostHide or unhide a commentpostDelete a commentdeleteGet next conversationget
Automations
    List automationsgetCreate an automationpostGet an automationgetDelete an automationdeleteUpdate an automationpatchList automation eventsget
Schemas
OmniSocials API
OmniSocials API

Schemas

Download schema

Error

​object

Pagination

total
​integer

Total number of items

Example: 42
limit
​integer

Items per page

Example: 20
offset
​integer

Number of items skipped

Example: 0
has_more
​boolean

Whether there are more items

Example: true

Post

id
​string

Post ID

Example: 1024
status
​string · enum

in_approval = waiting for a reviewer in an approval workflow; PATCH /posts/{id} can still move its schedule_at without changing this status. rejected = an approver declined the post via POST /posts/{id}/reject; it will not be published. posting = a publish is in flight. warning = some platforms published and some failed (see errors for the failures, published_urls for the successes); retry the failures with POST /posts/{id}/retry. failed = every platform failed. NOTE: a failed post whose dashboard 'retry as new post' succeeded flips to published even though it has no published_urls of its own. Check retries for the post that actually carries the live URLs.

Enum values:
draft
in_approval
scheduled
posting
published
failed
warning
rejected
type
​string · enum

Post type. 'reel' media must be a video (MP4/MOV): an image is rejected with 400 validation_error at schedule/publish; use 'post' to share an image. A 'story' carries 1 to 10 media items; every item is one slide and publishes as its own story, in order.

Enum values:
post
story
reel
​object

Stories only, after publishing. Per-platform list of the published slides in publish order. published_urls keeps the first slide's URL per platform; this field has every slide.

content
​object

Post content per platform

Example: {"default":"Our autumn menu is here.","instagram":"Our autumn menu is here. #autumnmenu"}
​object

The channels the post targets, as a map of platform key to true or false. Every platform key is present; the channels the post publishes to are true. Requests send accounts as an array of account IDs instead (POST /posts/create, PATCH /posts/{id}).

Example: {"instagram":true,"linkedin_page":true,"facebook":false,"x":false}
​object

Per-platform media object. Keys: default, instagram, facebook, etc. Each value is an array of {url, id, channel, alt?}.

Example: {"default":[{"url":"https://cdn.omnisocials.com/file/library-omnisocials/312a658f-2b45-4289-b240-890807221a74/library/1792573200000-k3j9xq_0c9e6b1a-2f4d-4b8e-a7c3-9d1e5f6a2b70.jpg","id":"482913","alt":"A bowl of pumpkin soup on a wooden table"}]}
location_id
​string

Instagram location tag (Facebook Place/Page ID), echoed back from the create/update request. Omitted when not set.

Example: 1234567890
collaborators
​string[]

Instagram co-author usernames (the 'Collab' feature), echoed back from the create/update request. Omitted when none set.

​object[]

Instagram photo user tags, echoed back from the create/update request. Omitted when none set.

schedule_at
​string · date-time

Scheduled publish time (ISO 8601)

Example: 2026-10-21T09:00:00.000Z
app_url
​string · uri

Deep link to open this post inside the OmniSocials app, correct for the environment (staging vs production). Draft, scheduled, and failed posts open in the composer; published posts open in the details view. Hand this to the user so they can click straight through to review a draft you just created.

Example: https://app.omnisocials.com/create-post/1024
​object

Live URLs of the post on each platform after publishing. Keys are platform identifiers (facebook, instagram, linkedin, linkedin_page, youtube, tiktok, pinterest, x, threads, bluesky, mastodon, google_business, telegram, discord). Only platforms that successfully published appear; failed platforms are omitted (see errors). Empty object {} while the post is still draft, scheduled, or processing.

Example: {"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","x":"https://x.com/yourhandle/status/1791234567890123456"}
retry_of
​string

Present when this post was created by the dashboard 'retry as new post' flow: the ID of the original failed post it retries. The live platform URLs are on THIS post's published_urls.

Example: 1023
retries
​string[]

Present on a post that has been retried as a new post: the IDs of its retry posts (newest last). A published post with empty published_urls and retries set is a resolved failure: the actual publish lives on the retry post, so don't double-count it.

created_at
​string · date-time
approval_status
​string | null · enum

Approval workflow status. none = no approval workflow attached. pending = waiting on an approver (post status is in_approval); act on it with POST /posts/{id}/approve or /reject. approved / rejected = the workflow finished. GET /posts/{id}/approval returns the review itself: steps, approvers, the rejection reason and the comments.

Enum values:
none
pending
approved
rejected
​object | null

Per-platform user-friendly error messages, keyed by platform identifier (facebook, instagram, linkedin, linkedin_page, youtube, tiktok, pinterest, x, threads, bluesky, mastodon, google_business). Populated when status is failed or warning. Only platforms that failed appear; successful platforms are omitted (see published_urls). null while the post is still draft/scheduled/processing or every platform succeeded. A platform's entry is removed once a retry of it succeeds (via POST /posts/{id}/retry or the dashboard). Mirrors the per-platform error a user sees in the dashboard with a Retry button.

Example: {"facebook":"Already Posted: These photos were already posted.","instagram":"Instagram couldn't accept one of your images. Check that every image is JPEG/PNG, at least 320×320, has an aspect ratio between 4:5 and 1.91:1, and isn't visually flagged by Instagram. Re-upload or replace the offending image and try again."}
source
​string | null

Origin of post creation: web, api, mcp, workflow, zapier, make, n8n, etc.

Example: api
updated_at
​string · date-time
x
​object | null

X (Twitter) options on the post. Includes per-publish settings (reply_settings, made_with_ai, paid_partnership), the poll and the canonical thread shape. Present when the post has X-specific data; omitted otherwise.

bluesky
​object | null

Bluesky options on the post. Present when the post is a Bluesky thread; omitted otherwise.

mastodon
​object | null

Mastodon options on the post. Present when the post is a Mastodon thread or carries a poll; omitted otherwise.

threads
​object | null

Threads options on the post. Present when the post is a Threads thread (multi-post chain), carries a location tag or a poll; omitted otherwise.

telegram
​object | null

Telegram options on the post, and after publishing the result. Omitted when none are set.

discord
​object | null

Discord options on the post, and after publishing the result. Omitted when none are set.

instagram
​object | null

Instagram options on the post. Present when set; includes first_comment (the configured auto first comment) and, after publish, first_comment_result describing the outcome.

​object

The post's video cover exactly as stored; null when none was chosen.

Example: {"type":"frame","thumb_offset":3000,"overrides":{"linkedin_page":{"type":"custom","cover_url":"https://example.com/cover.jpg"}}}
facebook
​object | null

Facebook options on the post: first_comment, its post-publish first_comment_result, and the video thumbnail (thumbnail_type + thumb_offset / cover_url) when one is set.

linkedin
​object | null

LinkedIn Profile options on the post: first_comment, its post-publish first_comment_result, carousel_as_images (present when the post opts out of the default PDF document carousel) and document_source (present as slides when the post opts out of sending the kept original PDF).

linkedin_page
​object | null

LinkedIn Company Page options on the post: first_comment, its post-publish first_comment_result, carousel_as_images (present when the post opts out of the default PDF document carousel) and document_source (present as slides when the post opts out of sending the kept original PDF).

youtube
​object | null

YouTube options on the post. After publish, first_comment and its first_comment_result are nested here alongside the Shorts metadata.

tiktok
​object | null

TikTok options on the post. After publish, first_comment and its first_comment_result are nested here alongside the TikTok publish options. First comments need the workspace's TikTok comments authorization.

​object

The comment-to-DM setup bound to this post, when one exists. Returned by GET /posts/{id} for a post that goes to Instagram or Facebook, and by create and update when the request carried comment_dm_automation. The fields are those of the first automation (Instagram first), plus platforms and automations (one per channel). Its post field is null here (the post is this one).

FirstCommentResult

Outcome of an auto first-comment attempt, written after the main post publishes.
status
​string · enum

posted = comment is live; failed = the main post published but the comment did not (see error; retry via POST /posts/retry-first-comment); skipped = the main post did not publish so the comment was never attempted.

Enum values:
posted
failed
skipped
pending
​boolean | null

TikTok only. true while the comment waits for TikTok to return the final video id (status is failed with an explanatory error meanwhile); the comment is posted automatically once the id resolves, usually within minutes.

Example: false
comment_id
​string | null
url
​string | null
error
​string | null
posted_at
​string | null · date-time

VideoCoverEntry

type
​string · enum · required

frame uses the video frame at thumb_offset; custom uploads the image at cover_url.

Enum values:
frame
custom
thumb_offset
​integer · min: 0

Milliseconds into the video (type frame).

Example: 3000
cover_url
​string · uri

Public image URL, JPEG or PNG (type custom).

Example: https://example.com/cover.jpg

VideoCover

Video thumbnail for a post whose media is one video. Applied on Instagram (feed videos and reels), Facebook (feed videos and reels), LinkedIn Profile and Page, TikTok, Pinterest and YouTube Shorts. On YouTube Shorts the cover shows only on channels where YouTube has enabled custom Shorts thumbnails (rolling out since July 2026, YouTube Partner Program channels first); on other channels YouTube stores it as the default thumbnail but shows a frame from the video on Shorts. TikTok only takes a frame, so a `custom` cover is skipped there (set a `tiktok` override with type `frame` to choose the frame). The per-platform reel fields (`instagram.thumb_offset` / `cover_url`, `tiktok.video_cover_timestamp_ms`, `pinterest.video_cover`) keep working and win over the base cover for their platform.
type
​string · enum · required

frame uses the video frame at thumb_offset; custom uploads the image at cover_url.

Enum values:
frame
custom
thumb_offset
​integer · min: 0

Milliseconds into the video (type frame).

Example: 3000
cover_url
​string · uri

Public image URL, JPEG or PNG (type custom).

Example: https://example.com/cover.jpg
​object

Per-platform overrides keyed by platform id (instagram, facebook, linkedin, linkedin_page, tiktok, pinterest, youtube). An override wins over the base cover for that platform.

LinkedInPollFields

question
​string · maxLength: 140 · required

The poll question.

Example: Which feature should we build next?
options
​string[] · minItems: 2 · maxItems: 4 · required

2-4 answer options.

duration
​string · enum · required

How long the poll stays open for votes.

Enum values:
ONE_DAY
THREE_DAYS
SEVEN_DAYS
FOURTEEN_DAYS

XPoll

A poll on an X post. The tweet text is the question. Stored as `x.poll`.
options
​string[] · minItems: 2 · maxItems: 4 · required

2 to 4 answer options of up to 25 characters, all different.

duration_minutes
​integer · min: 5 · max: 10080

How long the poll stays open, in minutes (5 to 10080, 7 days).

Default: 1440

ThreadsPoll

A poll on a Threads post. The post text is the question; Threads closes the poll 24 hours after it is published. Stored as `threads.poll`.
options
​string[] · minItems: 2 · maxItems: 4 · required

2 to 4 answer options of 1 to 25 characters, all different.

MastodonPoll

A poll on a Mastodon status. The status text is the question. Limits come from the instance (Mastodon's defaults: 4 options of 50 characters, 5 minutes to 1 month). Stored as `mastodon.poll`.
options
​string[] · minItems: 2 · required

The answer options, all different; count and length within the instance's limits.

expires_in
​integer

How long the poll stays open, in seconds, within the instance's range (default one day).

Default: 86400
multiple
​boolean

Allow several answers per person.

Default: false
hide_totals
​boolean

Hide the vote counts until the poll ends.

Default: false

TelegramPoll

A poll in a Telegram channel or group. The post text is the question (up to 300 characters). Polls in a channel are anonymous. Stored as `telegram.poll`.
options
​string[] · minItems: 2 · maxItems: 12 · required

2 to 12 answer options of up to 100 characters, all different.

open_period
​integer · min: 5 · max: 2628000

Seconds the poll stays open (5 seconds to about 30 days). Leave out to keep the poll open.

Example: 86400
multiple
​boolean

Allow several answers per person.

Default: false

TelegramButton

text
​string · maxLength: 64 · required

Button label.

Example: See the menu
url
​string · uri · required

Link the button opens: https://, http:// or tg://.

Example: https://example.com/menu

DiscordPoll

A native Discord poll. The post text is the question (1 to 300 characters). No media and no buttons with a poll. Stored as `discord.poll`.
options
​string[] · minItems: 2 · maxItems: 10 · required

2 to 10 answer options of up to 55 characters, all different.

duration_hours
​integer · min: 1 · max: 768

Hours the poll stays open (1 hour to 32 days).

Example: 24
Default: 24
multiple
​boolean

Allow several answers per person.

Default: false

DiscordButton

text
​string · maxLength: 80 · required

Button label (1 to 80 characters).

Example: See the menu
url
​string · uri · required

Link the button opens: https:// or http://.

Example: https://example.com/menu

CreatePostRequest

content
​object · required

Post content. Use 'default' for all platforms, or platform-specific keys: instagram, facebook, linkedin, linkedin_page, youtube, tiktok, pinterest, x, threads, bluesky, mastodon, google_business, telegram, discord. Coming soon: reddit, snapchat.

Example: {"default":"Hello world!","instagram":"Hello from IG! #awesome"}
accounts
​string[] · required

Social accounts to post to. Each entry is either:

  • A bare platform name (e.g. "youtube", "linkedin_page"), or
  • The composite ID returned by GET /v1/accounts in the form "<workspace_id>_<platform>" (e.g. "844008_youtube").

The composite form's workspace prefix must match the workspace your API key belongs to. Mismatched or unknown ids return 400 validation_error with an "Unknown account/platform" message. Always source ids from GET /v1/accounts for the API key in use.

type
​string · enum

Post type: 'post' (feed), 'story' (Instagram/Facebook), 'reel' (Instagram/Facebook/YouTube/TikTok). Telegram and Discord have no reels: a reel that names them is still accepted, and they get the video as a normal post; send a video for them alone as a 'post'. A 'reel' must have video media (MP4/MOV); an image is rejected with 400 validation_error at schedule/publish. Use 'post' to share an image. A 'story' takes 1 to 10 media items: each item is one slide, published as its own story in the order given (Instagram and Facebook have no multi-slide story container). More than 10 returns 400 validation_error.

Enum values:
post
story
reel
Default: post
​

Media IDs from POST /media/upload. Flat array or per-platform object. Any entry may be an { id, alt } object to carry a per-media accessibility description (alt text, max 1500 chars). For type 'story', each item is one slide (max 10, published in order).

​

External image/video/PDF URLs to download and attach (max 10 total, each file ≤ 100 MB). Flat array or per-platform object. Any entry may be a { url, alt } object to carry a per-media accessibility description (alt text, max 1500 chars), delivered to Mastodon, Bluesky, X, Pinterest, Instagram (images) and LinkedIn (images). When using per-platform format, 'default' acts as fallback for selected platforms without their own key. A PDF URL is rasterized into one image slide per page (max 20, in order). On LinkedIn it publishes as a swipeable document, elsewhere as an image carousel; slides inherit the entry's alt. For files over 100 MB (up to 1 GB), upload first via POST /v1/media/upload-from-url and attach the returned media id via the media field; oversized media_urls fail with code file_too_large.

schedule_at
​string · date-time

ISO 8601 datetime to schedule. Omit for a draft without a date. With draft: true the time is kept but the post stays a draft (a planned draft on the calendar, see draft).

Example: 2026-10-21T09:00:00Z
draft
​boolean

Planned draft. With schedule_at, the post is stored as draft and keeps that time: it shows on the dashboard calendar at that slot with a dashed outline, the scheduler never publishes it, and a person schedules it from the composer (or you do with PATCH /posts/{id} and draft: false). Use it when an agent proposes a slot that a human should confirm. Not allowed with publish_now or approval_workflow_id (400 validation_error). Without schedule_at it changes nothing: that post is a draft already.

Example: true
​object

Image fit per channel, for feed images (type post) whose ratio is outside what a channel shows uncropped. auto (the default when omitted) takes the channel's rule: Instagram crops a tall or wide image to 4:5 / 1.91:1 around the subject (Instagram cuts it to that window anyway, and Meta cannot boost a feed post outside it); Pinterest keeps a Pin taller than 2:3 and only reports it. crop crops for that channel, keep sends the original. Every decision is reported in the response warnings with code: "image_fit". The crop is a file of its own for that channel only; default and the other channels keep the original. On PATCH, media_fit alone (no media) re-decides the stored images: keep gives the original back, crop crops an image that was kept.

Example: {"instagram":"keep"}
publish_now
​boolean

Set true to publish immediately

Example: false
link_url
​string · uri

URL to share as a rich preview card on platforms that support link-share posts (currently LinkedIn and Facebook). When set on a text post, the URL renders as a preview tile with thumbnail / title / description instead of plain text. Ignored on platforms that don't support link shares (Instagram, TikTok, etc.) and on posts that already have media attached (media takes precedence).

Example: https://goodlightai.com/blog/new-feature
link_title
​string

Optional title for the link-share preview. LinkedIn uses this directly when set. Facebook ignores this: it fetches OG metadata server-side. Omit to let LinkedIn auto-fetch the page title.

Example: Our autumn menu
link_description
​string

Optional description for the link-share preview. LinkedIn uses this when set; Facebook auto-fetches the OG description. Omit to defer to OG metadata.

Example: Six new dishes, available from today.
link_thumbnail_url
​string · uri

Optional thumbnail image URL for the preview card. LinkedIn uploads this image as the card thumbnail; without it, LinkedIn uses the page's Open Graph image, and when the upload fails the card has no image. Facebook ignores it and uses the page's Open Graph image.

Example: https://example.com/preview.jpg
​VideoCover

Video thumbnail for a post whose media is one video. Applied on Instagram (feed videos and reels), Facebook (feed videos and reels), LinkedIn Profile and Page, TikTok, Pinterest and YouTube Shorts. On YouTube Shorts the cover shows only on channels where YouTube has enabled custom Shorts thumbnails (rolling out since July 2026, YouTube Partner Program channels first); on other channels YouTube stores it as the default thumbnail but shows a frame from the video on Shorts. TikTok only takes a frame, so a custom cover is skipped there (set a tiktok override with type frame to choose the frame). The per-platform reel fields (instagram.thumb_offset / cover_url, tiktok.video_cover_timestamp_ms, pinterest.video_cover) keep working and win over the base cover for their platform.

Example: {"type":"frame","thumb_offset":3000,"overrides":{"linkedin_page":{"type":"custom","cover_url":"https://example.com/cover.jpg"}}}
source
​string

Self-reported origin of the integration creating this post. Defaults to 'api' if omitted. Use 'zapier', 'make', 'n8n', etc. to identify your integration.

Example: zapier
location_id
​string

Instagram only. Facebook Place/Page ID to tag the post's location with (e.g. a dealership or storefront). Applied to single-image and carousel feed posts via Instagram's content-publishing location_id. Find a Place's Page ID via Facebook's Pages Search API. Ignored by other platforms. Send an empty string on PATCH to clear it.

Example: 1234567890
collaborators
​string[] · maxItems: 3

Instagram only. Up to 3 public Instagram usernames to invite as co-authors (the 'Collab' feature). Applied to image, carousel, and reel posts, not Stories. Invited users get an invitation in the Instagram app; once accepted, the post also appears on their profile and feed. Usernames are case-insensitive and a leading '@' is stripped. Private accounts and non-existent usernames are rejected by Instagram at publish time. Ignored by other platforms. Send an empty array on PATCH to clear collaborators.

Example: ["therock","kevinhart4real"]
​object[]

Instagram only. Tag public Instagram accounts at specific positions on a photo. Photos only, not video, reels, or stories. For a single image omit image_index (or set 0); for a carousel, set image_index to the 0-based slide the tag belongs to (tags attach to that slide's image). Public accounts only; private/non-existent usernames are rejected by Instagram at publish time. Ignored by other platforms. Send an empty array on PATCH to clear tags.

Example: [{"username":"therock","x":0.5,"y":0.8}]
hashtag_set
​string

Name of a saved hashtag set (see GET /hashtag-sets) to apply to this post, matched case-insensitively. The set's tags are merged in ONCE at create time: the post stores plain text, so later edits to the set never change this post. Tags already present in a caption are skipped (case-insensitive), and hard platform caps (Instagram 30) are enforced with a 400 hashtag_limit_exceeded before the platform can reject the post. Mutually interchangeable with hashtag_set_id.

Example: Fitness Brand
hashtag_set_id
​string

Id of a saved hashtag set to apply. Same behavior as hashtag_set; pass one or the other.

Example: 57
hashtag_placement
​string · enum

Where the set's tags land. caption_append (default) appends them to each target platform's caption after a blank line. first_comment puts them in the auto first comment on comment-capable platforms (Instagram, Facebook, LinkedIn Profile/Page, YouTube, TikTok with comments enabled, Telegram), appended after any first_comment you passed explicitly, and falls back to caption_append on platforms without a comment API. Stories always use captions (first comments are never posted on Stories).

Enum values:
caption_append
first_comment
Default: caption_append
hashtag_platforms
​string[]

Optional subset of the post's selected platforms to apply the set to (e.g. only ["instagram", "tiktok"]). Defaults to all selected platforms.

approval_workflow_id
​string

Id of an approval workflow (see GET /approval-workflows) to route this post through. The post is created with status in_approval and approval_status: pending instead of scheduled: the workflow's first-step approvers are notified (dashboard badge, email, Slack), they review it in the dashboard's Approvals page, and it publishes at schedule_at only once the last step approves it (dashboard, or POST /posts/{id}/approve). A rejection leaves it rejected. Requires schedule_at; cannot be combined with publish_now. Errors: 404 workflow_not_found (not a workflow of this company/workspace), 400 validation_error (missing schedule_at, publish_now set, or the workflow has no approvers on its first step).

Example: 57823504
comment_dm_automation
​object | null

A comment-to-DM automation bound to this post (Instagram or Facebook must be in accounts). When somebody comments one of trigger.keywords on the post once it is live, the account DMs them actions.dm.text, once per person, and optionally posts one of actions.public_reply.variations under the comment. On a Facebook Page the DM lands in Messenger. The shape is the AutomationInput of POST /automations without post_id, scope or kinds (always this post, comment trigger), plus platforms. The created automations come back as comment_dm_automation on the post. Needs the opt-in automations:write scope on the API key (403 insufficient_scope without it).

Example: {"trigger":{"keywords":["guide"]},"actions":{"dm":{"text":"Here is the guide: https://example.com/guide"},"public_reply":{"enabled":true,"variations":["Sent you a DM!"]}},"limits":{"max_sends":500}}
​object

Pinterest-specific options. Attach 2–5 images via media_urls.pinterest (or the flat media_urls) to publish a single carousel pin; the title, description, link, and alt_text apply to the whole pin. A single image or a single video still publishes as a normal image / video pin. Carousel constraints: carousels hard-cap at 5 images: attaching more responds 400 validation_error at create/schedule time. Pinterest's v5 API also requires every slide in a carousel pin to share the same aspect ratio (1% tolerance). If you attach mixed-ratio images and try to schedule or publish, the API responds 400 validation_error with mismatched_slides: [n, ...] listing the 1-indexed slide numbers that need to be re-cropped or removed. Both checks run when publish_now: true, when schedule_at is set, and when PATCH flips a draft to a scheduled status. Drafts are exempt so you can iterate on media.

​object

YouTube Shorts options. Only applies when type is reel and youtube is among the selected accounts.

​object

Instagram Reel options

​object

Facebook options

​object

LinkedIn Profile options

​object

LinkedIn Company Page options

linkedin_poll
​object | null

Non-sponsored LinkedIn poll(s), independent per channel, keyed by linkedin (personal profile) / linkedin_page (company page). A poll is mutually exclusive with media and a link share on that channel's post: a poll takes priority over both at publish time. Requires content.linkedin (or content.default) as that channel's caption/commentary; the poll itself only carries the question/options/duration.

​object

TikTok options

​object

X (Twitter) options

​object

Bluesky options

​object

Mastodon options

​object

Telegram options (2026-10-17). Telegram posts go to the connected channel or group through the OmniSocials bot. Text up to 4,096 characters; with media, text over 1,024 characters is sent as a reply under the media (Telegram's caption limit). Media: up to 10 photos and videos (an album), one GIF, one video up to 50 MB, or files. No Stories. Views are not available to bots: analytics report reactions and subscribers.

​object

Discord options (2026-10-22). Discord posts go to the channel the workspace connected, through that channel's webhook; the message shows the webhook's name and picture. Text up to 2,000 characters. Media: up to 10 images, GIFs and videos in one message (they may mix). A file over Discord's 20 MB attachment limit is sent differently: an image is re-encoded to fit, a video or GIF goes as a link in the text (listed in discord.result.video_links). No Stories; a reel is sent as one video message. Statistics: reactions and poll votes only (Discord gives webhooks no views). A sent message can be deleted at any time.

Example: {"silent":true,"link_preview":false,"buttons":[{"text":"Book a table","url":"https://example.com/book"}]}
​object

Threads options: thread mode via thread_parts, location tag via location_id, poll via poll.

​object

Google Business Profile options. Use to publish EVENT or OFFER posts in addition to STANDARD, attach a call-to-action button, or both. STANDARD posts can also use this object purely to add a CTA. The shape mirrors Google's LocalPost JSONB exactly; see https://developers.google.com/my-business/reference/rest/v4/accounts.locations.localPosts#LocalPost.

Caption rules, enforced at scheduling (text that violates these returns validation_error 400 before the post is saved): • No phone numbers in the caption (use a CALL button instead). • No inline URLs / bare domains / email addresses (use a LEARN_MORE, BOOK, SHOP, SIGN_UP, or ORDER button instead). • Caption max 1500 characters. • Media optional (text-only posts allowed). If attached: exactly one JPEG/PNG/WebP image (no video, no carousels). • The workspace must have a Google Business location selected (Settings → Organisation → Workspaces → Google Business) before scheduling.

Media

id
​string

Media ID (use this in post creation)

Example: 482913
url
​string

Permanent CDN URL for the media

Example: https://cdn.omnisocials.com/file/library-omnisocials/312a658f-2b45-4289-b240-890807221a74/library/1792573200000-k3j9xq_0c9e6b1a-2f4d-4b8e-a7c3-9d1e5f6a2b70.jpg
thumbnail_url
​string | null

CDN URL of the generated preview thumbnail (videos only; null for images, which use url directly)

Example: https://cdn.omnisocials.com/file/library-omnisocials/312a658f-2b45-4289-b240-890807221a74/library/thumbnails/1792573200000-k3j9xq_0c9e6b1a-2f4d-4b8e-a7c3-9d1e5f6a2b70_thumbnail.webp
type
​string · enum

document is a PDF kept as one item (see pdf): its id in media_ids expands into every page image, in order.

Enum values:
image
video
document
name
​string | null

Human-readable label set on upload or via PATCH (e.g. "pp-play5get50"). Falls back to the storage filename when unset. Search this with the search query param.

Example: autumn-menu-hero
folder_id
​string | null

Id of the folder this file lives in, or null for the root ("All media")

Example: 12
filename
​string

Generated storage filename (stable, used internally)

Example: 0c9e6b1a-2f4d-4b8e-a7c3-9d1e5f6a2b70.jpg
size
​string

Human-formatted file size (e.g. "2.50 MB")

Example: 2.50 MB
status
​string · enum

Processing state. 'ready' for normal uploads (usable immediately). Large videos uploaded via URL ingestion (over 100 MB) start as 'processing': poll get media / list media until 'ready' before using them in a post. 'failed' means the source couldn't be fetched or validated.

Enum values:
ready
processing
failed
created_at
​string · date-time
​object

Present on a PDF document item (type document): the kept file and its rendered pages in order. Also present on a slide rendered from a PDF (type image): which original file and page it came from. The original PDF is kept in storage. When a LinkedIn post's images are exactly the rendered pages of one PDF, in order and unchanged, LinkedIn receives that original file (sharp text, working in-document links, the real download) instead of a document rebuilt from the page images. Opt out per channel with document_source: "slides" on the post's linkedin / linkedin_page options.

MediaCompatibility

Whether the file fits the platforms connected to your workspace. `compatible` is true when no connected platform would reject it.
compatible
​boolean
​object[]
summary
​string | null

One-line human summary, or null when fully compatible.

Example: This file (450 MB) won't post to: Instagram (max 300 MB).

PdfUploadResult

Returned when the uploaded file is a PDF. With `pdf_mode: slides` (the default) the server rasterizes each page into an image slide and stores each as its own media item, and keeps the original PDF too. `data` mirrors the FIRST slide (so callers that read a single Media still work); `slides` and `media_ids` carry the whole carousel in page order. Pass ALL of `media_ids` to POST /posts as a carousel. With `pdf_mode: document` the response has no `slides`: `data` is the single document item (type `document`, pages in `data.pdf.pages`) and `media_ids` holds its one id, which expands into every page at post time. On LinkedIn it posts as a swipeable document made from the original PDF file (text stays sharp, links keep working, viewers download the real file); on Instagram, TikTok, Threads and Pinterest as an image carousel. Slides are capped at 20 pages; the original sent to LinkedIn is the whole file.
​Media
​Media[]

Every page as a Media item, in page order.

media_ids
​string[]

Slide ids in page order. Pass all of them to POST /posts.

​object
​MediaCompatibility

Whether the file fits the platforms connected to your workspace. compatible is true when no connected platform would reject it.

message
​string

Folder

id
​string
name
​string
parent_id
​string | null

Parent folder id, or null for a top-level folder

item_count
​integer

Number of media items directly in this folder

created_at
​string · date-time

HashtagSet

id
​string
name
​string

Set name, unique per workspace (case-insensitive)

hashtags
​string[]

Ordered tags WITHOUT the leading '#'

hashtag_count
​integer
preview
​string

The tags rendered as caption text, e.g. "#fitness

created_at
​string · date-time
updated_at
​string · date-time

ApprovalWorkflowApprover

id
​string · uuid

User id of the approver

name
​string | null
email
​string | null

ApprovalWorkflowStep

order
​integer

1-based step order; steps are approved in order

name
​string
require_mode
​string · enum

any = one approver of this step is enough; all = every approver must approve

Enum values:
any
all
​ApprovalWorkflowApprover[]

ApprovalWorkflow

id
​string

Pass this as approval_workflow_id on POST /posts/create

Example: 57823504
name
​string
workspace_id
​integer | null

Workspace the workflow is bound to, or null when it is available to every workspace of the company

​ApprovalWorkflowStep[]
created_at
​string · date-time
updated_at
​string · date-time

Account

id
​string

Account ID (use this when creating posts)

Example: 1234_instagram
platform
​string · enum
Enum values:
instagram
facebook
linkedin
linkedin_page
youtube
tiktok
pinterest
bluesky
username
​string | null

Social media username/handle. Null where the account has none, such as a Discord channel (a server has no handle; the webhook name posts show is in platform_details.webhook_name).

Example: yourbrand
display_name
​string

Display name on the platform. Discord: the server name for a connection made with Continue with Discord, the webhook name for a pasted webhook URL.

Example: Your Brand
profile_picture
​string

Profile picture URL

Example: https://example.com/avatar.jpg
content_types
​string[]

Supported content types for this platform

Enum values:
post
story
reel
status
​string · enum

Connection status. needs_reconnect means the account is still wired up to the workspace but its OAuth token has been revoked or expired; posts to this account will fail until the user reconnects in the OmniSocials UI. Most often caused by the user changing their password, deauthorizing OmniSocials on the platform, or the token expiring without a successful refresh.

Enum values:
active
needs_reconnect
needs_reconnect
​boolean

Convenience boolean: true when status is needs_reconnect.

Example: false
reauth_reason
​string | null

Short reason from the platform (e.g. "OAuthException: Session has expired"). Present only when needs_reconnect is true. Token-health tracking exists for Instagram, Facebook, Threads, X, Pinterest, LinkedIn (profile + page), Telegram (the bot was removed or lost the right to post) and Discord (the webhook was deleted in Discord); other platforms always report needs_reconnect: false.

Example: OAuthException: Session has expired
​object[]

Pinterest boards (only present for Pinterest accounts). Use board id as board_id when creating Pinterest posts.

​object

Platform-specific details. Present for X accounts with a Premium subscription, and for every Telegram and Discord account.

connected_at
​string · date-time

PostAnalytics

post_id
​string
​object

One entry per platform the post was published to. For thread platforms (X, Bluesky, Mastodon, Threads) a post can publish as a chain of several parts; the entry sums each part's metrics so you get the thread's total (matching the in-app analytics), and reports the thread's root as platform_post_id.

AnalyticsOverview

total_posts
​integer
total_platforms
​integer
total_engagement
​number
total_impressions
​number
average_engagement_rate
​number

Engagement rate as a percentage (0-100)

Example: 3.3
top_performing_platform
​string | null
​object

AccountAnalytics

platform
​string
platform_account_id
​string
date
​string · date
metrics
​object

Account-level metrics for the snapshot date, as the platform reports them. Stock values: followers, following, posts, and platform extras (monthly_views, pin_count, listed, media_count, average_rating, review_count, total_views, total_videos). Day values (period: "daily"): impressions (views), reach, engagement, likes, comments, shares, saves, profile_views, link_clicks, follows_gained, follows_lost, accounts_engaged, video_views, watch_time_minutes, and Google Business calls, direction_requests, website_clicks, bookings, impressions_breakdown, search_keywords. Audience objects when available: demographics (age, gender, country, city, or LinkedIn function, seniority, industry) with demographics_unit, online_followers (UTC hour -> followers online), link_clicks_breakdown (Threads, per URL). LinkedIn profile rows keep impressions_lifetime and carry period: "lifetime" when the daily breakdown is not available. Read the note field where present.

Example: {"followers":12840,"following":310,"posts":412}
collected_at
​string · date-time

Webhook

id
​string · uuid
url
​string · uri

URL to receive webhook events

Example: https://example.com/webhooks/omnisocials
events
​string[]

Events to subscribe to

Enum values:
post.scheduled
post.published
post.failed
post.approved
post.rejected
is_active
​boolean
last_triggered_at
​string · date-time
failure_count
​integer

Consecutive delivery failures since the last success. Resets to 0 on any successful delivery, so 0 means currently healthy.

Example: 0
last_failure
​object | null

Details of the most recent failed delivery. Not cleared on success, so it persists as the last known problem even when failure_count is 0. Null if no delivery has ever failed.

created_at
​string · date-time

WebhookPayload

id
​string

Unique delivery event ID (also sent as the X-OmniSocials-Delivery header)

Example: 80fbb5db-f0fa-4555-8c8d-8fc4fde94468
type
​string · enum

Event type

Enum values:
post.scheduled
post.published
post.failed
post.approved
post.rejected
Example: post.published
created_at
​string · date-time
​object

Event payload

PinterestProduct

pin_id
​string

Use this in pinterest.product_tags.

Example: 813744226420795884
title
​string | null
description
​string | null
link
​string | null

The product page the Pin links to.

Example: https://shop.example.com/products/blue-ribbed-top
image_url
​string | null

A small image of the product Pin.

price
​number | null

Catalog source only.

Example: 24.99
currency
​string | null

Catalog source only. ISO 4217 code.

Example: EUR
availability
​string | null

Catalog source only, as Pinterest reports it (for example IN_STOCK, OUT_OF_STOCK, PREORDER).

item_id
​string | null

Catalog source only. The merchant's own product id.

Example: TOP-BLUE-M

InboxParticipant

id
​string

Platform-scoped id of the other party

name
​string
username
​string
profile_picture
​string | null

InboxConversation

conversation_id
​string
platform
​string · enum
Enum values:
instagram
facebook
linkedin
tiktok
youtube
x
threads
type
​string · enum

dm = direct message; comment/mention = public interaction. LinkedIn is comment/mention only; TikTok and YouTube are comment only; X is dm only; Threads is comment (replies on your posts) and mention only.

Enum values:
dm
comment
mention
Example: comment
​InboxParticipant
unread_count
​integer

Unread incoming messages in this conversation

Example: 1
​object
post
​InboxPostContext

The post a comment/mention conversation belongs to, so a reply can be drafted with the post in view ("what size is this?" needs the caption and the picture). Null for DMs. url is the public link to the post when the platform provides one (Instagram, Facebook, YouTube, TikTok, LinkedIn, Threads); media_type is the platform's label (e.g. IMAGE, VIDEO, CAROUSEL_ALBUM on Instagram) when known.

InboxPostContext

The post a comment/mention conversation belongs to, so a reply can be drafted with the post in view ("what size is this?" needs the caption and the picture). Null for DMs. `url` is the public link to the post when the platform provides one (Instagram, Facebook, YouTube, TikTok, LinkedIn, Threads); `media_type` is the platform's label (e.g. IMAGE, VIDEO, CAROUSEL_ALBUM on Instagram) when known.
id
​string | null
caption
​string | null
thumbnail
​string | null

Image URL of the post (or the video's cover)

Example: https://example.com/photo.jpg
url
​string | null
media_type
​string | null

InboxMessage

id
​string
conversation_id
​string
platform
​string
type
​string · enum
Enum values:
dm
comment
mention
Example: comment
direction
​string · enum
Enum values:
incoming
outgoing
text
​string
timestamp
​string · date-time
is_read
​boolean
is_replied
​boolean
reaction
​string | null
parent_comment_id
​string | null
hidden
​boolean | null

Comments only: true when the comment is hidden on the platform (see POST /inbox/messages/{id}/hide). Null for DMs.

Example: false
permalink
​string | null

Link to the reply or mentioning post on the platform, when known

attachment
​object | null

Media sent with this message, when present. Incoming Instagram/Facebook DM images, videos, voice messages, and story mentions are re-hosted on our CDN so the URL stays valid indefinitely (the platform's own URL is short-lived). type reflects the fetched bytes, not the platform's label: a photo the platform sent under an unlabelled attachment type is image, a story mention that is really an MP4 is video. type: file covers media we could fetch but could not classify. type: link means the platform's URL did not point at media (for example a shared post that resolves to an instagram.com page); url is then the platform's own link, not re-hosted, and may require login or expire.

​InboxParticipant
post
​InboxPostContext

The post a comment/mention conversation belongs to, so a reply can be drafted with the post in view ("what size is this?" needs the caption and the picture). Null for DMs. url is the public link to the post when the platform provides one (Instagram, Facebook, YouTube, TikTok, LinkedIn, Threads); media_type is the platform's label (e.g. IMAGE, VIDEO, CAROUSEL_ALBUM on Instagram) when known.

InboxNextUnanswered

The next conversation that needs an answer, with everything needed to draft the reply. Null when the queue is empty.
​InboxConversation
​object

The unanswered incoming message itself: the customer's latest DM, or the specific comment. Its conversation_id is what the reply endpoint takes, and its id is the message_id to pass along with the reply for comment threads (so the reply lands under this comment and not under the newest one on the post); the same id is what POST /inbox/messages/{id}/hide and DELETE /inbox/messages/{id} take.

​InboxMessage[]

The conversation so far, oldest first (the most recent 50 messages for long DM threads).

​object

Whether a reply can still be sent through the API. Only Instagram and Facebook DMs have a window (Meta: 24 hours after the customer's last message); every other item has open: true and closes_at: null. When open is false the item is still served (the customer is still waiting) but the reply endpoint answers 422 outside_messaging_window: answer it from the native app (that reply is mirrored into the inbox and clears the item) or mark the conversation read to skip it.

InboxCursorPagination

next_cursor
​string | null

Pass as ?cursor= to fetch the next page; null when there are no more results

Example: MjAyNi0xMC0yMVQwOTowMDowMC4wMDBafDg4MjMx
has_more
​boolean
limit
​integer

AutomationTrigger

kinds
​string[]

What starts the automation. comment = a comment on an Instagram post or reel, or on a Facebook Page post (needs scope). dm = a keyword in a DM to the Instagram account, in a Messenger message to the Facebook Page, or in a DM to the X account. story_reply = a keyword in a reply to an Instagram story (Instagram only: Facebook has no story replies, and a Facebook automation with story_reply answers 400 validation_error). On X only dm exists. One automation can listen to several. Default ["comment"] (pass ["dm"] on X).

Enum values:
comment
dm
story_reply
scope
​string · enum

For the comment kind: post = one post (pass post_id, instagram_media_id or facebook_post_id on the request), next_post = the next post the workspace publishes on the automation's platform, any = every post of the account or Page. Default post.

Enum values:
post
next_post
any
keywords
​string[]

Up to 20 keywords (60 characters each), matched case-insensitively. Required unless match is any.

match
​string · enum

word (default) = the keyword stands on its own ("guide", "Guide!" match; "linkedin" does not match "link"), contains = the keyword appears anywhere, any = every comment or message with text.

Enum values:
word
contains
any

AutomationActions

​object · required
​object

A public reply under the comment, only for the comment kind. One of variations is picked at random per comment.

AutomationLimits

max_sends
​integer | null

Stop after this many DMs (the automation becomes completed). Omit for no limit.

Example: 500
stop_at
​string | null · date-time

Stop at this time. Omit for no end.

Example: 2026-11-30T23:00:00.000Z

AutomationStats

matched
​integer
sent
​integer
skipped
​integer
failed
​integer
last_event_at
​string | null · date-time

Automation

id
​string
type
​string · enum
Enum values:
comment_to_dm
platform
​string · enum

The channel the automation runs on: the connected Instagram account, the connected Facebook Page, or the connected X account. Set at create; it never changes.

Enum values:
instagram
facebook
x
status
​string · enum

completed = max_sends or stop_at was reached. A new limit or trigger starts it again.

Enum values:
active
paused
completed
name
​string | null
post_id
​string | null

The OmniSocials post the automation listens on, for the post scope. null for a post published outside OmniSocials and for the other scopes.

Example: 1024
instagram_media_id
​string | null

The Instagram media id the automation listens on. Set once the post is live on Instagram. Always null for a Facebook automation.

Example: 17912345678901234
facebook_post_id
​string | null

The Facebook Page post id ({page-id}_{post-id}) the automation listens on. Set once the post is live on the Page. Always null for an Instagram automation.

Example: 104857600123456_987654321098765
post
​object | null

A snapshot of the post: source (omnisocials, instagram or facebook: a post picked by id is read from that platform), id, caption, thumbnail_url, permalink, media_type and, for an OmniSocials post, status and live.

​AutomationTrigger
​AutomationActions
​AutomationLimits
​AutomationStats
created_at
​string · date-time
updated_at
​string · date-time

AutomationInput

The fields of an automation. POST /automations requires `actions`; PATCH /automations/{id} takes any subset.
name
​string

A label for the automations list (max 120 characters).

Example: Guide DM
platform
​string · enum

The channel the automation runs on. Default instagram. instagram_media_id implies instagram and facebook_post_id implies facebook; a body that names another platform answers 400 validation_error. On PATCH it cannot change: another platform answers 400 platform_immutable. x answers DMs to the connected X account: only the dm kind (X allows an automated DM only after the person DMed you), the workspace needs X DMs turned on in the dashboard (else 409 x_dms_off for an active automation; status: paused saves it), every answer ends with the line "Reply STOP to stop automatic messages.", and a person who replies STOP gets no automatic DM from the account again. X does not give apps the messages of an encrypted X Chat conversation, so those get no answer.

Enum values:
instagram
facebook
x
Example: instagram
​AutomationTrigger
post_id
​string

For scope post: an OmniSocials post (scheduled or live) that goes to the automation's platform. A post that does not go there answers 400 post_not_instagram or post_not_facebook. One automation per post and platform: a post that goes to Instagram and Facebook can have one of each.

Example: 1024
instagram_media_id
​string

For scope post on Instagram: the numeric id of a post or reel that was published outside OmniSocials (from the Instagram API, GET /me/media). The post is read from Instagram to check it belongs to the connected account.

Example: 17912345678901234
facebook_post_id
​string

For scope post on Facebook: the id of a post that was published on the connected Facebook Page outside OmniSocials. Pass {page-id}_{post-id} or the post id alone (the Page id is put in front). The post is read from Facebook with the Page token; a post of another Page answers 404 facebook_post_not_found. Implies platform: facebook. Pass one of post_id, instagram_media_id or facebook_post_id.

Example: 104857600123456_987654321098765
​AutomationActions
​AutomationLimits
status
​string · enum

paused creates the automation without turning it on. Default active.

Enum values:
active
paused

AutomationEvent

id
​string
automation_id
​string
kind
​string · enum

What the person did.

Enum values:
comment
dm
story_reply
outcome
​string · enum

queued = the answer waits for a free slot under the channel's send cap (X 15 per 15 minutes and 450 a day, Instagram and Facebook 180 an hour) and goes out within the hour, else it becomes skipped with rate_limited. opted_out = the person replied STOP on X (no automatic DMs to them from the account again).

Enum values:
sent
skipped
failed
pending
queued
opted_out
reason
​string | null

For skipped: already_sent, limit_reached, stopped, window_passed (comment older than 7 days), rate_limited (the send cap stayed full for an hour), cannot_message (Meta refused the message: a Page made the comment, or the person's settings block messages), already_replied (the comment already has a private reply), dm_window_passed (their message is older than 24 hours), dms_closed (X refused: the person does not accept DMs from the account), no_credits (X DMs had no credits for the answer), opted_out (the person replied STOP before), automation_off (the automation was paused or finished while the answer waited). For failed: the platform's error text.

reason_label
​string | null

The reason in plain words.

​object
trigger_id
​string | null

The comment id or message id that started the event.

trigger_text
​string | null

The comment or message text (300 characters). For dm and story_reply events it is returned only to a key with the inbox:read scope (OAuth: the social inbox permission); otherwise null.

message
​string | null

The DM that was sent.

public_reply
​string | null

The public reply posted under the comment, when one was.

platform_message_id
​string | null
created_at
​string · date-time
sent_at
​string | null · date-time
On this page
  • Error
  • Pagination
  • Post
  • FirstCommentResult
  • VideoCoverEntry
  • VideoCover
  • LinkedInPollFields
  • XPoll
  • ThreadsPoll
  • MastodonPoll
  • TelegramPoll
  • TelegramButton
  • DiscordPoll
  • DiscordButton
  • CreatePostRequest
  • Media
  • MediaCompatibility
  • PdfUploadResult
  • Folder
  • HashtagSet
  • ApprovalWorkflowApprover
  • ApprovalWorkflowStep
  • ApprovalWorkflow
  • Account
  • PostAnalytics
  • AnalyticsOverview
  • AccountAnalytics
  • Webhook
  • WebhookPayload
  • PinterestProduct
  • InboxParticipant
  • InboxConversation
  • InboxPostContext
  • InboxMessage
  • InboxNextUnanswered
  • InboxCursorPagination
  • AutomationTrigger
  • AutomationActions
  • AutomationLimits
  • AutomationStats
  • Automation
  • AutomationInput
  • AutomationEvent