Platform Settings

Per-platform destination parameters for posts, including Instagram tags, YouTube metadata, TikTok privacy, and first comments.

When creating a post, each entry in destinations[] targets one connected account. Alongside the required accountId, every destination accepts platform-specific settings that control how the content appears and behaves on that network. Fields that do not belong to the destination's platform are rejected with VALIDATION_ERROR before anything is queued.

This page is the complete reference. Each platform page repeats its own fields with examples.


Text limits

Publishing runs per destination, so a shared caption that is too long for one network used to fail there while the others went live (a partial post). Onepostly now validates every text field up front and rejects the whole request with 400 VALIDATION_ERROR before anything is written.

Each platform is measured with its own counter:

PlatformShared textdescriptiontitlefirstCommentCounting
X280———Weighted: CJK and emoji weigh 2, every URL counts as 23
Threads500——500Characters
Bluesky300———Graphemes (an emoji family is one)
Instagram2,200——2,200Characters
TikTok2,2004,000——Characters
YouTube5,0005,00010010,000Characters
Pinterest800800100—Characters
LinkedIn3,000——1,250Characters
Facebook63,206——8,000Characters

X is the one platform whose limit follows the connected account rather than the platform. A paid X subscription raises that account's posts and replies to 25,000 weighted units, GET /v1/connections reports the tier as xSubscriptionType, and each X destination is validated against its own account — so a Premium connection publishes long-form while a free one is still held to 280.

The request schema accepts up to the widest platform limit (text 63,206, description 5,000, firstComment 10,000, title 100), and the per-platform limit is enforced once the destinations resolve.

The shared text (and every threadItems[].content segment) must fit every selected destination. To post longer copy to one network, pass a per-destination text override on that destination — it is validated against that platform only. Exceeding a limit returns, for example:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Text is 800 characters. X allows 280. Shorten it or remove X."
  }
}

Comments and messages

Replies (POST /v1/comments) and direct/private messages (POST /v1/inbox/messages, POST /v1/comments/private-reply) are validated against the same per-platform table, so a reply can never be accepted and then rejected upstream:

PlatformCommentDirect messageCounting
X280—Weighted (CJK/emoji 2, URL 23); 25,000 on a paid X subscription
Threads500—Characters
Bluesky3001,000Graphemes
Instagram2,2001,000Characters
Facebook8,0002,000Characters
LinkedIn1,250—Characters
YouTube10,000—Characters

Platforms without an explicit direct-message row fall back to 2,000 characters.


X / Twitter

PropertyTypeDescription
quoteTweetIdstringId of the tweet to quote. Omit for a normal post.
textstringPer-destination text override. Falls back to the root text.
geoRestrictionstring[]Uppercase ISO 3166-1 alpha-2 codes with a max of 25. Restrict media visibility to a specific allowlist. Ignored for text-only tweets and text stays visible globally. Example ["US", "ES"]
threadItemsarrayReplies under the root post in order from 1 to 25. The root comes from top-level text with normal media rules
threadItems[].contentstringTweet text content
threadItems[].mediaItemsarrayMedia attachments for this reply. Max 4 images or a single video with no mixing

Threads are configured on the post body via threadItems with 1 to 25 replies under the root post and per-reply content and media within the account's limit per post (280 weighted units, or 25,000 on a paid X subscription).

{
  "text": "Excited to announce our new product!",
  "mediaKind": "image",
  "mediaUrls": ["https://cdn.onepostly.com/media/cover.jpg"],
  "threadItems": [
    { "content": "1/ Why we built it..." },
    {
      "content": "2/ How to get started...",
      "mediaItems": ["https://cdn.onepostly.com/media/demo.jpg"]
    }
  ],
  "destinations": [
    {
      "accountId": "YOUR_X_ACCOUNT_ID",
      "geoRestriction": ["US", "ES"]
    }
  ]
}

Threads

PropertyTypeDescription
quoteTweetIdstringPost id of the post to quote.
replyToIdstringPost id of the post to reply to.
textstringPer-destination text override.
threadItemsarrayReplies under the root post in order from 1 to 25. The root comes from top-level text with normal media rules
threadItems[].contentstringPost text content
threadItems[].mediaItemsarrayMedia attachments for this reply. One image or video or a carousel with a max of 20

Threads are configured on the post body via threadItems with 1 to 25 replies under the root post and per-reply content and media within 500 characters per post.

