Create a new post
Create a new post. You can attach media by uploading first (media/media_ids) or by passing external URLs (media_urls) which will be downloaded and processed automatically. Both can be combined.
Required media: Instagram and TikTok posts need at least one image/video. Pinterest posts need an image and a board_id. Posts without required media will be rejected with a 400 error.
Stories (type: "story"): 1 to 10 media items. Each item is one slide and publishes as its own story on Instagram and Facebook, in the order given. Per-platform objects can give each platform its own slide list. Videos max 60 s per slide. After publishing, story_slides lists every slide's native id and URL; published_urls keeps the first slide.
Per-platform media caps (enforced at submit, not at publish time):
- bluesky — max 4 images per post; cannot mix images and video
- mastodon — max 4 media items per post; cannot mix images and video
- x — max 4 images per post; cannot mix images and video
- instagram — max 10 items in a carousel; images and videos can be mixed in one carousel
- threads — max 10 items in a carousel; images and videos can be mixed in one carousel
- tiktok — max 35 items per photo post; cannot mix photos and videos in one post
- pinterest — max 5 images per carousel pin (videos are exempt — they publish as single video pins)
- facebook, linkedin, linkedin_page — cannot mix images and video in one post (their APIs accept images only or a single video)
Exceeding any cap returns 400 { error: { code: "validation_error", message: "<Platform> allows up to N media items per post. You attached M, please remove M-N." } } (Pinterest wording: "Pinterest carousel pins support a maximum of 5 images. Please remove some images and try again."). The Pinterest carousel aspect-ratio constraint (2–5 same-ratio images) is enforced the same way; see the Pinterest section for the mismatched_slides response shape.
Per-platform video file-size caps (validated via ffprobe; drafts exempt): Mastodon 99 MB · Bluesky 100 MB · Instagram 300 MB · X 512 MB free tier, 16 GB with Premium / Premium+ (in practice bounded by the 1 GB URL-ingest / 100 MB direct-upload limits) · Threads / Reddit 1 GB · Pinterest 2 GB · Facebook / TikTok 4 GB · LinkedIn 5 GB · YouTube 256 GB. Upload requests are capped at 100 MB on top of these — anything bigger is rejected before media processing with code: file_too_large.
Per-platform video duration caps (validated via ffprobe; drafts exempt): Facebook Post 240 min / Reel 90 s · Instagram 15 min (Post + Reel) · TikTok 10 min (Post + Reel) · YouTube Short 3 min · X 140 s free tier, 125 min when the connected X account has Premium or Premium+ (tier detected automatically; reconnect X after upgrading) · Bluesky 180 s · Threads 5 min · LinkedIn 10 min · Pinterest 15 min · Reddit 15 min · Mastodon (instance-dependent).
Cap violations return 400 { error: { code: "validation_error", message: "<Platform> only allows videos up to <cap>; yours is <duration>. Trim the video or deselect <Platform>." } } (duration) or "This video (<size>) is too large for <Platform>. ..." (size). When multiple platforms reject the same upload, each contributes one sentence to the message. See API_DEVELOPER_GUIDE.md → "Per-Platform Media Limits" and "Per-Platform Video Duration Caps" for the full table with source citations.
X link-post credits: X's API bills posts whose text contains a URL at a premium ($0.20 vs $0.015), and OmniSocials passes that fee through as prepaid credits at X's rate card (20 credits per URL-containing tweet; threads are billed per part that contains a link). Credits are purchased in euros: 1 credit = €0.01, top-ups of €5-500 in the dashboard. When a create/schedule targets X and the text contains a URL, the 201 response includes a warnings array entry (code: "x_url_post_credits") with credits_required, the company's current credits_balance, and the enforcement state. At publish time the credits are debited; if the balance can't cover it, the X target alone fails with an INSUFFICIENT_CREDITS message in its error_message (other platforms in the post publish normally) and the post can be retried after topping up in Settings → Organisation → Billing → Credits. Posts without links, analytics, and everything else on X stay free.
Schedule-time gate: every scheduled X link post reserves its cost until it publishes. Scheduling (or publishing) a new X link post that would push the total reserved past the balance is refused with 402 x_credits_insufficient (details carries credits_required, credits_balance, credits_reserved). Drafts are never gated; posts publishing before the enforcement date are never gated.
Request body
Example request
{
"content": {
"default": "Hello world!",
"instagram": "Hello from IG! #awesome"
},
"media_urls": {
"default": [
{
"url": "https://example.com/photo.jpg",
"alt": "A red bicycle leaning against a brick wall"
}
],
"instagram": [
"https://example.com/square.jpg"
]
},
"link_url": "https://goodlightai.com/blog/new-feature",
"location_id": "1234567890",
"collaborators": [
"therock",
"kevinhart4real"
],
"user_tags": [
{
"username": "therock",
"x": 0.5,
"y": 0.8
}
],
"hashtag_set": "Fitness Brand",
"instagram": {
"audio_id": "587784541076604"
},
"x": {
"thread_parts": [
{
"text": "1/3 — our results are in 👇",
"media_ids": [
"12345"
]
},
{
"text": "2/3 — grab your free pick here: https://example.com/signup"
},
{
"text": "3/3 — and here's the slip 🎁",
"media_ids": [
"12346"
]
}
]
},
"bluesky": {
"thread_parts": [
{
"text": "1/3 — our results are in 👇"
},
{
"text": "2/3 — read the full writeup: https://example.com/post"
},
{
"text": "3/3 — thanks for reading! #buildinpublic"
}
]
},
"mastodon": {
"thread_parts": [
{
"text": "1/3 — our picks are in 👇"
},
{
"text": "2/3 — read the full writeup: https://example.com/post"
},
{
"text": "3/3 — thanks for reading! #fediverse"
}
]
},
"threads": {
"location_id": "17841400000000000",
"location": {
"id": "17841400000000000",
"name": "Griffith Observatory",
"city": "Los Angeles",
"country": "United States"
},
"thread_parts": [
{
"text": "1/3: our results are in"
},
{
"text": "2/3: read the full writeup: https://example.com/post"
},
{
"text": "3/3: thanks for reading! #buildinpublic"
}
]
}
}Response
Post created
Example response
{
"data": {
"app_url": "https://app.omnisocials.com/create-post/1024",
"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",
"x": "https://x.com/yourhandle/status/1791234567890123456"
},
"errors": {
"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."
},
"threads": {
"location": {
"id": "17841400000000000",
"name": "Griffith Observatory",
"city": "Los Angeles",
"country": "United States"
}
}
},
"warnings": [
{
"code": "x_url_post_credits",
"credits_required": 20,
"enforce_from": "2026-08-14"
}
]
}Changes
No recorded changes to this endpoint across all 1 revision of this API.