{
  "text": "Excited to announce our new product!",
  "mediaKind": "image",
  "mediaUrls": ["https://cdn.onepostly.com/media/cover.jpg"],
  "threadItems": [
    { "content": "1/3 intro" },
    { "content": "2/3 body" },
    { "content": "3/3 CTA" }
  ],
  "destinations": [{ "accountId": "YOUR_THREADS_ACCOUNT_ID" }]
}

Instagram

PropertyTypeDescription
userTagsarrayTagged Instagram users, max 20. x/y (0.0 to 1.0) are required for image posts and optional on stories; coordinates are ignored for videos and reels. The @ prefix is optional.
userTags[].usernamestringInstagram username to tag.
userTags[].xnumberDistance from the left edge, 0.0 to 1.0. Required for images.
userTags[].ynumberDistance from the top edge, 0.0 to 1.0. Required for images.
collaboratorsstring[]Up to 3 co-author usernames. Feed images, reels, and carousels only; not stories.
firstCommentstringComment posted right after publish. Best effort: a failed comment never fails the post. Not applied to stories.
shareToFeedbooleanReels only. true (default) shows the reel on the feed and the Reels tab; false keeps it on the Reels tab only.
thumbOffsetnumberReels and videos only. Cover frame offset in milliseconds. Default 0 (first frame).
coverUrlstringReels only. Public URL of a custom cover image. Wins over thumbOffset when both are set.
audioNamestringReels only. Renames the original audio. Allowed once per reel.
locationIdstringNumeric Facebook Page id that has location data. Feed images, reels, and the carousel as a whole; not stories or individual carousel slides.
isPaidPartnershipbooleantrue shows the Paid partnership label. Images, reels, and carousels only.

Constraints:

  • Carousels support up to 10 media items
  • Feed images require 0.5625 (9:16) to 1.91 aspect ratio
  • Paid partnership and collaborators are rejected on stories
  • locationId is a Facebook Page id, not a place name
{
  "accountId": "YOUR_IG_ACCOUNT_ID",
  "firstComment": "Link in bio!",
  "collaborators": ["brandpartner"],
  "userTags": [{ "username": "friend_username", "x": 0.5, "y": 0.5 }],
  "shareToFeed": true,
  "thumbOffset": 1500,
  "locationId": "123456789"
}

Facebook

PropertyTypeDescription
firstCommentstringComment posted on the post right after publish. Not applied to stories.
{
  "accountId": "YOUR_FB_ACCOUNT_ID",
  "firstComment": "What do you think? Drop a comment below!"
}

LinkedIn

PropertyTypeDescription
firstCommentstringComment posted right after publish, as the same author.
{
  "accountId": "YOUR_LINKEDIN_ACCOUNT_ID",
  "firstComment": "What features would you like to see next?"
}

Pinterest

PropertyTypeDescription
boardIdstringRequired. Target board id.
titlestringPin title with a max of 100 characters. Defaults to the first line of the post text when omitted.
linkstringDestination URL the pin points to. Must be a full HTTPS URL; link shorteners are rejected.
coverImageUrlstringVideo Pins only. Custom cover image URL. Defaults to a frame from the video.
isAiGeneratedbooleantrue adds Pinterest's "AI modified" label to the pin.

The post text becomes the pin description (max 800 characters).

{
  "accountId": "YOUR_PINTEREST_ACCOUNT_ID",
  "boardId": "1234567890123456789",
  "title": "10 Tips for Better Photography",
  "link": "https://example.com/photography-tips"
}

YouTube

PropertyTypeDescription
privacyStatus"public" | "private" | "unlisted"Video visibility. Default public.
titlestringVideo title with a max of 100 characters. Overrides the text-derived title when both are present.
descriptionstringVideo description, max 5,000 characters.
tagsstring[]Video keywords. Each tag max 100 characters; combined length max 500 characters.
categoryIdstringVideo category id. Default "22" (People & Blogs). Common values: "10" Music, "20" Gaming, "27" Education, "28" Science & Technology.
madeForKidsbooleanCOPPA self-declaration. true marks the video as made for kids; comments and notifications are disabled by YouTube. Default false.
containsSyntheticMediabooleantrue discloses realistic AI-generated or altered content. YouTube may add a label.
firstCommentstringComment posted on the video right after the upload completes.

Videos 3 minutes or shorter in vertical format are classified as Shorts automatically. No flag is needed.

{
  "accountId": "YOUR_YOUTUBE_ACCOUNT_ID",
  "privacyStatus": "public",
  "title": "New Product Announcement",
  "description": "Full walkthrough with timestamps and links.",
  "tags": ["api", "tutorial"],
  "categoryId": "28",
  "madeForKids": false,
  "containsSyntheticMedia": false,
  "firstComment": "Thanks for watching! Subscribe for updates!"
}

TikTok

PropertyTypeDescription
privacyLevelstringRequired. One of PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY. Must match one of the creator's allowed values.
disableCommentbooleantrue turns comments off. Default false.
disableDuetbooleantrue disables duets. Default false (duets enabled). Video posts only.
disableStitchbooleantrue disables stitches. Default false (stitches enabled). Video posts only.
brandOrganicTogglebooleantrue declares the content promotes the creator's own brand.
brandContentTogglebooleantrue declares a paid partnership promoting a third-party business.
aiGeneratedbooleantrue discloses AI-generated content. Videos label with "made with AI"; photos get an AI tag.
descriptionstringLong-form caption for photo posts, max 4,000 characters.
videoCoverTimestampMsnumberVideo posts only. Cover frame timestamp in milliseconds. Default 1000.
photoCoverIndexnumberPhoto posts only. Zero-based index of the photo used as the cover. Default 0.
autoAddMusicbooleanPhoto posts only. true lets TikTok attach recommended music. Default false.

Constraints:

  • Photo carousels support up to 35 images
  • Video captions are capped at 2,200 characters; longer requests are rejected
  • Photo titles are truncated at 90 characters; use description for longer text
  • privacyLevel must match the creator's allowed options; there is no silent default
{
  "accountId": "YOUR_TIKTOK_ACCOUNT_ID",
  "privacyLevel": "PUBLIC_TO_EVERYONE",
  "disableComment": false,
  "disableDuet": false,
  "disableStitch": false,
  "description": "Full description here since photo titles are limited to 90 characters.",
  "photoCoverIndex": 0,
  "autoAddMusic": true
}

Bluesky

PropertyTypeDescription
quoteTweetIdstringat:// URI of the post to quote.
replyToIdstringat:// URI of the post to reply to.
linkstringDestination URL attached to the post card.
threadItemsarrayReplies under the root post in order from 1 to 25. The root comes from top-level text with normal media rules
threadItems[].contentstringPost text content
threadItems[].mediaItemsarrayMedia attachments for this reply. Max 4 images or a single video with no mixing. Link cards and quotes stay on root

Threads are configured on the post body via threadItems with 1 to 25 replies under the root post and per-reply content and media within 300 characters per post.

{
  "text": "Excited to announce our new product!",
  "mediaKind": "image",
  "mediaUrls": ["https://cdn.onepostly.com/media/cover.jpg"],
  "threadItems": [
    { "content": "1/3 intro" },
    { "content": "2/3 body" },
    { "content": "3/3 CTA" }
  ],
  "destinations": [{ "accountId": "YOUR_BLUESKY_ACCOUNT_ID" }]
}

Up to 4 images per post; larger images are recompressed automatically. Link previews are generated when no media is attached.


Complete Example

One request publishing everywhere with per-platform settings:

{
  "text": "Excited to announce our new product!",
  "mediaKind": "image",
  "mediaUrls": ["https://cdn.onepostly.com/media/product.jpg"],
  "destinations": [
    {
      "accountId": "x-account-id",
      "quoteTweetId": "17841405822304914"
    },
    {
      "accountId": "instagram-account-id",
      "firstComment": "Link in bio!",
      "collaborators": ["brandpartner"],
      "userTags": [{ "username": "friend_username", "x": 0.5, "y": 0.5 }]
    },
    {
      "accountId": "linkedin-account-id",
      "firstComment": "What would you like to see next?"
    },
    {
      "accountId": "youtube-account-id",
      "privacyStatus": "public",
      "title": "New Product Announcement"
    },
    {
      "accountId": "tiktok-account-id",
      "privacyLevel": "PUBLIC_TO_EVERYONE",
      "autoAddMusic": true
    },
    {
      "accountId": "pinterest-account-id",
      "boardId": "1234567890123456789",
      "title": "New Product Announcement",
      "link": "https://example.com/product"
    }
  ]
}

See Also